feat: enable Remote Control (BRIDGE_MODE) with stub completions#60
feat: enable Remote Control (BRIDGE_MODE) with stub completions#60amDosion wants to merge 5 commits intoclaude-code-best:mainfrom
Conversation
- Add BRIDGE_MODE to DEFAULT_FEATURES in dev.ts - Implement peerSessions.ts: cross-session messaging via bridge API - Implement webhookSanitizer.ts: redact secrets from webhook payloads - Replace any stubs in controlTypes.ts with Zod schema-inferred types - Fix tengu_bridge_system_init default to true for app "active" status Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Note Reviews pausedIt 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 Use the following commands to manage reviews:
Use the checkboxes below for quick actions:
📝 WalkthroughWalkthroughImplements real bridge peer messaging and inbound webhook sanitization, tightens SDK control protocol types to schema-derived TypeScript, adds Changes
Sequence DiagramsequenceDiagram
participant App as Calling Code
participant PostFunc as postInterClaudeMessage()
participant Bridge as Bridge Handle
participant HTTP as axios
participant Ingress as Ingress Endpoint
App->>PostFunc: postInterClaudeMessage(target, message)
PostFunc->>Bridge: fetch handle (get sender, ingress URL, token)
alt no handle / missing token / empty target
PostFunc-->>App: { ok: false, error }
else
PostFunc->>PostFunc: validate/convert target id
PostFunc->>HTTP: POST ${ingressUrl}/v1/sessions/<encodedTarget>/messages (body, headers, timeout)
HTTP->>Ingress: deliver peer_message
Ingress-->>HTTP: response (200/204 or non-5xx)
alt 200/204
PostFunc-->>App: { ok: true }
else
PostFunc-->>App: { ok: false, error }
end
end
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
⚔️ Resolve merge conflicts
Comment |
There was a problem hiding this comment.
Actionable comments posted: 2
🧹 Nitpick comments (2)
src/bridge/peerSessions.ts (2)
1-5: Consider usingsrc/path alias for imports.As per coding guidelines, imports should use the
src/path alias via tsconfig mapping instead of relative paths. However, this appears to be a common pattern in this codebase for same-package imports.🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/bridge/peerSessions.ts` around lines 1 - 5, The imports at the top of peerSessions.ts use relative paths (axios and local modules like logForDebugging, errorMessage, getReplBridgeHandle, toCompatSessionId); update these to use the project's src/ path alias (e.g., import { logForDebugging } from 'src/utils/debug' etc.) so TS path mapping is respected, keeping the same named symbols (logForDebugging, errorMessage, getReplBridgeHandle, toCompatSessionId) and ensuring imports resolve under tsconfig paths.
18-21: Consider using a discriminated union for better type safety.The return type
{ ok: boolean; error?: string }permits invalid states (e.g.,{ ok: true, error: '...' }). A discriminated union ensures callers handle both cases correctly.🔧 Suggested type refinement
export async function postInterClaudeMessage( target: string, message: string, -): Promise<{ ok: boolean; error?: string }> { +): Promise<{ ok: true } | { ok: false; error: string }> {🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/bridge/peerSessions.ts` around lines 18 - 21, The return type of postInterClaudeMessage allows invalid states like { ok: true, error: '...' }; change its signature to a discriminated union (e.g., Promise<{ ok: true } | { ok: false; error: string }>) and update all return sites inside postInterClaudeMessage to return exactly one of those shapes (success returns { ok: true } and all failure paths return { ok: false, error: <string> }). Also export or define a named type (e.g., PostInterClaudeResult) if used elsewhere to keep callers type-safe and update any callers to handle both union branches.
🤖 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/bridge/webhookSanitizer.ts`:
- Line 8: The sanitizer currently "fails open" by returning the original payload
on error; change sanitizeWebhook (and the same logic around lines 53-55) so that
it never returns the raw input when an internal error occurs — instead catch any
exception synchronously and return a fully redacted/placeholder payload (or an
empty safe structure) that preserves the expected return type, and optionally
log the error; ensure sanitizeWebhook remains synchronous and never throws, and
update all paths that currently return the original content on error to return
the safe redacted value instead.
- Around line 40-50: The code currently truncates the payload (sanitized =
sanitized.slice(...)) before applying SECRET_PATTERNS, which can break regex
matches that span the truncation boundary; run the redaction loop over
SECRET_PATTERNS on the full sanitized input first (ensure pattern.lastIndex = 0
before each replace), then apply the MAX_CONTENT_LENGTH truncation step
afterwards (optionally reset lastIndex and run one final pass if you want to be
extra safe). Update the order around the variables sanitized, SECRET_PATTERNS,
and MAX_CONTENT_LENGTH in webhookSanitizer.ts accordingly.
---
Nitpick comments:
In `@src/bridge/peerSessions.ts`:
- Around line 1-5: The imports at the top of peerSessions.ts use relative paths
(axios and local modules like logForDebugging, errorMessage,
getReplBridgeHandle, toCompatSessionId); update these to use the project's src/
path alias (e.g., import { logForDebugging } from 'src/utils/debug' etc.) so TS
path mapping is respected, keeping the same named symbols (logForDebugging,
errorMessage, getReplBridgeHandle, toCompatSessionId) and ensuring imports
resolve under tsconfig paths.
- Around line 18-21: The return type of postInterClaudeMessage allows invalid
states like { ok: true, error: '...' }; change its signature to a discriminated
union (e.g., Promise<{ ok: true } | { ok: false; error: string }>) and update
all return sites inside postInterClaudeMessage to return exactly one of those
shapes (success returns { ok: true } and all failure paths return { ok: false,
error: <string> }). Also export or define a named type (e.g.,
PostInterClaudeResult) if used elsewhere to keep callers type-safe and update
any callers to handle both union branches.
🪄 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: e0a1f7a5-70c7-4be8-a7f9-2662dc84fec8
📒 Files selected for processing (5)
scripts/dev.tssrc/bridge/peerSessions.tssrc/bridge/webhookSanitizer.tssrc/entrypoints/sdk/controlTypes.tssrc/hooks/useReplBridge.tsx
- webhookSanitizer: redact before truncate to avoid split secrets at boundary - webhookSanitizer: return safe placeholder on error instead of raw content - peerSessions: use discriminated union return type for type safety Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/bridge/peerSessions.ts (1)
1-5: Usesrc/path alias instead of relative imports.The imports use relative paths (
../utils/...,./...) instead of thesrc/path alias configured in tsconfig.♻️ Suggested refactor
import axios from 'axios' -import { logForDebugging } from '../utils/debug.js' -import { errorMessage } from '../utils/errors.js' -import { getReplBridgeHandle } from './replBridgeHandle.js' -import { toCompatSessionId } from './sessionIdCompat.js' +import { logForDebugging } from 'src/utils/debug.js' +import { errorMessage } from 'src/utils/errors.js' +import { getReplBridgeHandle } from 'src/bridge/replBridgeHandle.js' +import { toCompatSessionId } from 'src/bridge/sessionIdCompat.js'As per coding guidelines: "Import
src/path alias via tsconfig mapping instead of relative paths in imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/bridge/peerSessions.ts` around lines 1 - 5, Update the imports in peerSessions.ts to use the tsconfig "src/" path alias instead of relative paths: replace "../utils/debug.js" import of logForDebugging, "../utils/errors.js" import of errorMessage, "./replBridgeHandle.js" import of getReplBridgeHandle, and "./sessionIdCompat.js" import of toCompatSessionId with equivalent "src/..." aliased imports; ensure the module specifiers match the tsconfig paths (and keep the default axios import unchanged) so TypeScript path mapping resolves correctly and local build/IDE tooling recognizes the alias.
🤖 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/bridge/peerSessions.ts`:
- Around line 38-53: The POST to the peer message endpoint in
postInterClaudeMessage is missing an Authorization header because
ReplBridgeHandle doesn't expose the access token; fix by either adding
getAccessToken to the ReplBridgeHandle interface and using it inside
postInterClaudeMessage or by changing postInterClaudeMessage signature to accept
an accessToken parameter, then include "Authorization: Bearer <token>" in the
axios headers alongside Content-Type and anthropic-version; mirror how other
bridge calls (see remoteBridgeCore.ts / codeSessionApi.ts / bridgeApi.ts) attach
the Bearer token so this request is authenticated.
---
Nitpick comments:
In `@src/bridge/peerSessions.ts`:
- Around line 1-5: Update the imports in peerSessions.ts to use the tsconfig
"src/" path alias instead of relative paths: replace "../utils/debug.js" import
of logForDebugging, "../utils/errors.js" import of errorMessage,
"./replBridgeHandle.js" import of getReplBridgeHandle, and
"./sessionIdCompat.js" import of toCompatSessionId with equivalent "src/..."
aliased imports; ensure the module specifiers match the tsconfig paths (and keep
the default axios import unchanged) so TypeScript path mapping resolves
correctly and local build/IDE tooling recognizes the alias.
🪄 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: cff0d28c-d025-4836-b89b-c094fff9242f
📒 Files selected for processing (2)
src/bridge/peerSessions.tssrc/bridge/webhookSanitizer.ts
getBridgeAccessToken() provides the OAuth Bearer token, matching the auth pattern used by bridgeApi.ts and codeSessionApi.ts. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/bridge/peerSessions.ts (1)
2-6: Usesrc/path aliases instead of relative importsThese imports should use the configured
src/alias for consistency with repo standards.Suggested fix
-import { logForDebugging } from '../utils/debug.js' -import { errorMessage } from '../utils/errors.js' -import { getBridgeAccessToken } from './bridgeConfig.js' -import { getReplBridgeHandle } from './replBridgeHandle.js' -import { toCompatSessionId } from './sessionIdCompat.js' +import { logForDebugging } from 'src/utils/debug.js' +import { errorMessage } from 'src/utils/errors.js' +import { getBridgeAccessToken } from 'src/bridge/bridgeConfig.js' +import { getReplBridgeHandle } from 'src/bridge/replBridgeHandle.js' +import { toCompatSessionId } from 'src/bridge/sessionIdCompat.js'As per coding guidelines, "Import
src/path alias via tsconfig mapping instead of relative paths in imports".🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@src/bridge/peerSessions.ts` around lines 2 - 6, Replace the relative imports at the top of peerSessions.ts with the project alias imports using the src/ path mapping: update import statements that reference logForDebugging, errorMessage, getBridgeAccessToken, getReplBridgeHandle, and toCompatSessionId so they import from "src/utils/debug", "src/utils/errors", "src/bridge/bridgeConfig", "src/bridge/replBridgeHandle", and "src/bridge/sessionIdCompat" respectively (preserving the same exported identifiers) to align with the tsconfig path alias convention.
🤖 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/bridge/peerSessions.ts`:
- Around line 29-43: The URL path is built with compatTarget unescaped which can
break routing for reserved chars or slashes; update the code that computes
compatTarget (use the existing toCompatSessionId(target)) and then normalize and
percent-encode it before interpolating into url (e.g., trim/normalize any
leading/trailing slashes and apply an encodeURIComponent-style encoding) so the
constructed url =
`${handle.sessionIngressUrl}/v1/sessions/${encodedCompatTarget}/messages` is
safe; ensure you reference toCompatSessionId, compatTarget (or its encoded
variant) and handle.sessionIngressUrl when making the change.
---
Nitpick comments:
In `@src/bridge/peerSessions.ts`:
- Around line 2-6: Replace the relative imports at the top of peerSessions.ts
with the project alias imports using the src/ path mapping: update import
statements that reference logForDebugging, errorMessage, getBridgeAccessToken,
getReplBridgeHandle, and toCompatSessionId so they import from
"src/utils/debug", "src/utils/errors", "src/bridge/bridgeConfig",
"src/bridge/replBridgeHandle", and "src/bridge/sessionIdCompat" respectively
(preserving the same exported identifiers) to align with the tsconfig path alias
convention.
🪄 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: 905ffc73-8b03-4f9d-ac5d-9cf7df50215b
📒 Files selected for processing (1)
src/bridge/peerSessions.ts
- Trim and normalize target before use - Validate with validateBridgeId allowlist (same as bridgeApi.ts) - URL-encode compatTarget to prevent path traversal/injection Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
麻烦补充一下变更到 DEV-LOG.md 文件, 然后需要测试的截图哈 @amDosion |
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@DEV-LOG.md`:
- Line 33: The markdown references a missing image
"docs/images/remote-control-mobile.png" in DEV-LOG.md; fix by either adding the
requested screenshot file named remote-control-mobile.png into the docs/images/
directory (use the original "测试的截图" image) or remove/replace the markdown image
line `` from
DEV-LOG.md so the broken reference is eliminated.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
| - App 端(claude.ai/code)显示 "Remote Control active" | ||
| - 手机端(Claude iOS app)通过 URL 连接,双向消息正常 | ||
|
|
||
|  |
There was a problem hiding this comment.
🧩 Analysis chain
🏁 Script executed:
#!/bin/bash
# Description: Verify the referenced image exists and check for related test screenshots
# Check if the referenced image exists
fd -t f "remote-control-mobile.png" docs/images/
# List all images in docs/images to see what test screenshots are available
echo "=== All images in docs/images/ ==="
fd -t f . docs/images/ --exec ls -lh {}Repository: claude-code-best/claude-code
Length of output: 839
Add the missing screenshot or remove the broken image reference.
The documentation at line 33 references docs/images/remote-control-mobile.png, but this file does not exist in the repository. Either add the screenshot to docs/images/ as requested in the original review ("测试的截图"), or remove the broken image reference from the documentation.
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.
In `@DEV-LOG.md` at line 33, The markdown references a missing image
"docs/images/remote-control-mobile.png" in DEV-LOG.md; fix by either adding the
requested screenshot file named remote-control-mobile.png into the docs/images/
directory (use the original "测试的截图" image) or remove/replace the markdown image
line `` from
DEV-LOG.md so the broken reference is eliminated.


