chore: debug SDK WS classification and fix CLI binary resolution
Browse files- Add console.log for SDK WebSocket H5 classification debugging
- Bypass broken standalone dist/cli binary, delegate to sidecar/source
Co-Authored-By: Claude Big Pickle <noreply@anthropic.com>
- README.md +4 -0
- src/server/index.ts +5 -1
- src/server/services/conversationService.ts +30 -32
README.md
CHANGED
|
@@ -130,6 +130,10 @@ firefox http://localhost:8080
|
|
| 130 |
# cd desktop && bun run vite build
|
| 131 |
cd desktop && bun run tauri dev
|
| 132 |
# ai_friend api in 8889 so local build Omni model or use cloud service on 8889
|
|
|
|
|
|
|
|
|
|
|
|
|
| 133 |
```
|
| 134 |
|
| 135 |
|
|
|
|
| 130 |
# cd desktop && bun run vite build
|
| 131 |
cd desktop && bun run tauri dev
|
| 132 |
# ai_friend api in 8889 so local build Omni model or use cloud service on 8889
|
| 133 |
+
|
| 134 |
+
# test
|
| 135 |
+
HTTP_PROXY=http://127.0.0.1:8888 HTTPS_PROXY=http://127.0.0.1:8888 bun run tauri dev
|
| 136 |
+
mitmproxy -p 8888
|
| 137 |
```
|
| 138 |
|
| 139 |
|
src/server/index.ts
CHANGED
|
@@ -231,7 +231,11 @@ export function startServer(port = PORT, host = HOST) {
|
|
| 231 |
|
| 232 |
// Internal SDK WebSocket used by the spawned Claude CLI.
|
| 233 |
if (url.pathname.startsWith('/sdk/')) {
|
| 234 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
| 235 |
return h5AccessControlRejectedResponse()
|
| 236 |
}
|
| 237 |
|
|
|
|
| 231 |
|
| 232 |
// Internal SDK WebSocket used by the spawned Claude CLI.
|
| 233 |
if (url.pathname.startsWith('/sdk/')) {
|
| 234 |
+
const classification = classifyH5Request(req, url, h5RequestContext)
|
| 235 |
+
console.log(
|
| 236 |
+
`[SDK-WS] classifyH5Request=${classification}, clientAddress=${h5RequestContext.clientAddress}, origin=${req.headers.get('Origin')}, path=${url.pathname}`,
|
| 237 |
+
)
|
| 238 |
+
if (classification !== 'internal-sdk') {
|
| 239 |
return h5AccessControlRejectedResponse()
|
| 240 |
}
|
| 241 |
|
src/server/services/conversationService.ts
CHANGED
|
@@ -1103,47 +1103,45 @@ export class ConversationService {
|
|
| 1103 |
}
|
| 1104 |
|
| 1105 |
private resolveCliArgs(baseArgs: string[]): string[] {
|
| 1106 |
-
//
|
| 1107 |
-
//
|
| 1108 |
-
// the
|
| 1109 |
-
//
|
|
|
|
| 1110 |
//
|
| 1111 |
-
// When running inside the compiled sidecar, import.meta.dir resolves to
|
| 1112 |
-
// virtual bunfs path — use CLAUDE_APP_ROOT (set by the sidecar
|
| 1113 |
-
// to
|
| 1114 |
-
const appRoot = process.env.CLAUDE_APP_ROOT
|
| 1115 |
-
if (appRoot) {
|
| 1116 |
-
const standaloneCli = path.resolve(appRoot, '../../../../dist/cli')
|
| 1117 |
-
if (fs.existsSync(standaloneCli)) {
|
| 1118 |
-
return [standaloneCli, ...baseArgs]
|
| 1119 |
-
}
|
| 1120 |
-
}
|
| 1121 |
-
// Fallback for direct bun dev mode (outside the sidecar)
|
| 1122 |
-
const standaloneCli = path.resolve(import.meta.dir, '../../../dist/cli')
|
| 1123 |
-
if (fs.existsSync(standaloneCli)) {
|
| 1124 |
-
return [standaloneCli, ...baseArgs]
|
| 1125 |
-
}
|
| 1126 |
|
| 1127 |
const launcher = resolveClaudeCliLauncher({
|
| 1128 |
cliPath: process.env.CLAUDE_CLI_PATH,
|
| 1129 |
execPath: process.execPath,
|
| 1130 |
})
|
| 1131 |
|
| 1132 |
-
if (
|
| 1133 |
-
|
| 1134 |
-
return [
|
| 1135 |
-
process.execPath,
|
| 1136 |
-
'--preload',
|
| 1137 |
-
path.resolve(import.meta.dir, '../../../preload.ts'),
|
| 1138 |
-
path.resolve(import.meta.dir, '../../entrypoints/cli.tsx'),
|
| 1139 |
-
...baseArgs,
|
| 1140 |
-
]
|
| 1141 |
-
}
|
| 1142 |
-
// Try claude-haha from PATH (installed via npm/pip)
|
| 1143 |
-
return ['claude-haha', ...baseArgs]
|
| 1144 |
}
|
| 1145 |
|
| 1146 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1147 |
}
|
| 1148 |
|
| 1149 |
private clearStaleLock(sessionId: string): boolean {
|
|
|
|
| 1103 |
}
|
| 1104 |
|
| 1105 |
private resolveCliArgs(baseArgs: string[]): string[] {
|
| 1106 |
+
// The standalone dist/cli binary (April 18, pre-fork) is known to be
|
| 1107 |
+
// broken for --print / SDK mode — it parses --sdk-url but never
|
| 1108 |
+
// establishes the WebSocket connection and produces no stream-json
|
| 1109 |
+
// output. Bypass it unconditionally and delegate to the sidecar or
|
| 1110 |
+
// source-based launcher instead.
|
| 1111 |
//
|
| 1112 |
+
// When running inside the compiled sidecar, import.meta.dir resolves to
|
| 1113 |
+
// a virtual bunfs path — use CLAUDE_APP_ROOT (set by the sidecar
|
| 1114 |
+
// launcher) to find the repo root for source-based fallback.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1115 |
|
| 1116 |
const launcher = resolveClaudeCliLauncher({
|
| 1117 |
cliPath: process.env.CLAUDE_CLI_PATH,
|
| 1118 |
execPath: process.execPath,
|
| 1119 |
})
|
| 1120 |
|
| 1121 |
+
if (launcher) {
|
| 1122 |
+
return buildClaudeCliArgs(launcher, baseArgs, process.env.CLAUDE_APP_ROOT)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1123 |
}
|
| 1124 |
|
| 1125 |
+
// No launcher detected — try running from source via bun.
|
| 1126 |
+
const repoRoot = process.env.CLAUDE_APP_ROOT
|
| 1127 |
+
? path.resolve(process.env.CLAUDE_APP_ROOT, '../../../..')
|
| 1128 |
+
: path.resolve(import.meta.dir, '../../..')
|
| 1129 |
+
const sourceEntry = path.resolve(repoRoot, 'src/entrypoints/cli.tsx')
|
| 1130 |
+
if (fs.existsSync(sourceEntry)) {
|
| 1131 |
+
return [process.execPath, sourceEntry, ...baseArgs]
|
| 1132 |
+
}
|
| 1133 |
+
|
| 1134 |
+
if (process.platform === 'win32') {
|
| 1135 |
+
return [
|
| 1136 |
+
process.execPath,
|
| 1137 |
+
'--preload',
|
| 1138 |
+
path.resolve(import.meta.dir, '../../../preload.ts'),
|
| 1139 |
+
path.resolve(import.meta.dir, '../../entrypoints/cli.tsx'),
|
| 1140 |
+
...baseArgs,
|
| 1141 |
+
]
|
| 1142 |
+
}
|
| 1143 |
+
// Try claude-haha from PATH (installed via npm/pip)
|
| 1144 |
+
return ['claude-haha', ...baseArgs]
|
| 1145 |
}
|
| 1146 |
|
| 1147 |
private clearStaleLock(sessionId: string): boolean {
|