diff --git a/CLAUDE.md b/CLAUDE.md index d07ddccf4..b78af9a98 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -55,6 +55,8 @@ bun run health # Check unused exports bun run check:unused +bun run typecheck + # Remote Control Server bun run rcs diff --git a/build.ts b/build.ts index 857aefe8e..11b859330 100644 --- a/build.ts +++ b/build.ts @@ -88,8 +88,27 @@ for (const file of files) { } } +// Also patch unguarded globalThis.Bun destructuring from third-party deps +// (e.g. @anthropic-ai/sandbox-runtime) so Node.js doesn't crash at import time. +let bunPatched = 0 +const BUN_DESTRUCTURE = /var \{([^}]+)\} = globalThis\.Bun;?/g +const BUN_DESTRUCTURE_SAFE = 'var {$1} = typeof globalThis.Bun !== "undefined" ? globalThis.Bun : {};' +for (const file of files) { + if (!file.endsWith('.js')) continue + const filePath = join(outdir, file) + const content = await readFile(filePath, 'utf-8') + if (BUN_DESTRUCTURE.test(content)) { + await writeFile( + filePath, + content.replace(BUN_DESTRUCTURE, BUN_DESTRUCTURE_SAFE), + ) + bunPatched++ + } +} +BUN_DESTRUCTURE.lastIndex = 0 + console.log( - `Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for Node.js compat)`, + `Bundled ${result.outputs.length} files to ${outdir}/ (patched ${patched} for import.meta.require, ${bunPatched} for Bun destructure)`, ) // Step 4: Copy native .node addon files (audio-capture) @@ -119,46 +138,7 @@ const cliNode = join(outdir, 'cli-node.js') await writeFile(cliBun, '#!/usr/bin/env bun\nimport "./cli.js"\n') -// Node.js entry needs a Bun API polyfill because Bun.build({ target: 'bun' }) -// emits globalThis.Bun references (e.g. Bun.$ shell tag in computer-use-input, -// Bun.which in chunk-ys6smqg9) that crash at import time under plain Node.js. -const NODE_BUN_POLYFILL = `#!/usr/bin/env node -// Bun API polyfill for Node.js runtime -if (typeof globalThis.Bun === "undefined") { - const { execFileSync } = await import("child_process"); - const { resolve, delimiter } = await import("path"); - const { accessSync, constants: { X_OK } } = await import("fs"); - function which(bin) { - const isWin = process.platform === "win32"; - const pathExt = isWin ? (process.env.PATHEXT || ".EXE").split(";") : [""]; - for (const dir of (process.env.PATH || "").split(delimiter)) { - for (const ext of pathExt) { - const candidate = resolve(dir, bin + ext); - try { accessSync(candidate, X_OK); return candidate; } catch {} - } - } - return null; - } - // Bun.$ is the shell template tag (e.g. $\`osascript ...\`). Only used by - // computer-use-input/darwin — stub it so the top-level destructuring - // \`var { $ } = globalThis.Bun\` doesn't crash. - function $(parts, ...args) { - throw new Error("Bun.$ shell API is not available in Node.js. Use Bun runtime for this feature."); - } - function hash(data, seed) { - let h = ((seed || 0) ^ 0x811c9dc5) >>> 0; - for (let i = 0; i < data.length; i++) { - h ^= data.charCodeAt(i); - h = Math.imul(h, 0x01000193) >>> 0; - } - return h; - } - globalThis.Bun = { which, $, hash }; -} -import "./cli.js" -` -await writeFile(cliNode, NODE_BUN_POLYFILL) -// NOTE: when new Bun-specific globals appear in bundled output, add them here. +await writeFile(cliNode, '#!/usr/bin/env node\nimport "./cli.js"\n') // Make both executable const { chmodSync } = await import('fs') diff --git a/bun.lock b/bun.lock index eaa1a6b9f..f6621ad24 100644 --- a/bun.lock +++ b/bun.lock @@ -58,10 +58,11 @@ "@sentry/node": "^10.47.0", "@smithy/core": "^3.23.13", "@smithy/node-http-handler": "^4.5.1", - "@types/bun": "^1.3.11", + "@types/bun": "^1.3.12", "@types/cacache": "^20.0.1", "@types/he": "^1.2.3", "@types/lodash-es": "^4.17.12", + "@types/node": "^25.6.0", "@types/picomatch": "^4.0.3", "@types/plist": "^3.0.5", "@types/proper-lockfile": "^4.1.4", diff --git a/package.json b/package.json index f5d6b1d4d..8e147791c 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "claude-code-best", - "version": "1.3.6", + "version": "1.3.7", "description": "Reverse-engineered Anthropic Claude Code CLI — interactive AI coding assistant in the terminal", "type": "module", "author": "claude-code-best ", @@ -52,6 +52,7 @@ "health": "bun run scripts/health-check.ts", "postinstall": "node scripts/postinstall.cjs && node scripts/setup-chrome-mcp.mjs", "docs:dev": "npx mintlify dev", + "typecheck": "tsc --noEmit", "rcs": "bun run scripts/rcs.ts" }, "dependencies": { @@ -59,10 +60,6 @@ "@claude-code-best/mcp-chrome-bridge": "^2.0.7" }, "devDependencies": { - "@types/he": "^1.2.3", - "@langfuse/otel": "^5.1.0", - "@langfuse/tracing": "^5.1.0", - "@types/lodash-es": "^4.17.12", "@alcalzone/ansi-tokenize": "^0.3.0", "@ant/claude-for-chrome-mcp": "workspace:*", "@ant/computer-use-input": "workspace:*", @@ -76,9 +73,6 @@ "@anthropic-ai/sdk": "^0.80.0", "@anthropic-ai/vertex-sdk": "^0.14.4", "@anthropic/ink": "workspace:*", - "@claude-code-best/builtin-tools": "workspace:*", - "@claude-code-best/agent-tools": "workspace:*", - "@claude-code-best/mcp-client": "workspace:*", "@aws-sdk/client-bedrock": "^3.1020.0", "@aws-sdk/client-bedrock-runtime": "^3.1020.0", "@aws-sdk/client-sts": "^3.1020.0", @@ -86,8 +80,13 @@ "@aws-sdk/credential-providers": "^3.1020.0", "@azure/identity": "^4.13.1", "@biomejs/biome": "^2.4.10", + "@claude-code-best/agent-tools": "workspace:*", + "@claude-code-best/builtin-tools": "workspace:*", + "@claude-code-best/mcp-client": "workspace:*", "@commander-js/extra-typings": "^14.0.0", "@growthbook/growthbook": "^1.6.5", + "@langfuse/otel": "^5.1.0", + "@langfuse/tracing": "^5.1.0", "@modelcontextprotocol/sdk": "^1.29.0", "@opentelemetry/api": "^1.9.1", "@opentelemetry/api-logs": "^0.214.0", @@ -110,8 +109,11 @@ "@sentry/node": "^10.47.0", "@smithy/core": "^3.23.13", "@smithy/node-http-handler": "^4.5.1", - "@types/bun": "^1.3.11", + "@types/bun": "^1.3.12", "@types/cacache": "^20.0.1", + "@types/he": "^1.2.3", + "@types/lodash-es": "^4.17.12", + "@types/node": "^25.6.0", "@types/picomatch": "^4.0.3", "@types/plist": "^3.0.5", "@types/proper-lockfile": "^4.1.4", diff --git a/packages/@ant/claude-for-chrome-mcp/tsconfig.json b/packages/@ant/claude-for-chrome-mcp/tsconfig.json new file mode 100644 index 000000000..67fc2cf86 --- /dev/null +++ b/packages/@ant/claude-for-chrome-mcp/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/@ant/computer-use-input/src/backends/darwin.ts b/packages/@ant/computer-use-input/src/backends/darwin.ts index 4f9569d2d..37af38cff 100644 --- a/packages/@ant/computer-use-input/src/backends/darwin.ts +++ b/packages/@ant/computer-use-input/src/backends/darwin.ts @@ -5,9 +5,12 @@ * mouse and keyboard via CoreGraphics events and System Events. */ -import { $ } from 'bun' +import { execFile, execFileSync } from 'child_process' +import { promisify } from 'util' import type { FrontmostAppInfo, InputBackend } from '../types.js' +const execFileAsync = promisify(execFile) + const KEY_MAP: Record = { return: 36, enter: 36, tab: 48, space: 49, delete: 51, backspace: 51, escape: 53, esc: 53, @@ -25,13 +28,17 @@ const MODIFIER_MAP: Record = { } async function osascript(script: string): Promise { - const result = await $`osascript -e ${script}`.quiet().nothrow().text() - return result.trim() + const { stdout } = await execFileAsync('osascript', ['-e', script], { + encoding: 'utf-8', + }) + return stdout.trim() } async function jxa(script: string): Promise { - const result = await $`osascript -l JavaScript -e ${script}`.quiet().nothrow().text() - return result.trim() + const { stdout } = await execFileAsync('osascript', ['-l', 'JavaScript', '-e', script], { + encoding: 'utf-8', + }) + return stdout.trim() } function buildMouseJxa(eventType: string, x: number, y: number, btn: number, clickState?: number): string { @@ -115,19 +122,14 @@ export const typeText: InputBackend['typeText'] = async (text) => { export const getFrontmostAppInfo: InputBackend['getFrontmostAppInfo'] = () => { try { - const result = Bun.spawnSync({ - cmd: ['osascript', '-e', ` - tell application "System Events" - set frontApp to first application process whose frontmost is true - set appName to name of frontApp - set bundleId to bundle identifier of frontApp - return bundleId & "|" & appName - end tell - `], - stdout: 'pipe', - stderr: 'pipe', - }) - const output = new TextDecoder().decode(result.stdout).trim() + const output = execFileSync('osascript', ['-e', ` + tell application "System Events" + set frontApp to first application process whose frontmost is true + set appName to name of frontApp + set bundleId to bundle identifier of frontApp + return bundleId & "|" & appName + end tell + `], { encoding: 'utf-8', stdio: ['pipe', 'pipe', 'ignore'] }).trim() if (!output || !output.includes('|')) return null const [bundleId, appName] = output.split('|', 2) return { bundleId: bundleId!, appName: appName! } diff --git a/packages/@ant/computer-use-input/tsconfig.json b/packages/@ant/computer-use-input/tsconfig.json new file mode 100644 index 000000000..67fc2cf86 --- /dev/null +++ b/packages/@ant/computer-use-input/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/@ant/computer-use-mcp/tsconfig.json b/packages/@ant/computer-use-mcp/tsconfig.json new file mode 100644 index 000000000..67fc2cf86 --- /dev/null +++ b/packages/@ant/computer-use-mcp/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/@ant/computer-use-swift/src/backends/darwin.ts b/packages/@ant/computer-use-swift/src/backends/darwin.ts index 4bf6d5fa9..f0fad85af 100644 --- a/packages/@ant/computer-use-swift/src/backends/darwin.ts +++ b/packages/@ant/computer-use-swift/src/backends/darwin.ts @@ -274,4 +274,9 @@ export const screenshot: ScreenshotAPI = { if (displayId !== undefined) args.push('-D', String(displayId)) return captureScreenToBase64(args) }, + + captureWindowTarget(_titleOrHwnd: string | number): ScreenshotResult | null { + // Window capture not supported on macOS via this backend + return null + }, } diff --git a/packages/@ant/computer-use-swift/src/backends/linux.ts b/packages/@ant/computer-use-swift/src/backends/linux.ts index 692575433..da63efea9 100644 --- a/packages/@ant/computer-use-swift/src/backends/linux.ts +++ b/packages/@ant/computer-use-swift/src/backends/linux.ts @@ -275,4 +275,9 @@ export const screenshot: ScreenshotAPI = { return { base64: '', width: 0, height: 0 } } }, + + captureWindowTarget(_titleOrHwnd: string | number): ScreenshotResult | null { + // Window capture not supported on Linux via this backend + return null + }, } diff --git a/packages/@ant/computer-use-swift/src/types.ts b/packages/@ant/computer-use-swift/src/types.ts index 767a0fcde..67b3cba11 100644 --- a/packages/@ant/computer-use-swift/src/types.ts +++ b/packages/@ant/computer-use-swift/src/types.ts @@ -76,6 +76,7 @@ export interface ScreenshotAPI { x: number, y: number, w: number, h: number, outW: number, outH: number, quality: number, displayId?: number, ): Promise + captureWindowTarget(titleOrHwnd: string | number): ScreenshotResult | null } export interface SwiftBackend { diff --git a/packages/@ant/computer-use-swift/tsconfig.json b/packages/@ant/computer-use-swift/tsconfig.json new file mode 100644 index 000000000..5621e5882 --- /dev/null +++ b/packages/@ant/computer-use-swift/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/@ant/ink/tsconfig.json b/packages/@ant/ink/tsconfig.json new file mode 100644 index 000000000..f95464d03 --- /dev/null +++ b/packages/@ant/ink/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../../tsconfig.base.json", + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/agent-tools/src/__tests__/compat.test.ts b/packages/agent-tools/src/__tests__/compat.test.ts index 4ffd4a6e7..752043f0f 100644 --- a/packages/agent-tools/src/__tests__/compat.test.ts +++ b/packages/agent-tools/src/__tests__/compat.test.ts @@ -1,6 +1,6 @@ import { describe, expect, test } from 'bun:test' import type { CoreTool, Tool, Tools, AnyObject, ToolResult, ValidationResult, PermissionResult } from '@claude-code-best/agent-tools' -import type { Tool as HostTool } from '../../src/Tool.js' +import type { Tool as HostTool } from '../../../../src/Tool.js' describe('agent-tools compatibility', () => { test('CoreTool structural compatibility with host Tool', () => { @@ -27,7 +27,7 @@ describe('agent-tools compatibility', () => { } // This assignment should work if HostTool structurally extends CoreTool - const coreTool: CoreTool = mockHostTool as CoreTool + const coreTool: CoreTool = mockHostTool as unknown as CoreTool expect(coreTool.name).toBe('test') expect(coreTool.isEnabled()).toBe(true) }) diff --git a/packages/agent-tools/tsconfig.json b/packages/agent-tools/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/agent-tools/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/audio-capture-napi/tsconfig.json b/packages/audio-capture-napi/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/audio-capture-napi/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/builtin-tools/tsconfig.json b/packages/builtin-tools/tsconfig.json new file mode 100644 index 000000000..0908dc332 --- /dev/null +++ b/packages/builtin-tools/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.json", + "include": ["src/**/*.ts", "src/**/*.tsx"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/color-diff-napi/src/__tests__/color-diff.test.ts b/packages/color-diff-napi/src/__tests__/color-diff.test.ts index 0e38a3c25..2c95cc8b4 100644 --- a/packages/color-diff-napi/src/__tests__/color-diff.test.ts +++ b/packages/color-diff-napi/src/__tests__/color-diff.test.ts @@ -72,18 +72,18 @@ describe("detectColorMode", () => { describe("detectLanguage", () => { test("detects language from file extension", () => { - expect(detectLanguage("index.ts")).toBe("ts"); - expect(detectLanguage("main.py")).toBe("py"); - expect(detectLanguage("style.css")).toBe("css"); + expect(detectLanguage("index.ts", null)).toBe("ts"); + expect(detectLanguage("main.py", null)).toBe("py"); + expect(detectLanguage("style.css", null)).toBe("css"); }); test("detects language from known filenames", () => { - expect(detectLanguage("Makefile")).toBe("makefile"); - expect(detectLanguage("Dockerfile")).toBe("dockerfile"); + expect(detectLanguage("Makefile", null)).toBe("makefile"); + expect(detectLanguage("Dockerfile", null)).toBe("dockerfile"); }); test("returns null for unknown extensions", () => { - expect(detectLanguage("file.xyz123")).toBeNull(); + expect(detectLanguage("file.xyz123", null)).toBeNull(); }); }); diff --git a/packages/color-diff-napi/tsconfig.json b/packages/color-diff-napi/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/color-diff-napi/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/image-processor-napi/tsconfig.json b/packages/image-processor-napi/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/image-processor-napi/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/mcp-client/src/__tests__/InProcessTransport.test.ts b/packages/mcp-client/src/__tests__/InProcessTransport.test.ts index f9ee89a4e..37c986d67 100644 --- a/packages/mcp-client/src/__tests__/InProcessTransport.test.ts +++ b/packages/mcp-client/src/__tests__/InProcessTransport.test.ts @@ -38,7 +38,7 @@ describe('InProcessTransport', () => { let received: JSONRPCMessage | null = null client.onmessage = (msg) => { received = msg } - await server.send({ jsonrpc: '2.0', result: 42, id: 1 }) + await server.send({ jsonrpc: '2.0', result: 42, id: 1 } as any) await new Promise(resolve => setTimeout(resolve, 10)) diff --git a/packages/mcp-client/src/__tests__/discovery.test.ts b/packages/mcp-client/src/__tests__/discovery.test.ts index a43d3472f..642623e81 100644 --- a/packages/mcp-client/src/__tests__/discovery.test.ts +++ b/packages/mcp-client/src/__tests__/discovery.test.ts @@ -57,9 +57,9 @@ describe('discoverTools', () => { expect(tool.name).toBe('mcp__my-server__search') expect(tool.mcpInfo).toEqual({ serverName: 'my-server', toolName: 'search' }) expect(tool.isMcp).toBe(true) - expect(tool.isReadOnly()).toBe(true) - expect(tool.userFacingName()).toBe('Search Items') - expect(await tool.description()).toBe('Search for items') + expect(tool.isReadOnly({} as any)).toBe(true) + expect(tool.userFacingName(undefined)).toBe('Search Items') + expect(await tool.description({} as any, { isNonInteractiveSession: false, toolPermissionContext: {}, tools: [] })).toBe('Search for items') }) test('respects skipPrefix option', async () => { diff --git a/packages/mcp-client/src/__tests__/manager.test.ts b/packages/mcp-client/src/__tests__/manager.test.ts index f067ffa2e..f929cb922 100644 --- a/packages/mcp-client/src/__tests__/manager.test.ts +++ b/packages/mcp-client/src/__tests__/manager.test.ts @@ -65,7 +65,7 @@ describe('createMcpManager', () => { const result = await manager.connect('test-server', { command: 'npx', args: [] }) expect(result.type).toBe('connected') - expect(connectedEvent).toBe('test-server') + expect(connectedEvent as unknown as string).toBe('test-server') }) test('disconnect calls cleanup and emits disconnected', async () => { diff --git a/packages/mcp-client/tsconfig.json b/packages/mcp-client/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/mcp-client/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/modifiers-napi/tsconfig.json b/packages/modifiers-napi/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/modifiers-napi/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/packages/remote-control-server/src/__tests__/disconnect-monitor.test.ts b/packages/remote-control-server/src/__tests__/disconnect-monitor.test.ts index 23db3c0f6..de50e6f2d 100644 --- a/packages/remote-control-server/src/__tests__/disconnect-monitor.test.ts +++ b/packages/remote-control-server/src/__tests__/disconnect-monitor.test.ts @@ -75,7 +75,7 @@ describe("Disconnect Monitor Logic", () => { }); test("session becomes inactive when updatedAt is too old", () => { - const session = storeCreateSession({ status: "idle" }); + const session = storeCreateSession({}); storeUpdateSession(session.id, { status: "running" }); const timeoutMs = 300 * 1000 * 2; // 2x disconnect timeout diff --git a/packages/remote-control-server/src/routes/v1/environments.ts b/packages/remote-control-server/src/routes/v1/environments.ts index 692dc71b9..c812906ee 100644 --- a/packages/remote-control-server/src/routes/v1/environments.ts +++ b/packages/remote-control-server/src/routes/v1/environments.ts @@ -14,14 +14,14 @@ app.post("/bridge", acceptCliHeaders, apiKeyAuth, async (c) => { /** DELETE /v1/environments/bridge/:id — Deregister */ app.delete("/bridge/:id", acceptCliHeaders, apiKeyAuth, async (c) => { - const envId = c.req.param("id"); + const envId = c.req.param("id")!; deregisterEnvironment(envId); return c.json({ status: "ok" }, 200); }); /** POST /v1/environments/:id/bridge/reconnect — Reconnect */ app.post("/:id/bridge/reconnect", acceptCliHeaders, apiKeyAuth, async (c) => { - const envId = c.req.param("id"); + const envId = c.req.param("id")!; reconnectEnvironment(envId); const { reconnectWorkForEnvironment } = await import("../../services/work-dispatch"); await reconnectWorkForEnvironment(envId); diff --git a/packages/remote-control-server/src/routes/v1/environments.work.ts b/packages/remote-control-server/src/routes/v1/environments.work.ts index b5342eaff..7f024263a 100644 --- a/packages/remote-control-server/src/routes/v1/environments.work.ts +++ b/packages/remote-control-server/src/routes/v1/environments.work.ts @@ -7,7 +7,7 @@ const app = new Hono(); /** GET /v1/environments/:id/work/poll — Long-poll for work */ app.get("/:id/work/poll", acceptCliHeaders, apiKeyAuth, async (c) => { - const envId = c.req.param("id"); + const envId = c.req.param("id")!; updatePollTime(envId); const result = await pollWork(envId); if (!result) { @@ -19,21 +19,21 @@ app.get("/:id/work/poll", acceptCliHeaders, apiKeyAuth, async (c) => { /** POST /v1/environments/:id/work/:workId/ack — Acknowledge work */ app.post("/:id/work/:workId/ack", acceptCliHeaders, apiKeyAuth, async (c) => { - const workId = c.req.param("workId"); + const workId = c.req.param("workId")!; ackWork(workId); return c.json({ status: "ok" }, 200); }); /** POST /v1/environments/:id/work/:workId/stop — Stop work */ app.post("/:id/work/:workId/stop", acceptCliHeaders, apiKeyAuth, async (c) => { - const workId = c.req.param("workId"); + const workId = c.req.param("workId")!; stopWork(workId); return c.json({ status: "ok" }, 200); }); /** POST /v1/environments/:id/work/:workId/heartbeat — Heartbeat */ app.post("/:id/work/:workId/heartbeat", acceptCliHeaders, apiKeyAuth, async (c) => { - const workId = c.req.param("workId"); + const workId = c.req.param("workId")!; const result = heartbeatWork(workId); return c.json(result, 200); }); diff --git a/packages/remote-control-server/src/routes/v1/sessions.ts b/packages/remote-control-server/src/routes/v1/sessions.ts index 3dc950953..386602e6e 100644 --- a/packages/remote-control-server/src/routes/v1/sessions.ts +++ b/packages/remote-control-server/src/routes/v1/sessions.ts @@ -38,7 +38,7 @@ app.post("/", acceptCliHeaders, apiKeyAuth, async (c) => { /** GET /v1/sessions/:id — Get session */ app.get("/:id", acceptCliHeaders, apiKeyAuth, async (c) => { - const session = getSession(c.req.param("id")); + const session = getSession(c.req.param("id")!); if (!session) { return c.json({ error: { type: "not_found", message: "Session not found" } }, 404); } @@ -49,16 +49,16 @@ app.get("/:id", acceptCliHeaders, apiKeyAuth, async (c) => { app.patch("/:id", acceptCliHeaders, apiKeyAuth, async (c) => { const body = await c.req.json(); if (body.title) { - updateSessionTitle(c.req.param("id"), body.title); + updateSessionTitle(c.req.param("id")!, body.title); } - const session = getSession(c.req.param("id")); + const session = getSession(c.req.param("id")!); return c.json(session, 200); }); /** POST /v1/sessions/:id/archive — Archive session */ app.post("/:id/archive", acceptCliHeaders, apiKeyAuth, async (c) => { try { - archiveSession(c.req.param("id")); + archiveSession(c.req.param("id")!); } catch { return c.json({ status: "ok" }, 409); } @@ -67,7 +67,7 @@ app.post("/:id/archive", acceptCliHeaders, apiKeyAuth, async (c) => { /** POST /v1/sessions/:id/events — Send event to session */ app.post("/:id/events", acceptCliHeaders, apiKeyAuth, async (c) => { - const sessionId = c.req.param("id"); + const sessionId = c.req.param("id")!; const body = await c.req.json(); const events = body.events diff --git a/packages/remote-control-server/src/routes/v2/code-sessions.ts b/packages/remote-control-server/src/routes/v2/code-sessions.ts index e339e264f..00cb4b1cb 100644 --- a/packages/remote-control-server/src/routes/v2/code-sessions.ts +++ b/packages/remote-control-server/src/routes/v2/code-sessions.ts @@ -15,7 +15,7 @@ app.post("/", acceptCliHeaders, apiKeyAuth, async (c) => { /** POST /v1/code/sessions/:id/bridge — Get connection info + worker JWT */ app.post("/:id/bridge", acceptCliHeaders, apiKeyAuth, async (c) => { - const sessionId = c.req.param("id"); + const sessionId = c.req.param("id")!; const session = getSession(sessionId); if (!session) { return c.json({ error: { type: "not_found", message: "Session not found" } }, 404); diff --git a/packages/remote-control-server/src/routes/v2/worker-events-stream.ts b/packages/remote-control-server/src/routes/v2/worker-events-stream.ts index a177decbb..883e3073e 100644 --- a/packages/remote-control-server/src/routes/v2/worker-events-stream.ts +++ b/packages/remote-control-server/src/routes/v2/worker-events-stream.ts @@ -7,7 +7,7 @@ const app = new Hono(); /** SSE /v1/code/sessions/:id/worker/events/stream — SSE event stream */ app.get("/:id/worker/events/stream", acceptCliHeaders, sessionIngressAuth, async (c) => { - const sessionId = c.req.param("id"); + const sessionId = c.req.param("id")!; const session = getSession(sessionId); if (!session) { return c.json({ error: { type: "not_found", message: "Session not found" } }, 404); diff --git a/packages/remote-control-server/src/routes/v2/worker-events.ts b/packages/remote-control-server/src/routes/v2/worker-events.ts index d09fed5c3..3a36c74e6 100644 --- a/packages/remote-control-server/src/routes/v2/worker-events.ts +++ b/packages/remote-control-server/src/routes/v2/worker-events.ts @@ -7,7 +7,7 @@ const app = new Hono(); /** POST /v1/code/sessions/:id/worker/events — Write events */ app.post("/:id/worker/events", acceptCliHeaders, sessionIngressAuth, async (c) => { - const sessionId = c.req.param("id"); + const sessionId = c.req.param("id")!; const body = await c.req.json(); const events = Array.isArray(body) ? body : [body]; @@ -22,7 +22,7 @@ app.post("/:id/worker/events", acceptCliHeaders, sessionIngressAuth, async (c) = /** PUT /v1/code/sessions/:id/worker/state — Report worker state */ app.put("/:id/worker/state", acceptCliHeaders, sessionIngressAuth, async (c) => { - const sessionId = c.req.param("id"); + const sessionId = c.req.param("id")!; const body = await c.req.json(); if (body.status) { diff --git a/packages/remote-control-server/src/routes/v2/worker.ts b/packages/remote-control-server/src/routes/v2/worker.ts index 2ca067508..c65a21c3e 100644 --- a/packages/remote-control-server/src/routes/v2/worker.ts +++ b/packages/remote-control-server/src/routes/v2/worker.ts @@ -6,7 +6,7 @@ const app = new Hono(); /** POST /v1/code/sessions/:id/worker/register — Register worker */ app.post("/:id/worker/register", acceptCliHeaders, apiKeyAuth, async (c) => { - const sessionId = c.req.param("id"); + const sessionId = c.req.param("id")!; const session = getSession(sessionId); if (!session) { return c.json({ error: { type: "not_found", message: "Session not found" } }, 404); diff --git a/packages/remote-control-server/src/routes/web/control.ts b/packages/remote-control-server/src/routes/web/control.ts index e146bdb5f..e4ed09a8a 100644 --- a/packages/remote-control-server/src/routes/web/control.ts +++ b/packages/remote-control-server/src/routes/web/control.ts @@ -8,7 +8,7 @@ import { storeIsSessionOwner } from "../../store"; const app = new Hono(); function checkOwnership(c: { get: (key: string) => string | undefined }, sessionId: string) { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; if (!storeIsSessionOwner(sessionId, uuid)) { return { error: true, session: null }; } diff --git a/packages/remote-control-server/src/routes/web/sessions.ts b/packages/remote-control-server/src/routes/web/sessions.ts index 94165a84d..58de27396 100644 --- a/packages/remote-control-server/src/routes/web/sessions.ts +++ b/packages/remote-control-server/src/routes/web/sessions.ts @@ -11,7 +11,7 @@ const app = new Hono(); /** POST /web/sessions — Create a session from web UI */ app.post("/sessions", uuidAuth, async (c) => { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; const body = await c.req.json(); const session = createSession({ environment_id: body.environment_id || null, @@ -37,21 +37,21 @@ app.post("/sessions", uuidAuth, async (c) => { /** GET /web/sessions — List sessions owned by the requesting UUID */ app.get("/sessions", uuidAuth, async (c) => { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; const sessions = storeListSessionsByOwnerUuid(uuid); return c.json(sessions, 200); }); /** GET /web/sessions/all — List sessions owned by the requesting UUID (unowned sessions excluded) */ app.get("/sessions/all", uuidAuth, async (c) => { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; const sessions = listSessionSummariesByOwnerUuid(uuid); return c.json(sessions, 200); }); /** GET /web/sessions/:id — Session detail */ app.get("/sessions/:id", uuidAuth, async (c) => { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; const sessionId = c.req.param("id")!; if (!storeIsSessionOwner(sessionId, uuid)) { return c.json({ error: { type: "forbidden", message: "Not your session" } }, 403); @@ -65,7 +65,7 @@ app.get("/sessions/:id", uuidAuth, async (c) => { /** GET /web/sessions/:id/history — Historical events for session */ app.get("/sessions/:id/history", uuidAuth, async (c) => { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; const sessionId = c.req.param("id")!; if (!storeIsSessionOwner(sessionId, uuid)) { return c.json({ error: { type: "forbidden", message: "Not your session" } }, 403); @@ -82,7 +82,7 @@ app.get("/sessions/:id/history", uuidAuth, async (c) => { /** SSE /web/sessions/:id/events — Real-time event stream */ app.get("/sessions/:id/events", uuidAuth, async (c) => { - const uuid = c.get("uuid"); + const uuid = c.get("uuid")!; const sessionId = c.req.param("id")!; if (!storeIsSessionOwner(sessionId, uuid)) { return c.json({ error: { type: "forbidden", message: "Not your session" } }, 403); diff --git a/packages/remote-control-server/tsconfig.json b/packages/remote-control-server/tsconfig.json index 090f31d9f..74f468f60 100644 --- a/packages/remote-control-server/tsconfig.json +++ b/packages/remote-control-server/tsconfig.json @@ -1,17 +1,5 @@ { - "compilerOptions": { - "target": "ES2022", - "module": "ESNext", - "moduleResolution": "bundler", - "esModuleInterop": true, - "strict": true, - "skipLibCheck": true, - "outDir": "dist", - "rootDir": ".", - "declaration": true, - "resolveJsonModule": true, - "types": ["bun-types"] - }, + "extends": "../../tsconfig.base.json", "include": ["src/**/*.ts"], "exclude": ["node_modules", "dist", "web"] } diff --git a/packages/url-handler-napi/tsconfig.json b/packages/url-handler-napi/tsconfig.json new file mode 100644 index 000000000..af2850cc4 --- /dev/null +++ b/packages/url-handler-napi/tsconfig.json @@ -0,0 +1,5 @@ +{ + "extends": "../../tsconfig.base.json", + "include": ["src/**/*.ts"], + "exclude": ["node_modules", "dist"] +} diff --git a/tsconfig.base.json b/tsconfig.base.json new file mode 100644 index 000000000..db4bc1e3c --- /dev/null +++ b/tsconfig.base.json @@ -0,0 +1,15 @@ +{ + "compilerOptions": { + "target": "ESNext", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "skipLibCheck": true, + "noEmit": true, + "esModuleInterop": true, + "allowSyntheticDefaultImports": true, + "resolveJsonModule": true, + "jsx": "react-jsx", + "types": ["bun", "@types/node"] + } +} diff --git a/tsconfig.json b/tsconfig.json index 65f7e4c81..3ff0ed276 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,22 +1,12 @@ { + "extends": "./tsconfig.base.json", "compilerOptions": { - "target": "ESNext", - "module": "ESNext", - "moduleResolution": "bundler", - "jsx": "react-jsx", - "strict": true, - "skipLibCheck": true, - "noEmit": true, - "esModuleInterop": true, - "allowSyntheticDefaultImports": true, - "resolveJsonModule": true, - "types": ["bun"], "paths": { "src/*": ["./src/*"], "@claude-code-best/builtin-tools/*": ["./packages/builtin-tools/src/*"], "@claude-code-best/builtin-tools": ["./packages/builtin-tools/src/index.ts"] } }, - "include": ["src/**/*.ts", "src/**/*.tsx", "packages/builtin-tools/src/**/*.ts", "packages/builtin-tools/src/**/*.tsx"], + "include": ["src/**/*.ts", "src/**/*.tsx", "packages/**/*.ts", "packages/**/*.tsx"], "exclude": ["node_modules"] }