Summary
Enable the Remote Control feature (
BRIDGE_MODE) by completing stub implementations, fixing type definitions, and correcting feature gate defaults.Remote Control registers the local CLI as a bridge environment, generates a shareable URL (
https://claude.ai/code/session_xxx), and allows real-time two-way communication from browser, mobile, or other devices.Changes
scripts/dev.tsBRIDGE_MODEtoDEFAULT_FEATURESsrc/bridge/peerSessions.tssrc/bridge/webhookSanitizer.tssrc/entrypoints/sdk/controlTypes.tsanystubs →z.infertypes from existing Zod schemassrc/hooks/useReplBridge.tsxtengu_bridge_system_initdefaultfalse→trueDEV-LOG.mdSecurity
peerSessions.ts — Three-layer target validation
target.trim()— normalize inputvalidateBridgeId()— allowlist/^[a-zA-Z0-9_-]+$/(same pattern asbridgeApi.ts)encodeURIComponent()— URL encode before path interpolationpeerSessions.ts — Authentication
getBridgeAccessToken()for OAuth Bearer token (matchesbridgeApi.ts/codeSessionApi.tspattern)webhookSanitizer.ts — Fail-closed design
[webhook content redacted due to sanitization error](never raw content)Key Decisions
tengu_bridge_system_initdefault change: Anthropic pushestruevia GrowthBook to subscribers, but our build doesn't receive the push. Without this, app stays stuck on "Remote Control connecting..." instead of showing "active"controlTypes.ts: Schemas already exist incontrolSchemas.ts/coreSchemas.ts— types now usez.infer<ReturnType<typeof XxxSchema>>instead ofanyCommits
74e51e7feat: enable Remote Control (BRIDGE_MODE) with stub completions1d38eaefix: address CodeRabbit review findings8645d37fix: add Authorization header to peer message requestse784f23fix: validate and encode target sessionId in peer messages67caa5ddocs: add Remote Control (BRIDGE_MODE) entry to DEV-LOGTest plan
bun test src/bridge/__tests__/— 37 pass, 0 fail/remote-controlcommand visible and enabled inbun run dev🤖 Generated with Claude Code