Skip to content

fix: resolve proxy bugs and part ID prefix mismatch (#19, #20, #21, #23)#24

Open
SoulWayy wants to merge 5 commits into
joelhooks:mainfrom
OnlineChefGroep:fix/proxy-bugs-part-id-prefix
Open

fix: resolve proxy bugs and part ID prefix mismatch (#19, #20, #21, #23)#24
SoulWayy wants to merge 5 commits into
joelhooks:mainfrom
OnlineChefGroep:fix/proxy-bugs-part-id-prefix

Conversation

@SoulWayy

@SoulWayy SoulWayy commented Jun 10, 2026

Copy link
Copy Markdown

Summary

This PR resolves 4 critical bugs in the proxy layer and part ID generation:

Bug Fixes

  1. Fix Bug: prompt_async returns 400 - part IDs must start with "prt"Β #19: Part ID prefix mismatch

    • Changed generatePartId() from part- to prt- prefix in packages/core/src/api/prompt.ts
    • Aligns with OpenCode SDK expectations
  2. Fix Bug: API proxy doesn't forward POST body in Bun/Next.js 16Β #20: POST body forwarding crash

    • Replaced request.body ReadableStream with request.text() for POST/PUT/PATCH
    • Removed duplex: "half" workaround that failed in bun/Next.js 16
    • Added 204 No Content handling: returns new NextResponse(null, { status: 204 }) instead of crashing
  3. Fix Bug: OpencodeSSRPlugin with empty directory from ServerStatus breaks store lookupsΒ #21: SSRPlugin directory mismatch

    • Made directory optional in OpencodeConfig interface
    • Updated SessionLayout to always render OpencodeSSRPlugin (not conditionally)
    • Uses directory ?? "" for consistent store key lookup
  4. Fix Bug: API proxy drops all headers except content-type and x-opencode-directoryΒ #23: Header forwarding incomplete

    • Now forwards ALL request headers (authorization, accept, x-custom-*, etc.)
    • Filters out hop-by-hop headers per RFC 2616 (connection, keep-alive, transfer-encoding, te, trailer, upgrade)

Tests Updated

  • Uncommented 204 No Content test (was blocked by bug)
  • Added header forwarding tests: verifies all headers forwarded + hop-by-hop filtered
  • Removed outdated duplex: "half" checks from POST/PUT/PATCH tests
  • All 34 proxy route tests pass, 8 prompt tests pass

Files Changed

  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts β€” proxy implementation
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts β€” proxy tests
  • packages/core/src/api/prompt.ts β€” part ID generation
  • packages/react/src/next-ssr-plugin.tsx β€” SSR plugin directory handling
  • apps/web/src/app/session/[id]/session-layout.tsx β€” session layout

Verification

bun test apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts  # 34 pass
bun test packages/core/src/api/prompt.test.ts                             # 8 pass

Closes #19, #20, #21, #23

Summary by CodeRabbit

  • Bug Fixes

    • Proxy omits hop-by-hop headers (including names from Connection), handles empty Connection, and properly returns 204 No Content for DELETE/upstream 204 responses.
  • New Features

    • Proxy forwards all other incoming request headers.
    • Server spawn endpoint adds directory validation, normalization, blocked-path protections, and stricter startup/error handling.
  • Refactor

    • Session layout always mounts SSR plugin; directory config is now optional.
  • Chores

    • Generated part IDs now use "prt-" prefix; SSE payload typing tightened.
  • Tests

    • Expanded proxy and spawn tests to cover header handling, methods, validation, and startup scenarios.

- Fix joelhooks#19: Change generatePartId() prefix from 'part-' to 'prt-'
- Fix joelhooks#20: Replace request.body ReadableStream with request.text() for POST body forwarding
- Fix joelhooks#20: Add 204 No Content handling (return null body instead of crashing)
- Fix joelhooks#21: Make directory optional in OpencodeConfig, handle empty directory
- Fix joelhooks#23: Forward ALL request headers except hop-by-hop headers (RFC 2616)

Tests updated:
- Uncommented 204 No Content test
- Added header forwarding tests (all headers forwarded, hop-by-hop filtered)
- Removed outdated duplex: 'half' checks
- All 34 proxy route tests pass, 8 prompt tests pass

Closes joelhooks#19, joelhooks#20, joelhooks#21, joelhooks#23
@SoulWayy SoulWayy requested a review from joelhooks as a code owner June 10, 2026 00:03
@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

πŸ“ Walkthrough

Walkthrough

Proxy now forwards all non-hop-by-hop request headers (excludes Connection-listed tokens), reads POST/PUT/PATCH bodies via request.text(), returns empty 204 responses with headers, updates header/method tests, always mounts OpencodeSSRPlugin with optional directory, hardens server-spawn validation, and switches part IDs to the prt- prefix.

Changes

API Proxy Robustness and Configuration Updates

Layer / File(s) Summary
API Proxy headers and core implementation
apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts
Defines HOP_BY_HOP_HEADERS, removes Connection-listed headers from forwarding, forwards remaining incoming headers, reads POST/PUT/PATCH bodies via request.text(), handles 204 responses early and copies upstream headers, and copies all upstream response headers while ensuring a default content-type.
HTTP method and header tests
apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts
Adds header-forwarding tests asserting hop-by-hop and Connection-token filtering; removes duplex assertions for POST/PUT/PATCH; updates DELETE to expect 204; enables strengthened 204 empty-response test and adds invalid-port/reserved-segment negative tests for multiple methods.
Session layout and SSR plugin
packages/react/src/next-ssr-plugin.tsx, apps/web/src/app/session/[id]/session-layout.tsx
Makes OpencodeConfig.directory optional and always renders OpencodeSSRPlugin in session layout with directory ?? ""; updates inline docs to reflect always-on behavior.
Part ID generation contract
packages/core/src/api/prompt.ts
Changes generatePartId() to produce IDs with prt- prefix (prt-${Date.now()}-${counter++}) to satisfy backend validation.
Server spawn route and tests
apps/web/src/app/api/opencode/servers/spawn/route.ts, apps/web/src/app/api/opencode/servers/spawn/route.test.ts
Adds directory canonicalization/validation and blocked-prefix checks, fetch timeout for discovery, uses canonical path for lookup/spawn/wait, guards process.kill on missing pid; adds Vitest tests mocking fs/child_process covering validation, discovery, successful spawn, and spawn error handling.
SSE typing and factory comment
packages/core/src/sse/multi-server-sse.ts, packages/react/src/factory.ts
Types SSE payloads as Event from @opencode-ai/sdk, casts emitted payload accordingly, and removes a @ts-expect-error by documenting the typing assumption in comments while keeping runtime behavior.
sequenceDiagram
  participant Client
  participant proxyRequest
  participant Backend
  Client->>proxyRequest: Request (headers, method, body)
  proxyRequest->>proxyRequest: Remove HOP_BY_HOP and Connection-token headers
  proxyRequest->>Backend: fetch(targetUrl, { method, headers, bodyText? })
  Backend-->>proxyRequest: Response (status, headers, body?)
  alt status == 204
    proxyRequest-->>Client: NextResponse(null, {status:204, headers})
  else
    proxyRequest->>proxyRequest: response.text()
    proxyRequest-->>Client: Response with body and headers
  end
Loading

🎯 4 (Complex) | ⏱️ ~45 minutes

"I nibble headers, hop-by-hop I prune,
Bodies I read as text beneath the moon,
Part IDs wear prt- on their chest,
Spawn routes check paths before they rest,
SSEs typed β€” the plugin's always dressed." 🐰

πŸš₯ Pre-merge checks | βœ… 5
βœ… Passed checks (5 passed)
Check name Status Explanation
Description Check βœ… Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check βœ… Passed The PR title 'fix: resolve proxy bugs and part ID prefix mismatch (#19, #20, #21, #23)' clearly and specifically summarizes the main changes: fixing proxy-related bugs and a part ID prefix issue across linked issues.
Linked Issues check βœ… Passed All changes fully address the objectives from linked issues: part ID prefix changed from 'part-' to 'prt-' [#19], request.text() used for POST bodies and 204 handled explicitly [#20], directory made optional and SessionLayout always renders plugin [#21], and all request headers forwarded with hop-by-hop filtering [#23].
Out of Scope Changes check βœ… Passed All changes directly align with the four linked issues. File modifications focus on proxy routing, part ID generation, SSR plugin configuration, and header forwardingβ€”no out-of-scope refactoring or unrelated changes detected.
Docstring Coverage βœ… Passed Docstring coverage is 80.00% which is sufficient. The required threshold is 80.00%.

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

✨ Finishing Touches
πŸ§ͺ Generate unit tests (beta)
  • Create PR with unit tests

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

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 current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/app/api/opencode/`[port]/[[...path]]/route.test.ts:
- Around line 615-633: The test must fail if the proxy reads an upstream body
for 204 responses: update the mock fetch response used in this test (the object
returned by global.fetch) so its text() is a function that throws or rejects
(e.g. vi.fn().mockImplementation(() => { throw new Error("text() should not be
called for 204"); }) or vi.fn().mockRejectedValue(new Error(...))) instead of
resolving to "", and keep the existing assertions on DELETE and response.text()
accordingly; this ensures the mocked text() will break any implementation that
erroneously calls response.text() for status 204 (target symbols: global.fetch
mock, text(), DELETE handler, NextRequest used in the test).

In `@apps/web/src/app/api/opencode/`[port]/[[...path]]/route.ts:
- Around line 149-150: The 204 branch drops upstream headers by returning new
NextResponse(null, { status: 204 }) without copying response.headers; update the
branch that checks response.status === 204 to create the NextResponse and copy
all headers from response.headers into it (preserve ETag, Cache-Control,
Set-Cookie, etc.) before returning so the proxy remains transparentβ€”use the
existing response object and NextResponse constructor used elsewhere in this
file to transfer headers.
- Around line 125-128: The proxy currently only drops headers in
HOP_BY_HOP_HEADERS when copying request.headers; update the logic to also parse
any Connection header(s) from the incoming request, split on commas, trim and
lower-case each token, add those token names to the deny list, and ensure those
header names (and the Connection header itself) are not forwarded; modify the
loop that copies headers (the code referencing request.headers.entries(),
headers, and HOP_BY_HOP_HEADERS) to build a combined deny set (standard
hop-by-hop plus tokens from Connection) and skip any header whose lower-cased
name appears in that combined set.
πŸͺ„ 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 0f62177a-35a6-442d-b01d-20bb99fd2fbb

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 804a915 and 08d7600.

β›” Files ignored due to path filters (1)
  • bun.lock is excluded by !**/*.lock
πŸ“’ Files selected for processing (5)
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts
  • apps/web/src/app/session/[id]/session-layout.tsx
  • packages/core/src/api/prompt.ts
  • packages/react/src/next-ssr-plugin.tsx

Comment thread apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts Outdated
Comment thread apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts
Comment thread apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts Outdated
- Parse Connection header tokens per RFC 2616 Section 14.10
- Forward upstream headers on 204 No Content responses
- Improve 204 test to verify text() is not called
Spawn endpoint:
- Add validateDirectory() with realpath, stat, BLOCKED_PREFIXES
- Fix child.pid! non-null assertion β†’ guard check
- Add AbortSignal.timeout(2000) to findExistingServer fetch

Proxy:
- Add AbortSignal.timeout(30_000) to proxy fetch
- Forward all upstream response headers
- Default to application/json when upstream has no content-type

Addresses security findings from codebase scan.
- multi-server-sse.ts: Type SSEEvent.payload as SDK Event union
  instead of generic {type: string; properties: Record<string,unknown>}
- factory.ts: Remove @ts-expect-error (now type-safe)
- spawn/route.test.ts: Add 20 tests for directory validation,
  blocked prefixes, existing server detection, spawn flow, error handling

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 1

πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@apps/web/src/app/api/opencode/servers/spawn/route.ts`:
- Around line 68-93: The code currently checks BLOCKED_PREFIXES only against the
pre-realpath normalizedPath, allowing symlinks to resolve into blocked
locations; update the logic so after obtaining canonical via realpath() you
re-run the blocked-prefix check against a canonicalNormalized value (remove
trailing slashes but preserve "/" as a single slash) and return the same {
valid: false, error: ... } if canonical equals a prefix or startsWith
`${prefix}/`; ensure the normalization helper used for both normalizedPath and
canonicalNormalized preserves root ("/") instead of producing an empty string so
the root prefix check still works.
πŸͺ„ 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: ece489d2-856a-4967-9a1e-0eb93782afa8

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 7cb4235 and 72b782b.

πŸ“’ Files selected for processing (5)
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts
  • apps/web/src/app/api/opencode/servers/spawn/route.test.ts
  • apps/web/src/app/api/opencode/servers/spawn/route.ts
  • packages/core/src/sse/multi-server-sse.ts
  • packages/react/src/factory.ts
πŸ’€ Files with no reviewable changes (1)
  • packages/react/src/factory.ts
βœ… Files skipped from review due to trivial changes (1)
  • packages/core/src/sse/multi-server-sse.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.ts

Comment on lines +68 to +93
const absolutePath = isAbsolute(directory) ? directory : resolve(directory)
const normalizedPath = absolutePath.replace(/\/+$/, "")

for (const prefix of BLOCKED_PREFIXES) {
if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
return { valid: false, error: `Cannot spawn server in system directory: ${prefix}` }
}
}

let canonical: string
try {
canonical = await realpath(absolutePath)
} catch {
return { valid: false, error: `Directory does not exist: ${directory}` }
}

try {
const fileStat = await stat(canonical)
if (!fileStat.isDirectory()) {
return { valid: false, error: `Path is not a directory: ${directory}` }
}
} catch {
return { valid: false, error: `Cannot access directory: ${directory}` }
}

return { valid: true, canonical }

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 | ⚑ Quick win

Re-run the blocked-prefix check on the canonical path.

realpath() can turn an allowed-looking input into a blocked system path after the current prefix scan has already passed. A symlink like /tmp/project-link -> /etc will still be accepted and used as cwd, which defeats the hardening added here. Re-check BLOCKED_PREFIXES against the canonical path as well, and add a regression test where realpath() resolves into a blocked directory. This same normalization helper should preserve / instead of turning it into an empty string.

Suggested patch
+const normalizeForPrefixCheck = (path: string) => path.replace(/\/+$/, "") || "/"
+
+const getBlockedPrefix = (path: string) =>
+	BLOCKED_PREFIXES.find((prefix) => path === prefix || path.startsWith(`${prefix}/`))
+
 async function validateDirectory(
 	directory: string,
 ): Promise<{ valid: true; canonical: string } | { valid: false; error: string }> {
 	if (!directory || typeof directory !== "string") {
 		return { valid: false, error: "directory is required" }
 	}
 
 	const absolutePath = isAbsolute(directory) ? directory : resolve(directory)
-	const normalizedPath = absolutePath.replace(/\/+$/, "")
-
-	for (const prefix of BLOCKED_PREFIXES) {
-		if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
-			return { valid: false, error: `Cannot spawn server in system directory: ${prefix}` }
-		}
-	}
+	const blockedBeforeRealpath = getBlockedPrefix(normalizeForPrefixCheck(absolutePath))
+	if (blockedBeforeRealpath) {
+		return {
+			valid: false,
+			error: `Cannot spawn server in system directory: ${blockedBeforeRealpath}`,
+		}
+	}
 
 	let canonical: string
 	try {
 		canonical = await realpath(absolutePath)
 	} catch {
 		return { valid: false, error: `Directory does not exist: ${directory}` }
 	}
+
+	const blockedCanonical = getBlockedPrefix(normalizeForPrefixCheck(canonical))
+	if (blockedCanonical) {
+		return {
+			valid: false,
+			error: `Cannot spawn server in system directory: ${blockedCanonical}`,
+		}
+	}
πŸ“ Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const absolutePath = isAbsolute(directory) ? directory : resolve(directory)
const normalizedPath = absolutePath.replace(/\/+$/, "")
for (const prefix of BLOCKED_PREFIXES) {
if (normalizedPath === prefix || normalizedPath.startsWith(`${prefix}/`)) {
return { valid: false, error: `Cannot spawn server in system directory: ${prefix}` }
}
}
let canonical: string
try {
canonical = await realpath(absolutePath)
} catch {
return { valid: false, error: `Directory does not exist: ${directory}` }
}
try {
const fileStat = await stat(canonical)
if (!fileStat.isDirectory()) {
return { valid: false, error: `Path is not a directory: ${directory}` }
}
} catch {
return { valid: false, error: `Cannot access directory: ${directory}` }
}
return { valid: true, canonical }
const normalizeForPrefixCheck = (path: string) => path.replace(/\/+$/, "") || "/"
const getBlockedPrefix = (path: string) =>
BLOCKED_PREFIXES.find((prefix) => path === prefix || path.startsWith(`${prefix}/`))
async function validateDirectory(
directory: string,
): Promise<{ valid: true; canonical: string } | { valid: false; error: string }> {
if (!directory || typeof directory !== "string") {
return { valid: false, error: "directory is required" }
}
const absolutePath = isAbsolute(directory) ? directory : resolve(directory)
const blockedBeforeRealpath = getBlockedPrefix(normalizeForPrefixCheck(absolutePath))
if (blockedBeforeRealpath) {
return {
valid: false,
error: `Cannot spawn server in system directory: ${blockedBeforeRealpath}`,
}
}
let canonical: string
try {
canonical = await realpath(absolutePath)
} catch {
return { valid: false, error: `Directory does not exist: ${directory}` }
}
const blockedCanonical = getBlockedPrefix(normalizeForPrefixCheck(canonical))
if (blockedCanonical) {
return {
valid: false,
error: `Cannot spawn server in system directory: ${blockedCanonical}`,
}
}
try {
const fileStat = await stat(canonical)
if (!fileStat.isDirectory()) {
return { valid: false, error: `Path is not a directory: ${directory}` }
}
} catch {
return { valid: false, error: `Cannot access directory: ${directory}` }
}
return { valid: true, canonical }
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/api/opencode/servers/spawn/route.ts` around lines 68 - 93,
The code currently checks BLOCKED_PREFIXES only against the pre-realpath
normalizedPath, allowing symlinks to resolve into blocked locations; update the
logic so after obtaining canonical via realpath() you re-run the blocked-prefix
check against a canonicalNormalized value (remove trailing slashes but preserve
"/" as a single slash) and return the same { valid: false, error: ... } if
canonical equals a prefix or startsWith `${prefix}/`; ensure the normalization
helper used for both normalizedPath and canonicalNormalized preserves root ("/")
instead of producing an empty string so the root prefix check still works.

- Add PUT/DELETE/PATCH/OPTIONS port validation tests (proxy branch coverage)
- Add reserved segment 'servers' test for each HTTP method
- Add Connection header with empty values test
- Add 204 response with headers test
- Add spawn route tests: waitForServer timeout, null pid, non-Error exception
- Increase spawn test timeout to 15s for waitForServer polling

Coverage improvements:
- route.ts branches: 66% β†’ 88%
- spawn/route.ts branches: 70% β†’ 85%

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick comments (1)
apps/web/src/app/api/opencode/servers/spawn/route.test.ts (1)

335-338: πŸ’€ Low value

Remove unnecessary mock restoration.

mockImplementationOnce automatically reverts to the default behavior after one call, and vi.clearAllMocks() (line 26) already resets all mocks between tests. The restoration here is redundant and potentially confusing since mockImplementation expects an implementation function, not a mock object reference.

For consistency with the other error tests (lines 345, 395), consider using mockReturnValueOnce instead, which doesn't require manual restoration.

♻️ Proposed refactor
 it("returns 500 on spawn failure", async () => {
   const { spawn } = await import("child_process")
-  const originalSpawn = spawn
   ;(spawn as ReturnType<typeof vi.fn>).mockImplementationOnce(() => {
     throw new Error("spawn failed")
   })

   global.fetch = vi.fn().mockResolvedValue({
     ok: true,
     json: vi.fn().mockResolvedValue([]),
   }) as unknown as typeof fetch

   const request = new NextRequest("http://localhost:3000/api/opencode/servers/spawn", {
     method: "POST",
     body: JSON.stringify({ directory: "/home/user/project" }),
   })

   const response = await POST(request)
   const data = await response.json()

   expect(response.status).toBe(500)
   expect(data.error).toBe("Failed to spawn server")
-  ;(spawn as ReturnType<typeof vi.fn>).mockImplementation(
-    originalSpawn as ReturnType<typeof vi.fn>,
-  )
 })
πŸ€– Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@apps/web/src/app/api/opencode/servers/spawn/route.test.ts` around lines 335 -
338, The test restores the spawn mock with mockImplementation but that's
unnecessary and wrong β€” replace the manual restoration with a one-shot mock that
reverts automatically: change the usage of
spawn.mockImplementationOnce(originalSpawn) to
spawn.mockReturnValueOnce(originalSpawn) (or use mockImplementationOnce with a
proper implementation function) and rely on vi.clearAllMocks() for cleanup;
update the test around the spawn mock (and any related assertions) to mirror the
other error tests that use mockReturnValueOnce to keep behavior consistent.
πŸ€– Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@apps/web/src/app/api/opencode/servers/spawn/route.test.ts`:
- Around line 335-338: The test restores the spawn mock with mockImplementation
but that's unnecessary and wrong β€” replace the manual restoration with a
one-shot mock that reverts automatically: change the usage of
spawn.mockImplementationOnce(originalSpawn) to
spawn.mockReturnValueOnce(originalSpawn) (or use mockImplementationOnce with a
proper implementation function) and rely on vi.clearAllMocks() for cleanup;
update the test around the spawn mock (and any related assertions) to mirror the
other error tests that use mockReturnValueOnce to keep behavior consistent.

ℹ️ Review info
βš™οΈ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: e15657ae-51ce-4510-a74c-6e767100c27b

πŸ“₯ Commits

Reviewing files that changed from the base of the PR and between 72b782b and e91a17b.

πŸ“’ Files selected for processing (2)
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts
  • apps/web/src/app/api/opencode/servers/spawn/route.test.ts
🚧 Files skipped from review as they are similar to previous changes (1)
  • apps/web/src/app/api/opencode/[port]/[[...path]]/route.test.ts

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

Labels

None yet

Projects

None yet

2 participants