Skip to content

Add 'run' command, injector, and matcher updates#17

Merged
naheel0 merged 4 commits into
mainfrom
database
Mar 1, 2026
Merged

Add 'run' command, injector, and matcher updates#17
naheel0 merged 4 commits into
mainfrom
database

Conversation

@naheel0
Copy link
Copy Markdown
Member

@naheel0 naheel0 commented Mar 1, 2026

Introduce a new CLI subcommand (errlens run ) that spawns a Node child process, streams logs in real-time, captures stderr for analysis, and reports known issues or raw crash output. Add lib/injector.js to enable automatic runtime analysis for uncaught exceptions and unhandled promise rejections when injected into a project. Revamp matcher.findError to return {count,matches} and switch from fuzzy search to deterministic substring matching with specificity sorting and deduplication. Update auto.js to use the new matcher API and improve console output. Improve formatter styling and layout (fixed width, title tweak, margin change) and normalize fixes arrays in database.json; also add a couple of new syntax-related entries. Minor CLI description/version update and general UX/error reporting enhancements.

🚀 BΞYTΞFLʘW | Pull Request Protocol

PR Type: (Choose one: feat | fix | refactor | docs | perf)
Issue Link: Fixes #


📝 System Summary

Provide a concise brief of the changes introduced to the stream.

🛠️ Technical Changes

  • Logic change in ...
  • New UI component added: ...
  • Database schema updated: ...

🧪 Quality Assurance (QA)

  • Linting: Code style matches the BeyteFlow grid.
  • Build: npm run build executed without errors.
  • Testing: New logic has been verified and tested.
  • Dark Mode: UI is high-contrast and neon-optimized.

🖼️ Visual Evidence

If this PR affects the UI, drop a screenshot or GIF below:


📡 Developer Authorization

  • I have performed a self-review of my code.
  • My changes generate no new warnings in the console.
  • I have updated the documentation (if applicable).

Authorized by: @naheel0
Timestamp: {{ 1/3/2026 }}


Summary by CodeRabbit

  • New Features

    • New run command to execute and analyze JS files with live stdout streaming and crash analysis
    • Automatic runtime protection for uncaught exceptions and unhandled promise rejections
    • Improved error formatting and visual layout for clearer, compact reports
    • Expanded error database with two new patterns for better detection
  • Behavior Changes

    • Matching logic updated for more precise, deduplicated substring-based results

Introduce a new CLI subcommand (errlens run <file>) that spawns a Node child process, streams logs in real-time, captures stderr for analysis, and reports known issues or raw crash output. Add lib/injector.js to enable automatic runtime analysis for uncaught exceptions and unhandled promise rejections when injected into a project. Revamp matcher.findError to return {count,matches} and switch from fuzzy search to deterministic substring matching with specificity sorting and deduplication. Update auto.js to use the new matcher API and improve console output. Improve formatter styling and layout (fixed width, title tweak, margin change) and normalize fixes arrays in database.json; also add a couple of new syntax-related entries. Minor CLI description/version update and general UX/error reporting enhancements.
@coderabbitai
Copy link
Copy Markdown

coderabbitai Bot commented Mar 1, 2026

📝 Walkthrough

Walkthrough

Replaces the CLI with a new run <file> command that spawns Node to execute a file, streams stdout live, captures stderr for analysis, updates error matching to case-insensitive substring matching with deduplication, adds a runtime injector for crashes, enhances formatting, and extends the error database with two SyntaxError entries.

Changes

Cohort / File(s) Summary
CLI / Runner
bin/index.js
Removed old argument-driven interface; added run <file> command that spawns a Node child process, streams stdout live, captures stderr, handles exit codes, and analyzes captured errors. Added child_process.spawn and path usage; bumped description/version.
Runtime Crash Hooks
lib/injector.js, lib/auto.js
Added lib/injector.js to hook uncaught exceptions and unhandled rejections; reworked lib/auto.js to normalize thrown values and use findError result { count, matches }, printing colored summaries and exiting with code 1.
Matching Logic
lib/matcher.js
Replaced fuzzy search with case-insensitive substring matching, added input normalization, specificity sort (longer matches first), deduplication by name, and changed return shape to { count, matches }.
Formatting / Presentation
lib/formatter.js
Adjusted formatted output: emoji-prefixed bold title, combined WHAT/WHY lines, updated fixes list rendering, enforced 80-char box width and explicit margins, and minor layout tweaks.
Error Database
lib/database.json
Reformatted fixes arrays to multi-line and added two new SyntaxError entries ("Unexpected end of input", "Missing Parenthesis") with explanations, why, fixes, and examples.
Other
package.json (implicit), misc imports
Added/updated imports and dependencies used by new CLI and injector (spawn, path, chalk wiring across libs).

Sequence Diagram

sequenceDiagram
    participant User as User
    participant CLI as bin/index.js
    participant Child as Node Child Process
    participant Injector as lib/injector.js
    participant Matcher as lib/matcher.js
    participant Formatter as lib/formatter.js
    participant Console as Console Output

    User->>CLI: run <file>
    CLI->>Child: spawn node <file>
    Child->>Child: execute script

    par Stdout
        Child-->>CLI: stdout stream
        CLI->>Console: print logs (streamed)
    end

    par Crash Path
        Child-->>Injector: uncaught exception / rejection (stack/message)
        Injector->>Matcher: findError(stack)
        Matcher-->>Injector: { count, matches }
        alt matches > 0
            Injector->>Formatter: formatError(match)
            Formatter-->>Console: colored formatted results
        else no matches
            Injector-->>Console: raw error (red)
        end
    end

    Child-->>CLI: exit code
    alt code == 0
        CLI->>Console: success message
    else
        CLI->>Console: analyzed or raw crash output
    end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~50 minutes

Possibly related PRs

  • add files #5: Modifies the same CLI and matching/formatter/injector files; likely directly related to these interface and runtime changes.

Poem

🐰 I hopped into code to watch a run,
Spawned a child, chased stdout for fun,
I sniffed the stacks with substring art,
Matched fixes, printed color, did my part,
ErrLens now hops — precise and done! 🌿

🚥 Pre-merge checks | ✅ 1 | ❌ 2

❌ Failed checks (1 warning, 1 inconclusive)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
Title check ❓ Inconclusive The title references three distinct components (run command, injector, matcher updates) but doesn't clearly convey the primary purpose of this PR—enabling automatic runtime error analysis through a new CLI subcommand and crash handlers. Consider revising to emphasize the main feature: 'Add run command with automatic error analysis' or 'Introduce runtime error detection with run command and auto-analysis hooks'.
✅ Passed checks (1 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch database

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 6

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@bin/index.js`:
- Around line 63-65: The child.on("error") handler currently only calls
spinner.fail(chalk.red(...)) and leaves the CLI running; update the handler in
bin/index.js so after spinner.fail(...) it sets a non-zero exit (e.g.
process.exitCode = 1 or call process.exit(1)) to fail fast on spawn/system
errors and then return/exit to stop further processing; target the
child.on("error", (err) => { ... }) block and ensure the error message from
err.message is preserved when you set the exit.
- Around line 44-61: In the child.on("close", (code) => ...) handler, explicitly
accept the signal parameter (use (code, signal) => ...) and treat code === null
as a signal-based termination: stop the spinner, log a clear message that the
child was killed by the given signal (include the signal variable), and exit
with a non-zero status instead of passing null to process.exit; replace the
final process.exit(code) with process.exit(code ?? 1) (or process.exit(1) when
code is null) so signal-driven exits are not treated as successful; keep the
existing errorOutput/findError/formatError logic unchanged.
- Around line 25-27: Replace the hard-coded "node" in the spawn call with
process.execPath and pass an explicit stdio option to inherit stdin while piping
stdout/stderr (e.g. spawn(process.execPath, [filePath], { stdio: ['inherit',
'pipe', 'pipe'] })), and attach/adjust the spawn error handler for the child
process (the variable child) so that on error it logs the failure and calls
process.exit(1) to exit with a non-zero code.

In `@lib/auto.js`:
- Around line 6-7: The call to findError(err.message) assumes err is a standard
Error and misses non-Error throws; change it to compute a null-safe search
string (e.g., let msg = (err && err.message) ? err.message : String(err)) and
pass that msg into findError so findError receives a usable string for both
Error objects and primitive/non-standard throws; update any surrounding
references to use this message variable instead of err.message (look for
findError and err.message in lib/auto.js).

In `@lib/injector.js`:
- Line 12: The crash-handler assumes err is an object with stack/message; guard
against null/undefined by normalizing the thrown value before calling findError:
compute a safe string (e.g., check err !== null && typeof err === 'object' ?
(err.stack || err.message) : String(err) or a default like 'unknown error') and
pass that safe string into findError; update the use-sites (the occurrence
calling findError and the later access at line 29) so both read from the
normalized value instead of accessing err.stack or err.message directly.

In `@lib/matcher.js`:
- Around line 4-7: The code calls input.toLowerCase() without ensuring input is
a string; add a type guard before computing lowerInput (the call site where
lowerInput = input.toLowerCase()) to handle non-string truthy values safely —
e.g., check typeof input === 'string' and only proceed, otherwise return the
empty result ({ count: 0, matches: [] }) or coerce via String(input) if you want
to accept non-string primitives; update the logic around lowerInput to use that
guard so toLowerCase is never invoked on non-string values.

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 4976f90 and 064087f.

📒 Files selected for processing (6)
  • bin/index.js
  • lib/auto.js
  • lib/database.json
  • lib/formatter.js
  • lib/injector.js
  • lib/matcher.js

Comment thread bin/index.js Outdated
Comment thread bin/index.js Outdated
Comment thread bin/index.js
Comment thread lib/auto.js Outdated
Comment thread lib/injector.js Outdated
Comment thread lib/matcher.js
@jaseel0
Copy link
Copy Markdown
Collaborator

jaseel0 commented Mar 1, 2026

@copilot
Verify each finding against the current code and only fix it if needed.

In @bin/index.js around lines 25 - 27, Replace the hard-coded "node" in the
spawn call with process.execPath and pass an explicit stdio option to inherit
stdin while piping stdout/stderr (e.g. spawn(process.execPath, [filePath], {
stdio: ['inherit', 'pipe', 'pipe'] })), and attach/adjust the spawn error
handler for the child process (the variable child) so that on error it logs the
failure and calls process.exit(1) to exit with a non-zero code.

Verify each finding against the current code and only fix it if needed.

In @bin/index.js around lines 44 - 61, In the child.on("close", (code) => ...)
handler, explicitly accept the signal parameter (use (code, signal) => ...) and
treat code === null as a signal-based termination: stop the spinner, log a clear
message that the child was killed by the given signal (include the signal
variable), and exit with a non-zero status instead of passing null to
process.exit; replace the final process.exit(code) with process.exit(code ?? 1)
(or process.exit(1) when code is null) so signal-driven exits are not treated as
successful; keep the existing errorOutput/findError/formatError logic unchanged.

Verify each finding against the current code and only fix it if needed.

In @bin/index.js around lines 63 - 65, The child.on("error") handler currently
only calls spinner.fail(chalk.red(...)) and leaves the CLI running; update the
handler in bin/index.js so after spinner.fail(...) it sets a non-zero exit (e.g.
process.exitCode = 1 or call process.exit(1)) to fail fast on spawn/system
errors and then return/exit to stop further processing; target the
child.on("error", (err) => { ... }) block and ensure the error message from
err.message is preserved when you set the exit.
Verify each finding against the current code and only fix it if needed.

In @lib/auto.js around lines 6 - 7, The call to findError(err.message) assumes
err is a standard Error and misses non-Error throws; change it to compute a
null-safe search string (e.g., let msg = (err && err.message) ? err.message :
String(err)) and pass that msg into findError so findError receives a usable
string for both Error objects and primitive/non-standard throws; update any
surrounding references to use this message variable instead of err.message (look
for findError and err.message in lib/auto.js).

Verify each finding against the current code and only fix it if needed.

In @lib/injector.js at line 12, The crash-handler assumes err is an object with
stack/message; guard against null/undefined by normalizing the thrown value
before calling findError: compute a safe string (e.g., check err !== null &&
typeof err === 'object' ? (err.stack || err.message) : String(err) or a default
like 'unknown error') and pass that safe string into findError; update the
use-sites (the occurrence calling findError and the later access at line 29) so
both read from the normalized value instead of accessing err.stack or
err.message directly.

Verify each finding against the current code and only fix it if needed.

In @lib/matcher.js around lines 4 - 7, The code calls input.toLowerCase()
without ensuring input is a string; add a type guard before computing lowerInput
(the call site where lowerInput = input.toLowerCase()) to handle non-string
truthy values safely — e.g., check typeof input === 'string' and only proceed,
otherwise return the empty result ({ count: 0, matches: [] }) or coerce via
String(input) if you want to accept non-string primitives; update the logic
around lowerInput to use that guard so toLowerCase is never invoked on
non-string values.

Copy link
Copy Markdown
Contributor

Copilot AI commented Mar 1, 2026

@jaseel0 I've opened a new pull request, #18, to work on those changes. Once the pull request is ready, I'll request review from you.

Copilot AI and others added 2 commits March 1, 2026 13:47
…rs, add type guard in matcher

Co-authored-by: jaseel0 <225665919+jaseel0@users.noreply.github.com>
Harden spawn, signal handling, and null-error guards across run command and runtime hooks
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (4)
bin/index.js (1)

60-60: Optional: Same linter hint as other files on forEach callback.

Consistent with lib/auto.js and lib/injector.js - use block body if you want to silence the Biome warning.

♻️ Optional fix
-          matches.forEach(m => console.log(formatError(m)));
+          matches.forEach(m => { console.log(formatError(m)); });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@bin/index.js` at line 60, The forEach callback uses a concise arrow body
which triggers the linter warning elsewhere; update the matches.forEach usage
(the matches.forEach callback that calls formatError) to use a block body arrow
function instead (e.g., matches.forEach(m => { console.log(formatError(m)); }) )
so it matches the style used in lib/auto.js and lib/injector.js and silences the
Biome warning while keeping the same behavior.
lib/auto.js (2)

6-8: Null-safe extraction implemented, but consider including stack trace.

The guard correctly handles non-Error throws. However, unlike lib/injector.js which uses err.stack || err.message, this file only uses err.message. Stack traces often contain additional context that improves matching accuracy.

♻️ Optional: Include stack trace for richer analysis
 process.on("uncaughtException", (err) => {
-  // Use the message for the search, guard against non-Error throws
-  const msg = (err && err.message) ? err.message : String(err);
+  // Use the stack trace for the search (includes message), guard against non-Error throws
+  const msg = (err && typeof err === "object") ? (err.stack || err.message) : String(err);
   const { count, matches } = findError(msg);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/auto.js` around lines 6 - 8, The extraction of the error text for
findError in lib/auto.js only uses err.message (const msg = ...), so update the
logic to prefer the stack when available (e.g., use err.stack || err.message or
concatenate both) before passing to findError; modify the msg assignment in the
same block where const msg is defined so that findError(msg) receives the richer
text for better matching.

10-17: Output flow is correct; static analysis hint is low-priority.

The logic properly branches on match count. The Biome warning about forEach callback return value is technically correct (arrow function implicitly returns console.log's undefined), but has no functional impact. If you want to silence the linter:

♻️ Optional: Use block body to satisfy linter
-    matches.forEach(match => console.log(formatError(match)));
+    matches.forEach(match => { console.log(formatError(match)); });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/auto.js` around lines 10 - 17, The linter warns about the implicit return
of the arrow callback in the forEach call in the auto.js block that logs
matches; change the arrow callback in matches.forEach(match =>
console.log(formatError(match))) to use a block body (e.g.,
matches.forEach(match => { console.log(formatError(match)); })) or replace with
a for...of loop to explicitly avoid returning a value from the callback in the
function that prints detected issues.
lib/injector.js (1)

17-17: Optional: Silence linter warnings on forEach callbacks.

Same low-priority issue as lib/auto.js - the arrow functions implicitly return console.log's undefined. No functional impact, but block bodies would satisfy the linter.

♻️ Optional fix for both lines
-    matches.forEach(match => console.log(formatError(match)));
+    matches.forEach(match => { console.log(formatError(match)); });

Also applies to: 35-35

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@lib/injector.js` at line 17, The linter warns because the forEach callbacks
use concise arrow bodies that implicitly return console.log's undefined; update
the callbacks in lib/injector.js (the matches.forEach(...) calls that invoke
formatError) to use block arrow bodies so they explicitly execute console.log
without an implicit return (e.g., replace the concise arrow with a
brace-enclosed block that calls console.log(formatError(match));); do the same
for the other occurrence on the file (around the second matches.forEach).
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@bin/index.js`:
- Line 60: The forEach callback uses a concise arrow body which triggers the
linter warning elsewhere; update the matches.forEach usage (the matches.forEach
callback that calls formatError) to use a block body arrow function instead
(e.g., matches.forEach(m => { console.log(formatError(m)); }) ) so it matches
the style used in lib/auto.js and lib/injector.js and silences the Biome warning
while keeping the same behavior.

In `@lib/auto.js`:
- Around line 6-8: The extraction of the error text for findError in lib/auto.js
only uses err.message (const msg = ...), so update the logic to prefer the stack
when available (e.g., use err.stack || err.message or concatenate both) before
passing to findError; modify the msg assignment in the same block where const
msg is defined so that findError(msg) receives the richer text for better
matching.
- Around line 10-17: The linter warns about the implicit return of the arrow
callback in the forEach call in the auto.js block that logs matches; change the
arrow callback in matches.forEach(match => console.log(formatError(match))) to
use a block body (e.g., matches.forEach(match => {
console.log(formatError(match)); })) or replace with a for...of loop to
explicitly avoid returning a value from the callback in the function that prints
detected issues.

In `@lib/injector.js`:
- Line 17: The linter warns because the forEach callbacks use concise arrow
bodies that implicitly return console.log's undefined; update the callbacks in
lib/injector.js (the matches.forEach(...) calls that invoke formatError) to use
block arrow bodies so they explicitly execute console.log without an implicit
return (e.g., replace the concise arrow with a brace-enclosed block that calls
console.log(formatError(match));); do the same for the other occurrence on the
file (around the second matches.forEach).

ℹ️ Review info

Configuration used: defaults

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 064087f and 5550209.

📒 Files selected for processing (4)
  • bin/index.js
  • lib/auto.js
  • lib/injector.js
  • lib/matcher.js

@naheel0 naheel0 merged commit a7aa0ce into main Mar 1, 2026
5 checks passed
@naheel0 naheel0 deleted the database branch March 1, 2026 13:54
@coderabbitai coderabbitai Bot mentioned this pull request Mar 4, 2026
10 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants