Skip to content

feat(diagnose): add AI diagnosis with SSE streaming and rating#59

Open
jwfing wants to merge 6 commits intomainfrom
feat/diagnosis
Open

feat(diagnose): add AI diagnosis with SSE streaming and rating#59
jwfing wants to merge 6 commits intomainfrom
feat/diagnosis

Conversation

@jwfing
Copy link
Copy Markdown
Member

@jwfing jwfing commented Apr 10, 2026

Summary

  • Add --ai <question> option to insforge diagnose for cloud-powered AI analysis
  • Stream analysis results from POST /diagnostic/v1/analyze via SSE with real-time text output
  • Handle 5 SSE event types: delta (streamed text), tool_call, tool_result, done, error
  • After analysis, prompt user to rate the result (helpful / not helpful / incorrect) via POST /diagnostic/v1/sessions/{sessionId}/rating
  • Send client_info (CLI version, Node.js version, OS) alongside diagnostic context
  • Refactor data collection into shared collectDiagnosticData() used by both standard report and AI modes
  • Fix lint: remove unused CLIError import in env-vars.ts

Usage

npx @insforge/cli diagnose --ai "why is my API returning 429?"
npx @insforge/cli diagnose --ai "high CPU usage" --json

Test plan

  • Run diagnose --ai "test question" and verify SSE streaming output
  • Verify rating prompt appears after analysis and submits successfully
  • Run with --json and verify structured event output
  • Verify standard diagnose (no --ai) still works unchanged
  • Verify question length validation (1-2000 chars)

🤖 Generated with Claude Code

Note

Add AI diagnosis with SSE streaming and post-analysis rating to the diagnose command

  • Adds an --ai <question> flag to the diagnose command in src/commands/diagnose/index.ts that streams AI analysis of collected diagnostics via Server-Sent Events.
  • Adds streamDiagnosticAnalysis (POSTs to /diagnostic/v1/analyze, parses SSE delta/tool_call/done/error events) and rateDiagnosticSession (POSTs to /diagnostic/v1/sessions/{sessionId}/rating) in src/lib/api/platform.ts.
  • Extracts a collectDiagnosticData helper that concurrently gathers metrics, advisor summary, DB checks, and logs, normalizing results and accumulating errors for both AI and standard output flows.
  • After streaming, the CLI optionally prompts the user for a 1–5 star rating via @clack/prompts and submits it; usage is tracked under distinct event names cli.diagnose vs cli.diagnose.ai.
  • Injects process.env.CLI_VERSION at build time via tsup.config.ts so the CLI version is included in the diagnostic context sent to the AI.

Macroscope summarized d5224b5.

Summary by CodeRabbit

  • New Features

    • Added an AI-powered diagnostic mode (--ai) that streams analysis, supports optional JSON session/events output, and prompts for in-command session rating/feedback.
  • Chores

    • Bumped CLI version to 0.1.44.
    • Removed an unused import and added build-time embedding of the CLI version.

- Add `--ai <question>` option to `diagnose` command
- Stream analysis from POST /diagnostic/v1/analyze via SSE with
  real-time delta output, tool_call indicators, and error handling
- Collect and send client_info (cli_version, node_version, os) in context
- Extract sessionId from done event for rating submission
- Add interactive rating prompt (helpful/not_helpful/incorrect) via
  POST /diagnostic/v1/sessions/{sessionId}/rating
- Refactor data collection into reusable collectDiagnosticData()
- Fix unused CLIError import in env-vars.ts

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 10, 2026

Note

Reviews paused

It looks like this branch is under active development. To avoid overwhelming you with review comments due to an influx of new commits, CodeRabbit has automatically paused this review. You can configure this behavior by changing the reviews.auto_review.auto_pause_after_reviewed_commits setting.

Use the following commands to manage reviews:

  • @coderabbitai resume to resume automatic reviews.
  • @coderabbitai review to trigger a single review.

Use the checkboxes below for quick actions:

  • ▶️ Resume reviews
  • 🔍 Trigger review

Walkthrough

Added AI streaming analysis to the diagnose CLI with interactive rating and JSON/stream modes; implemented streaming diagnostic APIs and session rating in the platform client; bumped package version; exposed CLI version at build time; removed one unused import.

Changes

Cohort / File(s) Summary
Version & small tidy
package.json, src/commands/deployments/env-vars.ts
Bumped package @insforge/cli 0.1.43 → 0.1.44; removed an unused CLIError import.
Diagnostic CLI
src/commands/diagnose/index.ts
Added .option('--ai <question>'); implemented AI streaming path, collectDiagnosticData, JSON vs streamed output, spinner/validation, interactive rating prompt, and adjusted analytics/usage attribution.
Platform API (diagnostics)
src/lib/api/platform.ts
Added DiagnosticRequest, DiagnosticSSEEvent, DiagnosticEventHandler; added streamDiagnosticAnalysis (SSE-like parsing + event callback) and rateDiagnosticSession; enhanced platformFetch debug and error-message handling.
Build config
tsup.config.ts
Read package.json at build time and defined process.env.CLI_VERSION with the package version for the bundle.
Project linking defaults
src/commands/projects/link.ts
Adjusted OSS/self-hosted default ProjectConfig values (project_id, org_id, appkey, region) for direct-link branch.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Suggested reviewers

  • CarmenDou
  • tonychang04
  • Fermionic-Lyu

Poem

🐰
I listened to events flow by,
Lines and data, streaming sky,
I nudged the version, gave a hop,
Rated answers, then I stop —
A tiny rabbit cheers — well done! 🎉

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 11.11% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding AI diagnosis capability to the diagnose command with SSE streaming and rating features, which aligns with the primary focus of the changeset.
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 unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/diagnosis

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: 5

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

Inline comments:
In `@src/commands/diagnose/index.ts`:
- Around line 166-169: When in JSON mode the handler early-returns after pushing
to jsonEvents, so sessionId (the variable consumed by outputJson()) is never
captured; update the event callback that pushes to jsonEvents to also extract
and store event.data.sessionId (when present) into the same sessionId variable
before returning. Apply the same change to the other JSON fast-path branches
referenced (the handlers around the "done" and the later event handlers) so any
event carrying sessionId sets it immediately, ensuring outputJson() emits the
correct sessionId.
- Around line 166-169: The handler that processes SSE events currently returns
early for json mode on error events and only logs errors in TTY, which lets the
command exit successfully; change the logic in the event callback that
references jsonEvents/events so that on event.type === 'error' you record the
error (e.g., push the error payload into jsonEvents or set an error flag)
instead of returning early, and after streaming completes (where the function
currently decides exit success) check for any recorded streamed errors and throw
a CLIError (include the error message/payload) so the command exits non-zero;
apply the same change to the other identical handlers around the json handling
at the referenced blocks (lines noted in the review: also applies to 186-188 and
229-230) and ensure TTY logging still emits the error but does not mask the
thrown CLIError.
- Around line 29-39: The ossMode fallback in collectDiagnosticData is never
reached because the caller invokes requireAuth(apiUrl) before computing ossMode,
causing early exit for API-key-linked projects; to fix, compute/determine
ossMode (or whether the project is API-key linked) before calling requireAuth so
collectDiagnosticData can run its degraded-path branches, or change the call
site to defer requireAuth until after collectDiagnosticData has been invoked;
update the caller flow that currently calls requireAuth(apiUrl) prior to
invoking collectDiagnosticData (and adjust any related logic) so
collectDiagnosticData's ossMode branches can execute when appropriate.
- Around line 229-230: The failure telemetry is misclassified because the AI
success path calls reportCliUsage('cli.diagnose.ai') but the shared catch block
always reports 'cli.diagnose'; update the code so the catch block reports the
same event name used for success when the AI path is active. Concretely,
introduce a local variable/eventName (e.g., const telemetryEvent =
'cli.diagnose.ai' when invoking the AI flow) or an isAiRun flag in the diagnose
command, use that variable when calling reportCliUsage in both the success
branch and the shared catch block (reportCliUsage(telemetryEvent, false)), and
ensure any existing non-AI path still uses 'cli.diagnose' unchanged.
- Around line 127-136: The current runtime package.json lookup in
src/commands/diagnose/index.ts (the block that sets cliVersion by reading
package.json using import.meta.url and join(... '../../../package.json')) fails
for tsup-bundled single-file outputs; replace this runtime filesystem traversal
with a build-time injected constant or a bundled data import: stop using
import.meta.url/readFileSync for cliVersion and either (a) add a DEFINE like
CLI_VERSION via tsup's define option and reference that constant where
cliVersion is set, or (b) generate a small version.json at build time and import
it (e.g. import version from './version.json') so the Diagnose command reads the
injected/bundled version instead of reading package.json at runtime.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: fc8867ff-0f8c-4692-8fe3-ccf2ad2fb07f

📥 Commits

Reviewing files that changed from the base of the PR and between a6a1abd and 23c6b52.

📒 Files selected for processing (4)
  • package.json
  • src/commands/deployments/env-vars.ts
  • src/commands/diagnose/index.ts
  • src/lib/api/platform.ts

- SSE parser: initialize currentEvent to 'delta', validate against
  known event types before casting
- SSE parser: flush remaining buffer and multi-byte sequences after
  stream ends
- CLI version: inject via tsup define (process.env.CLI_VERSION) instead
  of runtime package.json path traversal that breaks in bundled output
- sessionId: capture from done event before JSON early-return so it's
  included in JSON output
- Stream errors: record as CLIError and throw after streaming completes
  instead of silently succeeding
- Telemetry: use consistent usageEvent variable for both success and
  failure paths (cli.diagnose.ai vs cli.diagnose)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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: 1

🧹 Nitpick comments (3)
src/lib/api/platform.ts (2)

225-225: Encode sessionId before embedding it in the URL path.

Dynamic path segments should be URL-encoded to avoid malformed requests when IDs contain reserved characters.

Proposed fix
-  await platformFetch(`/diagnostic/v1/sessions/${sessionId}/rating`, {
+  await platformFetch(`/diagnostic/v1/sessions/${encodeURIComponent(sessionId)}/rating`, {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/api/platform.ts` at line 225, The call building the path for
platformFetch embeds sessionId directly which can break URLs if the ID contains
reserved characters; update the call that uses platformFetch and the sessionId
variable to URL-encode the dynamic segment (e.g., replace
`/diagnostic/v1/sessions/${sessionId}/rating` with a path that uses
encodeURIComponent(sessionId) when constructing the string) so the sessionId is
safely encoded before sending the request.

156-158: Function docstring is stale versus actual return type.

The comment says it returns raw Response, but the function returns Promise<void> (Line 163). This can cause incorrect caller assumptions.

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

In `@src/lib/api/platform.ts` around lines 156 - 158, The docstring for
streamDiagnosticAnalysisViaSSE is stale: it claims the function returns a raw
Response while the implementation returns Promise<void>; update the function
comment to accurately describe the actual return type and behavior (e.g.,
"Returns Promise<void>; streaming handled via onEvent and caller receives errors
via thrown exceptions or callback") or alternatively change the function
signature to return the raw Response if you intend that behavior—edit the
comment near the streamDiagnosticAnalysisViaSSE definition to match whichever
approach you choose so the docstring and the function (return type Promise<void>
or Response) are consistent.
tsup.config.ts (1)

4-4: Avoid CWD-coupled package.json resolution in build config.

Line 4 uses a relative path string ('./package.json'), which can break when build is executed from a different working directory.

Proposed fix
-const pkg = JSON.parse(readFileSync('./package.json', 'utf-8')) as { version: string };
+const pkg = JSON.parse(
+  readFileSync(new URL('./package.json', import.meta.url), 'utf-8'),
+) as { version: string };
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@tsup.config.ts` at line 4, The build config currently reads package.json via
a CWD-dependent relative path in the const pkg assignment; change it to resolve
package.json relative to the config file itself (e.g., using
fileURLToPath(import.meta.url) + dirname or new URL('./package.json',
import.meta.url)) and then readFileSync that resolved path before JSON.parse, so
pkg loading no longer depends on the current working directory.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/lib/api/platform.ts`:
- Around line 179-190: processLine currently leaves currentEvent unchanged when
an unknown "event:" line is seen, causing a following "data:" line to be emitted
with a stale type; update processLine so that when an "event:" value is not in
VALID_EVENTS it explicitly resets currentEvent (e.g., to undefined/null) and
returns, and ensure the "data:" branch only calls onEvent({ type: currentEvent,
data }) when currentEvent is a valid DiagnosticSSEEvent['type']; reference
processLine, currentEvent, VALID_EVENTS, DiagnosticSSEEvent, and onEvent when
making the change.

---

Nitpick comments:
In `@src/lib/api/platform.ts`:
- Line 225: The call building the path for platformFetch embeds sessionId
directly which can break URLs if the ID contains reserved characters; update the
call that uses platformFetch and the sessionId variable to URL-encode the
dynamic segment (e.g., replace `/diagnostic/v1/sessions/${sessionId}/rating`
with a path that uses encodeURIComponent(sessionId) when constructing the
string) so the sessionId is safely encoded before sending the request.
- Around line 156-158: The docstring for streamDiagnosticAnalysisViaSSE is
stale: it claims the function returns a raw Response while the implementation
returns Promise<void>; update the function comment to accurately describe the
actual return type and behavior (e.g., "Returns Promise<void>; streaming handled
via onEvent and caller receives errors via thrown exceptions or callback") or
alternatively change the function signature to return the raw Response if you
intend that behavior—edit the comment near the streamDiagnosticAnalysisViaSSE
definition to match whichever approach you choose so the docstring and the
function (return type Promise<void> or Response) are consistent.

In `@tsup.config.ts`:
- Line 4: The build config currently reads package.json via a CWD-dependent
relative path in the const pkg assignment; change it to resolve package.json
relative to the config file itself (e.g., using fileURLToPath(import.meta.url) +
dirname or new URL('./package.json', import.meta.url)) and then readFileSync
that resolved path before JSON.parse, so pkg loading no longer depends on the
current working directory.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: a703fe01-e830-420d-bd22-c4e4dc4da3ff

📥 Commits

Reviewing files that changed from the base of the PR and between 23c6b52 and a5a9137.

📒 Files selected for processing (3)
  • src/commands/diagnose/index.ts
  • src/lib/api/platform.ts
  • tsup.config.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/commands/diagnose/index.ts

Align with backend OpenAPI spec: session_id instead of sessionId,
tool_name instead of toolName.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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.

♻️ Duplicate comments (1)
src/commands/diagnose/index.ts (1)

105-112: ⚠️ Potential issue | 🟠 Major

Move auth gating after OSS-mode detection to preserve degraded diagnostics.

At Line 105, unconditional requireAuth(apiUrl) prevents the ossMode fallback logic from ever executing, so partial diagnostics cannot run for API-key-linked OSS projects.

Suggested fix
-        await requireAuth(apiUrl);
         const config = getProjectConfig();
         if (!config) throw new ProjectNotLinkedError();

         const projectId = config.project_id;
         const projectName = config.project_name;
         const ossMode = config.project_id === 'oss-project';
+        if (!ossMode) {
+          await requireAuth(apiUrl);
+        }
         trackDiagnose(opts.ai ? 'ai' : 'report', config);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/diagnose/index.ts` around lines 105 - 112, The call to
requireAuth(apiUrl) is currently unconditional and blocks the ossMode fallback;
instead, first call getProjectConfig() and compute ossMode (using
config.project_id === 'oss-project') and run trackDiagnose(opts.ai ? 'ai' :
'report', config), then only call requireAuth(apiUrl) if needed for non-OSS
flows; ensure ProjectNotLinkedError is still thrown when config is missing and
preserve existing behavior for API-key-linked projects while allowing degraded
diagnostics when ossMode is true.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/commands/diagnose/index.ts`:
- Around line 105-112: The call to requireAuth(apiUrl) is currently
unconditional and blocks the ossMode fallback; instead, first call
getProjectConfig() and compute ossMode (using config.project_id ===
'oss-project') and run trackDiagnose(opts.ai ? 'ai' : 'report', config), then
only call requireAuth(apiUrl) if needed for non-OSS flows; ensure
ProjectNotLinkedError is still thrown when config is missing and preserve
existing behavior for API-key-linked projects while allowing degraded
diagnostics when ossMode is true.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 5bb8c19b-6aa2-406b-a0b8-eaae53b87473

📥 Commits

Reviewing files that changed from the base of the PR and between a5a9137 and e6db246.

📒 Files selected for processing (1)
  • src/commands/diagnose/index.ts

Set currentEvent to null when event type is not in VALID_EVENTS,
and skip data lines when currentEvent is null to prevent emitting
events with a stale type.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
@jwfing jwfing requested review from CarmenDou and tonychang04 April 11, 2026 03:50
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: 3

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

Inline comments:
In `@src/lib/api/platform.ts`:
- Line 224: Interpolate an encoded sessionId into the platformFetch path to
avoid reserved-character issues: replace the direct `${sessionId}` usage in the
call to platformFetch(`/diagnostic/v1/sessions/${sessionId}/rating`, ...) by
wrapping sessionId with encodeURIComponent (i.e., use
encodeURIComponent(sessionId)) so the URL path segment is safely encoded; update
the invocation in platformFetch where the sessionId variable is used.
- Around line 155-158: The JSDoc for streamDiagnosticAnalysis is wrong: it
claims the function returns a raw Response but the signature is Promise<void>;
update the comment for the function (streamDiagnosticAnalysis) to reflect the
actual return contract (e.g., state that it returns Promise<void> which resolves
when streaming setup completes and that the raw Response is not returned), or
alternatively modify the function signature to return Promise<Response> if you
intend to return the raw Response—pick one and make the JSDoc and the function
signature consistent.
- Around line 179-193: processLine currently dispatches each 'data:' line
immediately, which breaks SSE multi-line messages; change it to accumulate
consecutive 'data:' lines into a buffer (e.g., currentData string/array) when
encountering lines that start with 'data:' (append raw content, join with '\n'
between entries), and only attempt JSON.parse and call onEvent({ type:
currentEvent, data }) when a blank line (empty or whitespace-only) is seen;
after dispatching reset currentData and currentEvent appropriately and ensure
malformed JSON is caught and ignored. Update the same logic in the other handler
block referenced (lines ~204-213) so both places use currentEvent and
currentData for proper SSE framing.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0bb867a2-3281-41c4-8828-469819f53857

📥 Commits

Reviewing files that changed from the base of the PR and between e6db246 and bccbdc9.

📒 Files selected for processing (1)
  • src/lib/api/platform.ts

jwfing and others added 2 commits April 12, 2026 15:35
- Filter out metrics with no data points (avoid null values)
- Strip extra advisor fields (scanId, scanType, etc.), only send
  summary + collectorErrors as string[]
- Stringify all db values to match spec types (string not number)
- Explicitly pick log error fields (timestamp, message, source)
- Improve platformFetch error message to include response message field
- Add INSFORGE_DEBUG env var for request logging

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Replace non-hex placeholder IDs (oss-project, oss-org) with
properly formatted UUIDs for OSS/self-hosted linking.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
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: 2

♻️ Duplicate comments (4)
src/lib/api/platform.ts (2)

225-236: ⚠️ Potential issue | 🟠 Major

Encode sessionId before inserting it into the URL path.

Reserved characters in sessionId can change the request path and send the rating to the wrong endpoint.

Suggested fix
-  await platformFetch(`/diagnostic/v1/sessions/${sessionId}/rating`, {
+  await platformFetch(`/diagnostic/v1/sessions/${encodeURIComponent(sessionId)}/rating`, {
     method: 'POST',
     body: JSON.stringify(body),
   }, apiUrl);
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/api/platform.ts` around lines 225 - 236, The sessionId is inserted
into the request URL without encoding, so reserved characters could break the
path; update the URL construction in rateDiagnosticSession to use an encoded
sessionId (e.g., call encodeURIComponent(sessionId)) when building
`/diagnostic/v1/sessions/${...}/rating` so the platformFetch request always
targets the intended endpoint.

188-202: ⚠️ Potential issue | 🟠 Major

SSE framing is still incomplete.

This still emits on every data: line instead of buffering until the blank-line delimiter, so multi-line events are fragmented or lost. That was the earlier SSE-spec issue and it remains unresolved here.

Also applies to: 205-222

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

In `@src/lib/api/platform.ts` around lines 188 - 202, processLine currently emits
on every `data:` line, fragmenting multi-line SSE messages; change it to buffer
consecutive `data:` lines and only parse/emit when a blank-line delimiter is
received: add a `dataBuffer` string (or array) scoped with `currentEvent` in the
same module, on `data:` append the raw line (preserving newline between lines),
on blank line (line.trim() === '') join the buffered lines into a single string,
parse JSON once and call `onEvent({ type: currentEvent, data })`, then clear
`dataBuffer` and `currentEvent`; ensure malformed JSON is handled the same and
apply the same fix to the other identical block referenced around lines 205-222
so both occurrences (the `processLine` implementations) behave identically.
src/commands/diagnose/index.ts (2)

102-113: ⚠️ Potential issue | 🟠 Major

OSS-linked projects still fail before the degraded path can run.

requireAuth(apiUrl) executes before the project config is read, so API-key-linked/self-hosted projects exit immediately and never reach collectDiagnosticData(..., ossMode, ...). That keeps insforge diagnose broken for direct links.

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

In `@src/commands/diagnose/index.ts` around lines 102 - 113, The command calls
requireAuth(apiUrl) before reading project config, which causes
API-key/self-hosted projects to exit early; change the order so
getProjectConfig() is called first (call getProjectConfig() and compute ossMode
using config.project_id), then only call requireAuth(apiUrl) when ossMode is
false (i.e., for non-OSS linked projects) so collectDiagnosticData(..., ossMode,
...) and the degraded OSS path run for direct links; update references in the
action handler around requireAuth, getProjectConfig, ossMode, trackDiagnose and
collectDiagnosticData accordingly.

210-213: ⚠️ Potential issue | 🟠 Major

Use sessionId instead of session_id in the done event handler.

The done event data uses camelCase sessionId. Reading event.data.session_id (snake_case) will be undefined, silently breaking rating submission and JSON output.

Suggested fix
             if (event.type === 'done') {
-              sessionId = event.data.session_id as string | undefined;
+              sessionId = event.data.sessionId as string | undefined;
             }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/commands/diagnose/index.ts` around lines 210 - 213, In the done event
handler use the camelCase property: replace reading event.data.session_id with
event.data.sessionId so the existing sessionId variable (captured earlier) is
assigned correctly when event.type === 'done'; update the assignment in the
block that checks event.type === 'done' (the code referencing sessionId and
event.data) to use event.data.sessionId to ensure rating submission and JSON
output receive the real sessionId.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/commands/projects/link.ts`:
- Around line 77-84: The diff replaced the OSS sentinel value with UUID-shaped
IDs which breaks existing checks that look for config.project_id ===
'oss-project'; instead add an explicit boolean flag (e.g., isOSS or
isSelfHosted) to the ProjectConfig type and set it when constructing
projectConfig in link.ts, then update the consumers that currently check
config.project_id === 'oss-project' (notably the logic in diagnose/index.ts and
lib/analytics.ts) to check the new flag (config.isOSS) so behavior remains
consistent without relying on a sentinel ID; ensure ProjectConfig declaration,
the creation site (projectConfig), and all callers are migrated together.

In `@src/lib/api/platform.ts`:
- Around line 29-34: The debug logging block gated by process.env.INSFORGE_DEBUG
is leaking sensitive data (Authorization bearer tokens and full request bodies);
update the logging in the platform debug section to redact auth-like headers
(e.g., any header key matching /authorization|auth/i or value starting with
"Bearer ") and to avoid printing full bodies by either masking large/JSON bodies
or printing only a truncated/summary string; modify the code that inspects
headers and options.body (the same place that currently logs headers and body)
to create a sanitizedHeaders object and a safeBody string before passing them to
console.error so tokens and PII are not emitted.

---

Duplicate comments:
In `@src/commands/diagnose/index.ts`:
- Around line 102-113: The command calls requireAuth(apiUrl) before reading
project config, which causes API-key/self-hosted projects to exit early; change
the order so getProjectConfig() is called first (call getProjectConfig() and
compute ossMode using config.project_id), then only call requireAuth(apiUrl)
when ossMode is false (i.e., for non-OSS linked projects) so
collectDiagnosticData(..., ossMode, ...) and the degraded OSS path run for
direct links; update references in the action handler around requireAuth,
getProjectConfig, ossMode, trackDiagnose and collectDiagnosticData accordingly.
- Around line 210-213: In the done event handler use the camelCase property:
replace reading event.data.session_id with event.data.sessionId so the existing
sessionId variable (captured earlier) is assigned correctly when event.type ===
'done'; update the assignment in the block that checks event.type === 'done'
(the code referencing sessionId and event.data) to use event.data.sessionId to
ensure rating submission and JSON output receive the real sessionId.

In `@src/lib/api/platform.ts`:
- Around line 225-236: The sessionId is inserted into the request URL without
encoding, so reserved characters could break the path; update the URL
construction in rateDiagnosticSession to use an encoded sessionId (e.g., call
encodeURIComponent(sessionId)) when building
`/diagnostic/v1/sessions/${...}/rating` so the platformFetch request always
targets the intended endpoint.
- Around line 188-202: processLine currently emits on every `data:` line,
fragmenting multi-line SSE messages; change it to buffer consecutive `data:`
lines and only parse/emit when a blank-line delimiter is received: add a
`dataBuffer` string (or array) scoped with `currentEvent` in the same module, on
`data:` append the raw line (preserving newline between lines), on blank line
(line.trim() === '') join the buffered lines into a single string, parse JSON
once and call `onEvent({ type: currentEvent, data })`, then clear `dataBuffer`
and `currentEvent`; ensure malformed JSON is handled the same and apply the same
fix to the other identical block referenced around lines 205-222 so both
occurrences (the `processLine` implementations) behave identically.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 9ff1fd8e-d025-423d-b77e-cabd407f0a97

📥 Commits

Reviewing files that changed from the base of the PR and between bccbdc9 and d5224b5.

📒 Files selected for processing (3)
  • src/commands/diagnose/index.ts
  • src/commands/projects/link.ts
  • src/lib/api/platform.ts

Comment on lines 77 to 84
const projectConfig: ProjectConfig = {
project_id: 'oss-project',
project_id: 'fa4e0000-1234-5678-90ab-0e02b2c3d479',
project_name: 'oss-project',
org_id: 'oss-org',
appkey: 'oss',
region: 'local',
org_id: 'fa4e0001-1234-5678-90ab-0e02b2c3d479',
appkey: 'ossfkey',
region: 'us-test',
api_key: opts.apiKey,
oss_host: opts.apiBaseUrl.replace(/\/$/, ''), // remove trailing slash if any
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Don’t change the OSS sentinel without migrating its consumers.

These UUID placeholders no longer match the existing config.project_id === 'oss-project' checks in src/commands/diagnose/index.ts and src/lib/analytics.ts, so direct-linked projects will now be treated like platform-linked ones. If you need UUID-shaped IDs here, add an explicit OSS/self-hosted flag to ProjectConfig and switch those callers to that instead.

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

In `@src/commands/projects/link.ts` around lines 77 - 84, The diff replaced the
OSS sentinel value with UUID-shaped IDs which breaks existing checks that look
for config.project_id === 'oss-project'; instead add an explicit boolean flag
(e.g., isOSS or isSelfHosted) to the ProjectConfig type and set it when
constructing projectConfig in link.ts, then update the consumers that currently
check config.project_id === 'oss-project' (notably the logic in
diagnose/index.ts and lib/analytics.ts) to check the new flag (config.isOSS) so
behavior remains consistent without relying on a sentinel ID; ensure
ProjectConfig declaration, the creation site (projectConfig), and all callers
are migrated together.

Comment on lines +29 to +34
if (process.env.INSFORGE_DEBUG) {
console.error(`[DEBUG] ${options.method ?? 'GET'} ${url}`);
console.error(`[DEBUG] Headers: ${JSON.stringify(headers, null, 2)}`);
if (options.body) {
console.error(`[DEBUG] Body: ${typeof options.body === 'string' ? options.body : JSON.stringify(options.body)}`);
}
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Redact auth headers and diagnostic bodies from debug logs.

INSFORGE_DEBUG currently prints the bearer token verbatim and can dump full diagnostic payloads to stderr. That is enough to leak credentials and user data into CI or support logs.

Suggested fix
   const url = `${baseUrl}${path}`;
   if (process.env.INSFORGE_DEBUG) {
+    const debugHeaders = {
+      ...headers,
+      ...(headers.Authorization ? { Authorization: 'Bearer [REDACTED]' } : {}),
+    };
     console.error(`[DEBUG] ${options.method ?? 'GET'} ${url}`);
-    console.error(`[DEBUG] Headers: ${JSON.stringify(headers, null, 2)}`);
+    console.error(`[DEBUG] Headers: ${JSON.stringify(debugHeaders, null, 2)}`);
     if (options.body) {
-      console.error(`[DEBUG] Body: ${typeof options.body === 'string' ? options.body : JSON.stringify(options.body)}`);
+      console.error('[DEBUG] Body: [redacted]');
     }
   }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/lib/api/platform.ts` around lines 29 - 34, The debug logging block gated
by process.env.INSFORGE_DEBUG is leaking sensitive data (Authorization bearer
tokens and full request bodies); update the logging in the platform debug
section to redact auth-like headers (e.g., any header key matching
/authorization|auth/i or value starting with "Bearer ") and to avoid printing
full bodies by either masking large/JSON bodies or printing only a
truncated/summary string; modify the code that inspects headers and options.body
(the same place that currently logs headers and body) to create a
sanitizedHeaders object and a safeBody string before passing them to
console.error so tokens and PII are not emitted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant