@xdevops/issue-auto-finish 1.0.87 → 1.0.89
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/{AIRunnerRegistry-II3WWSFN.js → AIRunnerRegistry-CFDNWSXC.js} +6 -3
- package/dist/{LockNote-Z2CLDZNN.js → LockNote-W2JNVMW7.js} +3 -3
- package/dist/PtyRunner-NYASBTRP.js +33 -0
- package/dist/SdkRunner-U2OTOMZU.js +9 -0
- package/dist/ai-runner/AIRunner.d.ts +19 -1
- package/dist/ai-runner/AIRunner.d.ts.map +1 -1
- package/dist/ai-runner/AIRunnerRegistry.d.ts +8 -0
- package/dist/ai-runner/AIRunnerRegistry.d.ts.map +1 -1
- package/dist/ai-runner/PlanFileResolver.d.ts +53 -0
- package/dist/ai-runner/PlanFileResolver.d.ts.map +1 -0
- package/dist/ai-runner/PtyRunner.d.ts +45 -4
- package/dist/ai-runner/PtyRunner.d.ts.map +1 -1
- package/dist/ai-runner/SdkRunner.d.ts +22 -0
- package/dist/ai-runner/SdkRunner.d.ts.map +1 -0
- package/dist/ai-runner/index.d.ts +5 -2
- package/dist/ai-runner/index.d.ts.map +1 -1
- package/dist/ai-runner/sdk/ClaudeCodeSDK.d.ts +37 -0
- package/dist/ai-runner/sdk/ClaudeCodeSDK.d.ts.map +1 -0
- package/dist/ai-runner/sdk/Stream.d.ts +22 -0
- package/dist/ai-runner/sdk/Stream.d.ts.map +1 -0
- package/dist/ai-runner/sdk/types.d.ts +146 -0
- package/dist/ai-runner/sdk/types.d.ts.map +1 -0
- package/dist/{ai-runner-HLA44WI6.js → ai-runner-TOHVJJ76.js} +14 -5
- package/dist/{analyze-ZIXNC5GN.js → analyze-DBH4K3J7.js} +8 -6
- package/dist/{analyze-ZIXNC5GN.js.map → analyze-DBH4K3J7.js.map} +1 -1
- package/dist/{braindump-56WAY2RD.js → braindump-RYI4BGMG.js} +11 -9
- package/dist/{braindump-56WAY2RD.js.map → braindump-RYI4BGMG.js.map} +1 -1
- package/dist/{chunk-AVGZH64A.js → chunk-2RWGZPNF.js} +4 -1
- package/dist/chunk-2RWGZPNF.js.map +1 -0
- package/dist/chunk-4XMYOXGZ.js +1153 -0
- package/dist/chunk-4XMYOXGZ.js.map +1 -0
- package/dist/{chunk-UBQLXQ7I.js → chunk-5JBADEKR.js} +7 -7
- package/dist/{chunk-M5C2WILQ.js → chunk-5M5SB6ZA.js} +7 -5
- package/dist/{chunk-M5C2WILQ.js.map → chunk-5M5SB6ZA.js.map} +1 -1
- package/dist/{chunk-HDFNMVRQ.js → chunk-DVNAH2GV.js} +2 -2
- package/dist/{chunk-GXFG4JU6.js → chunk-EU4XFZ2T.js} +2 -2
- package/dist/{chunk-NZHKAPU6.js → chunk-FJTZKAJA.js} +9 -3
- package/dist/chunk-FJTZKAJA.js.map +1 -0
- package/dist/chunk-G7QI5WDI.js +14 -0
- package/dist/chunk-G7QI5WDI.js.map +1 -0
- package/dist/{chunk-2YQHKXLL.js → chunk-GPZX4DSY.js} +22 -6
- package/dist/chunk-GPZX4DSY.js.map +1 -0
- package/dist/{chunk-IP3QTP5A.js → chunk-IWSMQXBL.js} +189 -48
- package/dist/chunk-IWSMQXBL.js.map +1 -0
- package/dist/{chunk-O3WEV5W3.js → chunk-JMACM7AJ.js} +47 -9
- package/dist/chunk-JMACM7AJ.js.map +1 -0
- package/dist/chunk-MSL7ROVK.js +1 -0
- package/dist/{chunk-YCYVNRLF.js → chunk-OBGEEGQ3.js} +61 -19
- package/dist/chunk-OBGEEGQ3.js.map +1 -0
- package/dist/chunk-R32Q3RGK.js +666 -0
- package/dist/chunk-R32Q3RGK.js.map +1 -0
- package/dist/{chunk-SAMTXC4A.js → chunk-TFEPHOVE.js} +12 -17
- package/dist/chunk-TFEPHOVE.js.map +1 -0
- package/dist/{chunk-QZZGIZWC.js → chunk-XSX3PGQW.js} +63 -20
- package/dist/chunk-XSX3PGQW.js.map +1 -0
- package/dist/{chunk-2MESXJEZ.js → chunk-YNRKPQLS.js} +3 -3
- package/dist/cli/setup/PreflightChecker.d.ts +1 -0
- package/dist/cli/setup/PreflightChecker.d.ts.map +1 -1
- package/dist/cli/setup/env-metadata.d.ts.map +1 -1
- package/dist/cli.js +10 -9
- package/dist/cli.js.map +1 -1
- package/dist/{config-WTRSZLOC.js → config-23TBYFP5.js} +5 -4
- package/dist/config-schema.d.ts +6 -0
- package/dist/config-schema.d.ts.map +1 -1
- package/dist/config.d.ts +6 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/{doctor-37JNBGDN.js → doctor-ZG3DO7J5.js} +3 -3
- package/dist/errors/AIExecutionError.d.ts +3 -0
- package/dist/errors/AIExecutionError.d.ts.map +1 -1
- package/dist/{errors-S3BWYA4I.js → errors-J3ZRP66W.js} +2 -2
- package/dist/events/EventBus.d.ts +1 -1
- package/dist/events/EventBus.d.ts.map +1 -1
- package/dist/i18n/locales/en.d.ts.map +1 -1
- package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +16 -14
- package/dist/{init-QQDXGTPB.js → init-37DLQ5AJ.js} +9 -8
- package/dist/{init-QQDXGTPB.js.map → init-37DLQ5AJ.js.map} +1 -1
- package/dist/lib.js +10 -8
- package/dist/lib.js.map +1 -1
- package/dist/orchestrator/PendingDialogStore.d.ts +12 -0
- package/dist/orchestrator/PendingDialogStore.d.ts.map +1 -0
- package/dist/orchestrator/steps/FailureHandler.d.ts.map +1 -1
- package/dist/orchestrator/steps/PhaseLoopStep.d.ts.map +1 -1
- package/dist/persistence/PlanPersistence.d.ts +5 -0
- package/dist/persistence/PlanPersistence.d.ts.map +1 -1
- package/dist/persistence/TodolistExtractor.d.ts +31 -0
- package/dist/persistence/TodolistExtractor.d.ts.map +1 -0
- package/dist/phases/BasePhase.d.ts.map +1 -1
- package/dist/phases/PhaseOutcome.d.ts +2 -0
- package/dist/phases/PhaseOutcome.d.ts.map +1 -1
- package/dist/phases/PlanPhase.d.ts.map +1 -1
- package/dist/prompts/templates.d.ts +2 -2
- package/dist/prompts/templates.d.ts.map +1 -1
- package/dist/{restart-BMILTP5X.js → restart-C7QBXT44.js} +9 -8
- package/dist/{restart-BMILTP5X.js.map → restart-C7QBXT44.js.map} +1 -1
- package/dist/run.js +16 -14
- package/dist/run.js.map +1 -1
- package/dist/start-66JO56AW.js +16 -0
- package/dist/start-66JO56AW.js.map +1 -0
- package/dist/tracker/IssueTracker.d.ts +6 -0
- package/dist/tracker/IssueTracker.d.ts.map +1 -1
- package/dist/web/routes/api.d.ts.map +1 -1
- package/package.json +5 -1
- package/src/web/frontend/dist/assets/index-DJzC2saL.css +1 -0
- package/src/web/frontend/dist/assets/{index-D_oTMuJU.js → index-Mnu8M3ww.js} +57 -57
- package/src/web/frontend/dist/index.html +2 -2
- package/dist/PtyRunner-6UGI5STW.js +0 -22
- package/dist/chunk-2YQHKXLL.js.map +0 -1
- package/dist/chunk-AVGZH64A.js.map +0 -1
- package/dist/chunk-IP3QTP5A.js.map +0 -1
- package/dist/chunk-NZHKAPU6.js.map +0 -1
- package/dist/chunk-O3WEV5W3.js.map +0 -1
- package/dist/chunk-QZZGIZWC.js.map +0 -1
- package/dist/chunk-SAMTXC4A.js.map +0 -1
- package/dist/chunk-U237JSLB.js +0 -1
- package/dist/chunk-U6GWFTKA.js +0 -657
- package/dist/chunk-U6GWFTKA.js.map +0 -1
- package/dist/chunk-YCYVNRLF.js.map +0 -1
- package/dist/start-6QRW6IJI.js +0 -15
- package/src/web/frontend/dist/assets/index-COYziOhv.css +0 -1
- /package/dist/{AIRunnerRegistry-II3WWSFN.js.map → AIRunnerRegistry-CFDNWSXC.js.map} +0 -0
- /package/dist/{LockNote-Z2CLDZNN.js.map → LockNote-W2JNVMW7.js.map} +0 -0
- /package/dist/{PtyRunner-6UGI5STW.js.map → PtyRunner-NYASBTRP.js.map} +0 -0
- /package/dist/{ai-runner-HLA44WI6.js.map → SdkRunner-U2OTOMZU.js.map} +0 -0
- /package/dist/{chunk-U237JSLB.js.map → ai-runner-TOHVJJ76.js.map} +0 -0
- /package/dist/{chunk-UBQLXQ7I.js.map → chunk-5JBADEKR.js.map} +0 -0
- /package/dist/{chunk-HDFNMVRQ.js.map → chunk-DVNAH2GV.js.map} +0 -0
- /package/dist/{chunk-GXFG4JU6.js.map → chunk-EU4XFZ2T.js.map} +0 -0
- /package/dist/{config-WTRSZLOC.js.map → chunk-MSL7ROVK.js.map} +0 -0
- /package/dist/{chunk-2MESXJEZ.js.map → chunk-YNRKPQLS.js.map} +0 -0
- /package/dist/{errors-S3BWYA4I.js.map → config-23TBYFP5.js.map} +0 -0
- /package/dist/{doctor-37JNBGDN.js.map → doctor-ZG3DO7J5.js.map} +0 -0
- /package/dist/{start-6QRW6IJI.js.map → errors-J3ZRP66W.js.map} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai-runner/SdkRunner.ts","../src/ai-runner/sdk/ClaudeCodeSDK.ts","../src/ai-runner/sdk/Stream.ts","../src/ai-runner/sdk/types.ts"],"sourcesContent":["/**\n * SdkRunner — AIRunner implementation that drives Claude Code via its\n * structured JSON SDK protocol (--output-format stream-json).\n *\n * Unlike PtyRunner (which parses ANSI terminal output heuristically),\n * SdkRunner relies on deterministic JSON messages for completion detection\n * and uses the canCallTool callback for native plan mode support.\n */\n\nimport fs from 'node:fs';\nimport path from 'node:path';\nimport type { ChildProcess } from 'node:child_process';\nimport type {\n AIRunner,\n RunOptions,\n RunResult,\n StreamEvent,\n} from './AIRunner.js';\nimport { query } from './sdk/ClaudeCodeSDK.js';\nimport type {\n SDKMessage,\n SDKResultMessage,\n SDKAssistantMessage,\n PermissionResult,\n QueryOptions,\n} from './sdk/types.js';\nimport { AbortError } from './sdk/types.js';\nimport { isShuttingDown } from '../shutdown/ShutdownSignal.js';\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('SdkRunner');\n\nconst SIGKILL_GRACE_MS = 10_000;\nconst IDLE_CHECK_INTERVAL_MS = 5_000;\n\ninterface ActiveProcess {\n child: ChildProcess;\n workDir: string;\n abort: AbortController;\n}\n\nexport class SdkRunner implements AIRunner {\n private activeProcesses = new Map<ChildProcess, ActiveProcess>();\n\n constructor(\n private readonly binary: string,\n private readonly nvmNodeVersion: string,\n private readonly model?: string,\n ) {}\n\n // -- AIRunner interface ----------------------------------------------------\n\n async run(options: RunOptions): Promise<RunResult> {\n if (isShuttingDown()) {\n logger.warn('SdkRunner skipped — service is shutting down');\n return { success: false, output: 'Service shutting down', exitCode: null };\n }\n\n const {\n prompt,\n workDir,\n timeoutMs,\n idleTimeoutMs,\n onStreamEvent,\n mode,\n artifactPaths,\n } = options;\n\n logger.info('SdkRunner.run()', {\n workDir,\n timeoutMs,\n mode,\n phaseName: options.phaseName,\n });\n\n const abortController = new AbortController();\n\n // -- Build query options --\n const isPlanMode = mode === 'plan';\n let planContent: string | undefined;\n\n const queryOptions: QueryOptions = {\n cwd: workDir,\n model: this.model,\n abort: abortController.signal,\n };\n\n if (isPlanMode) {\n queryOptions.permissionMode = 'plan';\n queryOptions.allowedTools = ['Read', 'Grep', 'Glob', 'WebSearch'];\n queryOptions.canCallTool = async (\n toolName: string,\n input: unknown,\n _opts: { signal: AbortSignal },\n ): Promise<PermissionResult> => {\n if (\n toolName === 'ExitPlanMode' ||\n toolName === 'exit_plan_mode'\n ) {\n const planInput = input as Record<string, unknown> | null;\n planContent = typeof planInput?.plan === 'string'\n ? planInput.plan\n : undefined;\n\n logger.info('ExitPlanMode intercepted', {\n hasPlan: !!planContent,\n planLength: planContent?.length,\n });\n\n if (planContent && artifactPaths && artifactPaths.length > 0) {\n for (const targetPath of artifactPaths) {\n const targetDir = path.dirname(targetPath);\n if (!fs.existsSync(targetDir)) {\n fs.mkdirSync(targetDir, { recursive: true });\n }\n fs.writeFileSync(targetPath, planContent, 'utf-8');\n logger.info('Plan written to artifact path', { target: targetPath });\n }\n }\n\n return { behavior: 'deny', message: 'Plan captured by SdkRunner' };\n }\n\n return {\n behavior: 'allow',\n updatedInput: (input && typeof input === 'object')\n ? input as Record<string, unknown>\n : {},\n };\n };\n } else {\n queryOptions.permissionMode = 'bypassPermissions';\n }\n\n if (options.continueSession && options.sessionId) {\n queryOptions.resume = options.sessionId;\n }\n\n // -- Spawn Claude Code process --\n const q = query({\n prompt,\n binary: this.binary,\n options: queryOptions,\n });\n\n const entry: ActiveProcess = {\n child: q.child,\n workDir,\n abort: abortController,\n };\n this.activeProcesses.set(q.child, entry);\n\n // -- Collect output and detect completion --\n const outputParts: string[] = [];\n const stderrParts: string[] = [];\n let sessionId: string | undefined;\n let resultMessage: SDKResultMessage | undefined;\n let caughtError: Error | undefined;\n let lastActivityTime = Date.now();\n let timedOut = false;\n let timeoutType: 'wall-clock' | 'idle' | undefined;\n let wasActiveAtTimeout = false;\n\n q.child.stderr.on('data', (data: Buffer) => {\n stderrParts.push(data.toString());\n });\n\n // Wall-clock timeout with progressive extension\n const graceWindowMs = options.timeoutGraceMs ?? 60_000;\n const extensionMs = options.timeoutExtensionMs ?? 600_000;\n const maxExtensions = options.timeoutMaxExtensions ?? 3;\n let extensions = 0;\n\n const scheduleWallTimer = (delayMs: number): ReturnType<typeof setTimeout> => {\n return setTimeout(() => {\n const recentMs = Date.now() - lastActivityTime;\n const isActive = recentMs < graceWindowMs;\n if (isActive && extensions < maxExtensions) {\n extensions++;\n logger.info('Wall-clock timeout extended (agent still active)', {\n extensions,\n maxExtensions,\n lastOutputAgoMs: recentMs,\n });\n wallTimer = scheduleWallTimer(extensionMs);\n return;\n }\n timedOut = true;\n timeoutType = 'wall-clock';\n wasActiveAtTimeout = isActive;\n abortController.abort();\n }, delayMs);\n };\n let wallTimer = scheduleWallTimer(timeoutMs);\n\n // Idle timeout\n const effectiveIdleMs = idleTimeoutMs ?? 600_000;\n const idleCheck = setInterval(() => {\n const idleMs = Date.now() - lastActivityTime;\n if (idleMs >= effectiveIdleMs) {\n timedOut = true;\n timeoutType = 'idle';\n wasActiveAtTimeout = false;\n abortController.abort();\n }\n }, IDLE_CHECK_INTERVAL_MS);\n\n try {\n for await (const message of q) {\n lastActivityTime = Date.now();\n this.processMessage(\n message,\n outputParts,\n onStreamEvent,\n (sid) => { sessionId = sid; },\n (result) => { resultMessage = result; },\n );\n }\n } catch (error) {\n caughtError = error as Error;\n if (error instanceof AbortError) {\n logger.info('Claude Code process aborted', { timedOut, timeoutType });\n } else {\n logger.error('Unexpected error during SDK message iteration', {\n error: (error as Error).message,\n });\n }\n } finally {\n clearTimeout(wallTimer);\n clearInterval(idleCheck);\n this.activeProcesses.delete(q.child);\n }\n\n // -- Build RunResult --\n const output = outputParts.join('');\n const success = !timedOut && resultMessage != null && !resultMessage.is_error;\n\n let errorMessage: string | undefined;\n if (!success) {\n const parts: string[] = [];\n if (timedOut) {\n parts.push(\n timeoutType === 'idle'\n ? 'AI 长时间无响应,已超时终止'\n : '执行超时',\n );\n }\n if (resultMessage?.is_error && resultMessage.result) {\n parts.push(resultMessage.result);\n }\n if (!resultMessage && caughtError && !(caughtError instanceof AbortError)) {\n parts.push(caughtError.message);\n }\n const stderr = stderrParts.join('').trim();\n if (stderr && parts.length === 0) {\n parts.push(stderr.slice(0, 500));\n }\n errorMessage = parts.join(' | ') || 'Claude Code 进程异常退出(无输出)';\n }\n\n logger.info('SdkRunner completed', {\n workDir,\n success,\n timedOut,\n timeoutType,\n outputLength: output.length,\n sessionId,\n resultSubtype: resultMessage?.subtype,\n });\n\n return {\n success,\n output: resultMessage?.result ?? output,\n errorMessage,\n sessionId: sessionId ?? resultMessage?.session_id,\n exitCode: success ? 0 : (timedOut ? null : 1),\n timeoutType,\n wasActiveAtTimeout,\n };\n }\n\n killAll(): void {\n for (const [child, entry] of this.activeProcesses) {\n entry.abort.abort();\n this.forceKill(child);\n }\n logger.info('SdkRunner: all active processes killed', {\n count: this.activeProcesses.size,\n });\n this.activeProcesses.clear();\n }\n\n killByWorkDir(targetWorkDir: string): number {\n let killed = 0;\n for (const [child, entry] of this.activeProcesses) {\n if (entry.workDir === targetWorkDir) {\n entry.abort.abort();\n this.forceKill(child);\n this.activeProcesses.delete(child);\n killed++;\n }\n }\n if (killed > 0) {\n logger.info('SdkRunner: killed processes by workDir', {\n workDir: targetWorkDir,\n killed,\n });\n }\n return killed;\n }\n\n // -- Internal helpers ------------------------------------------------------\n\n private processMessage(\n message: SDKMessage,\n outputParts: string[],\n onStreamEvent: ((event: StreamEvent) => void) | undefined,\n onSessionId: (sid: string) => void,\n onResult: (result: SDKResultMessage) => void,\n ): void {\n switch (message.type) {\n case 'system': {\n const sys = message as { session_id?: string; model?: string };\n if (sys.session_id) onSessionId(sys.session_id);\n if (onStreamEvent) {\n onStreamEvent({\n type: 'system',\n content: message,\n timestamp: new Date().toISOString(),\n });\n }\n break;\n }\n\n case 'assistant': {\n const assistant = message as SDKAssistantMessage;\n if (assistant.message?.content) {\n for (const block of assistant.message.content) {\n if (block.type === 'text' && block.text) {\n outputParts.push(block.text);\n }\n }\n }\n if (onStreamEvent) {\n onStreamEvent({\n type: 'assistant',\n content: message,\n timestamp: new Date().toISOString(),\n });\n }\n break;\n }\n\n case 'result': {\n const result = message as SDKResultMessage;\n onResult(result);\n if (result.session_id) onSessionId(result.session_id);\n if (onStreamEvent) {\n onStreamEvent({\n type: 'result',\n content: message,\n timestamp: new Date().toISOString(),\n });\n }\n break;\n }\n\n case 'user': {\n if (onStreamEvent) {\n onStreamEvent({\n type: 'user',\n content: message,\n timestamp: new Date().toISOString(),\n });\n }\n break;\n }\n\n case 'log': {\n const log = message as { log?: { level?: string; message?: string } };\n if (log.log) {\n logger.debug(`Claude log [${log.log.level}]: ${log.log.message}`);\n }\n break;\n }\n\n default: {\n if (onStreamEvent) {\n onStreamEvent({\n type: message.type || 'raw',\n content: message,\n timestamp: new Date().toISOString(),\n });\n }\n break;\n }\n }\n }\n\n private forceKill(child: ChildProcess): void {\n try {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n setTimeout(() => {\n if (child.exitCode === null) {\n child.kill('SIGKILL');\n }\n }, SIGKILL_GRACE_MS);\n }\n } catch {\n // process may have already exited\n }\n }\n}\n","/**\n * Claude Code SDK — spawns Claude Code CLI with --output-format stream-json\n * and provides a structured async iterable of SDK messages.\n *\n * Adapted from happy project (packages/happy-cli/src/claude/sdk/query.ts).\n */\n\nimport { spawn, type ChildProcessWithoutNullStreams } from 'node:child_process';\nimport { createInterface } from 'node:readline';\nimport type { Writable } from 'node:stream';\nimport { Stream } from './Stream.js';\nimport {\n type QueryOptions,\n type QueryPrompt,\n type SDKMessage,\n type SDKControlResponse,\n type CanUseToolControlRequest,\n type CanUseToolControlResponse,\n type ControlCancelRequest,\n type PermissionResult,\n type CanCallToolCallback,\n AbortError,\n} from './types.js';\nimport { logger as rootLogger } from '../../logger.js';\n\nconst logger = rootLogger.child('ClaudeCodeSDK');\n\n// ---------------------------------------------------------------------------\n// Query class — manages a single Claude Code process interaction\n// ---------------------------------------------------------------------------\n\ntype ControlResponseHandler = (response: SDKControlResponse['response']) => void;\n\nexport class Query implements AsyncIterableIterator<SDKMessage> {\n private pendingControlResponses = new Map<string, ControlResponseHandler>();\n private cancelControllers = new Map<string, AbortController>();\n private sdkMessages: AsyncIterableIterator<SDKMessage>;\n private inputStream = new Stream<SDKMessage>();\n private canCallTool?: CanCallToolCallback;\n\n /** The underlying child process — exposed for kill/abort by SdkRunner. */\n readonly child: ChildProcessWithoutNullStreams;\n\n constructor(\n child: ChildProcessWithoutNullStreams,\n private childStdin: Writable | null,\n processExitPromise: Promise<void>,\n canCallTool?: CanCallToolCallback,\n ) {\n this.child = child;\n this.canCallTool = canCallTool;\n this.readMessages(processExitPromise);\n this.sdkMessages = this.readSdkMessages();\n }\n\n setError(error: Error): void {\n this.inputStream.error(error);\n }\n\n // -- AsyncIterableIterator -------------------------------------------------\n\n next(): Promise<IteratorResult<SDKMessage>> {\n return this.sdkMessages.next();\n }\n\n return(value?: unknown): Promise<IteratorResult<SDKMessage>> {\n if (this.sdkMessages.return) {\n return this.sdkMessages.return(value as undefined);\n }\n return Promise.resolve({ done: true, value: undefined });\n }\n\n throw(e?: unknown): Promise<IteratorResult<SDKMessage>> {\n if (this.sdkMessages.throw) {\n return this.sdkMessages.throw(e);\n }\n return Promise.reject(e);\n }\n\n [Symbol.asyncIterator](): AsyncIterableIterator<SDKMessage> {\n return this.sdkMessages;\n }\n\n // -- Internal: read stdout JSON lines --------------------------------------\n\n private async readMessages(processExitPromise: Promise<void>): Promise<void> {\n const rl = createInterface({ input: this.child.stdout });\n\n try {\n for await (const line of rl) {\n if (!line.trim()) continue;\n try {\n const message = JSON.parse(line) as SDKMessage | SDKControlResponse;\n\n if (message.type === 'control_response') {\n const controlResponse = message as SDKControlResponse;\n const handler = this.pendingControlResponses.get(\n controlResponse.response.request_id,\n );\n if (handler) {\n handler(controlResponse.response);\n }\n continue;\n }\n\n if (message.type === 'control_request') {\n await this.handleControlRequest(\n message as unknown as CanUseToolControlRequest,\n );\n continue;\n }\n\n if (message.type === 'control_cancel_request') {\n this.handleControlCancelRequest(\n message as unknown as ControlCancelRequest,\n );\n continue;\n }\n\n this.inputStream.enqueue(message);\n } catch {\n logger.debug('Non-JSON line from Claude stdout: ' + line.slice(0, 200));\n }\n }\n await processExitPromise;\n } catch (error) {\n this.inputStream.error(error as Error);\n } finally {\n this.inputStream.done();\n this.cleanupControllers();\n rl.close();\n }\n }\n\n private async *readSdkMessages(): AsyncIterableIterator<SDKMessage> {\n for await (const message of this.inputStream) {\n yield message;\n }\n }\n\n // -- Control request handling (tool permissions) ---------------------------\n\n private async handleControlRequest(\n request: CanUseToolControlRequest,\n ): Promise<void> {\n if (!this.childStdin) {\n logger.debug('Cannot handle control request — no stdin available');\n return;\n }\n\n const controller = new AbortController();\n this.cancelControllers.set(request.request_id, controller);\n\n try {\n const response = await this.processControlRequest(\n request,\n controller.signal,\n );\n const controlResponse: CanUseToolControlResponse = {\n type: 'control_response',\n response: {\n subtype: 'success',\n request_id: request.request_id,\n response,\n },\n };\n this.childStdin.write(JSON.stringify(controlResponse) + '\\n');\n } catch (error) {\n const controlErrorResponse: CanUseToolControlResponse = {\n type: 'control_response',\n response: {\n subtype: 'error',\n request_id: request.request_id,\n error: error instanceof Error ? error.message : String(error),\n },\n };\n this.childStdin.write(JSON.stringify(controlErrorResponse) + '\\n');\n } finally {\n this.cancelControllers.delete(request.request_id);\n }\n }\n\n private handleControlCancelRequest(request: ControlCancelRequest): void {\n const controller = this.cancelControllers.get(request.request_id);\n if (controller) {\n controller.abort();\n this.cancelControllers.delete(request.request_id);\n }\n }\n\n private async processControlRequest(\n request: CanUseToolControlRequest,\n signal: AbortSignal,\n ): Promise<PermissionResult> {\n if (request.request.subtype === 'can_use_tool') {\n if (!this.canCallTool) {\n throw new Error('canCallTool callback is not provided.');\n }\n return this.canCallTool(\n request.request.tool_name,\n request.request.input,\n { signal },\n );\n }\n throw new Error(\n 'Unsupported control request subtype: ' + request.request.subtype,\n );\n }\n\n private cleanupControllers(): void {\n for (const [, controller] of this.cancelControllers) {\n controller.abort();\n }\n this.cancelControllers.clear();\n }\n}\n\n// ---------------------------------------------------------------------------\n// query() factory — spawns Claude Code and returns a Query\n// ---------------------------------------------------------------------------\n\nexport function query(config: {\n prompt: QueryPrompt;\n binary: string;\n options?: QueryOptions;\n}): Query {\n const {\n prompt,\n binary,\n options: {\n allowedTools = [],\n disallowedTools = [],\n cwd,\n model,\n permissionMode = 'default',\n canCallTool,\n resume,\n continueConversation,\n appendSystemPrompt,\n maxTurns,\n abort,\n } = {},\n } = config;\n\n // Build CLI arguments\n const args = ['--output-format', 'stream-json', '--verbose'];\n\n if (appendSystemPrompt) args.push('--append-system-prompt', appendSystemPrompt);\n if (maxTurns) args.push('--max-turns', maxTurns.toString());\n if (model) args.push('--model', model);\n if (continueConversation) args.push('--continue');\n if (resume) args.push('--resume', resume);\n if (allowedTools.length > 0) args.push('--allowedTools', allowedTools.join(','));\n if (disallowedTools.length > 0) args.push('--disallowedTools', disallowedTools.join(','));\n if (permissionMode) args.push('--permission-mode', permissionMode);\n\n if (canCallTool) {\n args.push('--permission-prompt-tool', 'stdio');\n args.push('--input-format', 'stream-json');\n }\n\n // --print for single-shot mode (no canCallTool), stdin stream otherwise\n if (!canCallTool) {\n args.push('--print', prompt.trim());\n }\n\n // Build clean env: remove CLAUDECODE to prevent nested session detection\n const { CLAUDECODE: _, ...cleanEnv } = process.env;\n\n logger.info('Spawning Claude Code process', {\n binary,\n argCount: args.length,\n cwd,\n hasCanCallTool: !!canCallTool,\n });\n logger.debug('Claude Code args', { args });\n\n const child = spawn(binary, args, {\n cwd,\n stdio: ['pipe', 'pipe', 'pipe'],\n signal: abort,\n env: cleanEnv,\n windowsHide: true,\n }) as ChildProcessWithoutNullStreams;\n\n // Handle stdin\n let childStdin: Writable | null = null;\n if (!canCallTool) {\n child.stdin.end();\n } else {\n childStdin = child.stdin;\n // Send the initial user message via stream-json\n const userMessage: SDKMessage = {\n type: 'user',\n message: {\n role: 'user',\n content: prompt.trim(),\n },\n };\n childStdin.write(JSON.stringify(userMessage) + '\\n');\n }\n\n // Pipe stderr to logger\n child.stderr.on('data', (data: Buffer) => {\n logger.debug('Claude Code stderr: ' + data.toString().trimEnd());\n });\n\n // Process lifecycle\n const cleanup = () => {\n if (!child.killed) {\n child.kill('SIGTERM');\n }\n };\n\n abort?.addEventListener('abort', cleanup);\n process.on('exit', cleanup);\n\n const processExitPromise = new Promise<void>((resolve, reject) => {\n child.on('close', (code) => {\n if (abort?.aborted) {\n reject(new AbortError('Claude Code process aborted'));\n } else if (code !== 0) {\n reject(new Error(`Claude Code process exited with code ${code}`));\n } else {\n resolve();\n }\n });\n });\n\n const q = new Query(child, childStdin, processExitPromise, canCallTool);\n\n child.on('error', (error) => {\n if (abort?.aborted) {\n q.setError(new AbortError('Claude Code process aborted'));\n } else {\n q.setError(\n new Error(`Failed to spawn Claude Code process: ${error.message}`),\n );\n }\n });\n\n processExitPromise.catch(() => { /* handled in readMessages */ }).finally(() => {\n cleanup();\n abort?.removeEventListener('abort', cleanup);\n });\n\n return q;\n}\n","/**\n * Async stream implementation for handling SDK message streams.\n * Provides an AsyncIterableIterator interface with queuing, error propagation,\n * and proper cleanup.\n *\n * Adapted from happy project (packages/happy-cli/src/claude/sdk/stream.ts).\n */\n\nexport class Stream<T> implements AsyncIterableIterator<T> {\n private queue: T[] = [];\n private readResolve?: (value: IteratorResult<T>) => void;\n private readReject?: (error: Error) => void;\n private isDone = false;\n private hasError?: Error;\n private started = false;\n\n [Symbol.asyncIterator](): AsyncIterableIterator<T> {\n if (this.started) {\n throw new Error('Stream can only be iterated once');\n }\n this.started = true;\n return this;\n }\n\n async next(): Promise<IteratorResult<T>> {\n if (this.queue.length > 0) {\n return { done: false, value: this.queue.shift()! };\n }\n\n if (this.isDone) {\n return { done: true, value: undefined };\n }\n\n if (this.hasError) {\n throw this.hasError;\n }\n\n return new Promise((resolve, reject) => {\n this.readResolve = resolve;\n this.readReject = reject;\n });\n }\n\n enqueue(value: T): void {\n if (this.readResolve) {\n const resolve = this.readResolve;\n this.readResolve = undefined;\n this.readReject = undefined;\n resolve({ done: false, value });\n } else {\n this.queue.push(value);\n }\n }\n\n done(): void {\n this.isDone = true;\n if (this.readResolve) {\n const resolve = this.readResolve;\n this.readResolve = undefined;\n this.readReject = undefined;\n resolve({ done: true, value: undefined });\n }\n }\n\n error(error: Error): void {\n this.hasError = error;\n if (this.readReject) {\n const reject = this.readReject;\n this.readResolve = undefined;\n this.readReject = undefined;\n reject(error);\n }\n }\n\n async return(): Promise<IteratorResult<T>> {\n this.isDone = true;\n return { done: true, value: undefined };\n }\n}\n","/**\n * Type definitions for Claude Code SDK integration.\n * Provides type-safe interfaces for all SDK communication via\n * --output-format stream-json.\n *\n * Adapted from happy project (packages/happy-cli/src/claude/sdk/types.ts).\n */\n\n// ---------------------------------------------------------------------------\n// SDK Message types (stdout JSON lines)\n// ---------------------------------------------------------------------------\n\nexport interface SDKMessage {\n type: string;\n [key: string]: unknown;\n}\n\nexport interface SDKUserMessage extends SDKMessage {\n type: 'user';\n parent_tool_use_id?: string;\n message: {\n role: 'user';\n content: string | Array<{\n type: string;\n text?: string;\n tool_use_id?: string;\n content?: unknown;\n [key: string]: unknown;\n }>;\n };\n}\n\nexport interface SDKAssistantMessage extends SDKMessage {\n type: 'assistant';\n parent_tool_use_id?: string;\n message: {\n role: 'assistant';\n content: Array<{\n type: string;\n text?: string;\n id?: string;\n name?: string;\n input?: unknown;\n [key: string]: unknown;\n }>;\n };\n}\n\nexport interface SDKSystemMessage extends SDKMessage {\n type: 'system';\n subtype: string;\n session_id?: string;\n model?: string;\n cwd?: string;\n tools?: string[];\n}\n\nexport interface SDKResultMessage extends SDKMessage {\n type: 'result';\n subtype: 'success' | 'error_max_turns' | 'error_during_execution';\n result?: string;\n num_turns: number;\n usage?: {\n input_tokens: number;\n output_tokens: number;\n cache_read_input_tokens?: number;\n cache_creation_input_tokens?: number;\n };\n total_cost_usd: number;\n duration_ms: number;\n duration_api_ms: number;\n is_error: boolean;\n session_id: string;\n}\n\nexport interface SDKLogMessage extends SDKMessage {\n type: 'log';\n log: {\n level: 'debug' | 'info' | 'warn' | 'error';\n message: string;\n };\n}\n\n// ---------------------------------------------------------------------------\n// Control protocol (stdin/stdout JSON for tool permissions)\n// ---------------------------------------------------------------------------\n\nexport interface SDKControlRequest {\n request_id: string;\n type: 'control_request';\n request: ControlRequest;\n}\n\nexport interface ControlRequest {\n subtype: string;\n}\n\nexport interface CanUseToolRequest extends ControlRequest {\n subtype: 'can_use_tool';\n tool_name: string;\n input: unknown;\n}\n\nexport interface CanUseToolControlRequest {\n type: 'control_request';\n request_id: string;\n request: CanUseToolRequest;\n}\n\nexport interface CanUseToolControlResponse {\n type: 'control_response';\n response: {\n subtype: 'success' | 'error';\n request_id: string;\n response?: PermissionResult;\n error?: string;\n };\n}\n\nexport interface SDKControlResponse extends SDKMessage {\n type: 'control_response';\n response: {\n request_id: string;\n subtype: 'success' | 'error';\n error?: string;\n };\n}\n\nexport interface ControlCancelRequest {\n type: 'control_cancel_request';\n request_id: string;\n}\n\n// ---------------------------------------------------------------------------\n// Permission result (canCallTool callback return type)\n// ---------------------------------------------------------------------------\n\nexport type PermissionResult = {\n behavior: 'allow';\n updatedInput: Record<string, unknown>;\n} | {\n behavior: 'deny';\n message: string;\n};\n\nexport interface CanCallToolCallback {\n (toolName: string, input: unknown, options: { signal: AbortSignal }): Promise<PermissionResult>;\n}\n\n// ---------------------------------------------------------------------------\n// Query options\n// ---------------------------------------------------------------------------\n\nexport type SdkPermissionMode = 'default' | 'acceptEdits' | 'bypassPermissions' | 'plan';\n\nexport interface QueryOptions {\n abort?: AbortSignal;\n allowedTools?: string[];\n cwd?: string;\n disallowedTools?: string[];\n model?: string;\n permissionMode?: SdkPermissionMode;\n canCallTool?: CanCallToolCallback;\n /** Resume a previous session by its ID */\n resume?: string;\n /** Continue the most recent conversation */\n continueConversation?: boolean;\n /** Append to the system prompt */\n appendSystemPrompt?: string;\n /** Max turns before auto-stopping */\n maxTurns?: number;\n}\n\nexport type QueryPrompt = string;\n\n// ---------------------------------------------------------------------------\n// Errors\n// ---------------------------------------------------------------------------\n\nexport class AbortError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'AbortError';\n }\n}\n"],"mappings":"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","names":["logger","logger"]}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
|
+
import {
|
|
2
|
+
isShuttingDown
|
|
3
|
+
} from "./chunk-G7QI5WDI.js";
|
|
1
4
|
import {
|
|
2
5
|
RunnerNotRegisteredError
|
|
3
|
-
} from "./chunk-
|
|
6
|
+
} from "./chunk-2RWGZPNF.js";
|
|
4
7
|
import {
|
|
5
8
|
logger
|
|
6
9
|
} from "./chunk-GF2RRYHB.js";
|
|
@@ -65,17 +68,6 @@ function resolveModelForRunner(runnerMode, model) {
|
|
|
65
68
|
|
|
66
69
|
// src/ai-runner/BaseAIRunner.ts
|
|
67
70
|
import { spawn } from "child_process";
|
|
68
|
-
|
|
69
|
-
// src/shutdown/ShutdownSignal.ts
|
|
70
|
-
var _shuttingDown = false;
|
|
71
|
-
function isShuttingDown() {
|
|
72
|
-
return _shuttingDown;
|
|
73
|
-
}
|
|
74
|
-
function setShuttingDown() {
|
|
75
|
-
_shuttingDown = true;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
// src/ai-runner/BaseAIRunner.ts
|
|
79
71
|
var logger3 = logger.child("AIRunner");
|
|
80
72
|
var SIGKILL_GRACE_MS = 1e4;
|
|
81
73
|
var IDLE_CHECK_INTERVAL_MS = 5e3;
|
|
@@ -1004,6 +996,11 @@ function getRunnerCapabilities(mode) {
|
|
|
1004
996
|
function getPtyProfile(agentMode) {
|
|
1005
997
|
return AI_RUNNER_REGISTRY[agentMode]?.ptyProfile;
|
|
1006
998
|
}
|
|
999
|
+
function usesDeterministicPlanCopy(agentMode) {
|
|
1000
|
+
const caps = AI_RUNNER_REGISTRY[agentMode]?.capabilities;
|
|
1001
|
+
const profile = AI_RUNNER_REGISTRY[agentMode]?.ptyProfile;
|
|
1002
|
+
return !caps?.nativePlanMode && !!profile?.modeCycleKey && !!profile?.planModeName;
|
|
1003
|
+
}
|
|
1007
1004
|
function getRegistryEntry(mode) {
|
|
1008
1005
|
return AI_RUNNER_REGISTRY[mode];
|
|
1009
1006
|
}
|
|
@@ -1068,8 +1065,7 @@ registerAIRunner("claude-internal", {
|
|
|
1068
1065
|
// unreachable and preventing the commit-to-file step.
|
|
1069
1066
|
buildPtyArgs: ({ model }) => [
|
|
1070
1067
|
"--dangerously-skip-permissions",
|
|
1071
|
-
|
|
1072
|
-
"max",
|
|
1068
|
+
// '--effort', 'max',
|
|
1073
1069
|
...model ? ["--model", model] : []
|
|
1074
1070
|
],
|
|
1075
1071
|
modeCycleKey: SHIFT_TAB,
|
|
@@ -1128,8 +1124,6 @@ registerAIRunner("codebuddy-acp", {
|
|
|
1128
1124
|
|
|
1129
1125
|
export {
|
|
1130
1126
|
resolveModelForRunner,
|
|
1131
|
-
isShuttingDown,
|
|
1132
|
-
setShuttingDown,
|
|
1133
1127
|
BaseAIRunner,
|
|
1134
1128
|
ClaudeInternalRunner,
|
|
1135
1129
|
CursorAgentRunner,
|
|
@@ -1143,9 +1137,10 @@ export {
|
|
|
1143
1137
|
getBinaryEnvKey,
|
|
1144
1138
|
getRunnerCapabilities,
|
|
1145
1139
|
getPtyProfile,
|
|
1140
|
+
usesDeterministicPlanCopy,
|
|
1146
1141
|
getRegistryEntry,
|
|
1147
1142
|
createAIRunner,
|
|
1148
1143
|
validateRunnerRegistry,
|
|
1149
1144
|
isBinaryAvailable
|
|
1150
1145
|
};
|
|
1151
|
-
//# sourceMappingURL=chunk-
|
|
1146
|
+
//# sourceMappingURL=chunk-TFEPHOVE.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ai-runner/AIRunnerRegistry.ts","../src/ai-runner/ModelMapping.ts","../src/ai-runner/BaseAIRunner.ts","../src/ai-runner/ClaudeInternalRunner.ts","../src/ai-runner/CursorAgentRunner.ts","../src/ai-runner/CodebuddyRunner.ts","../src/ai-runner/CodebuddyAcpRunner.ts","../src/ai-runner/acp/AcpProtocol.ts"],"sourcesContent":["import { spawn } from 'node:child_process';\nimport type { AIRunner } from './AIRunner.js';\nimport type { BaseAIRunner } from './BaseAIRunner.js';\nimport { RunnerNotRegisteredError } from '../errors/index.js';\nimport { resolveModelForRunner } from './ModelMapping.js';\n\n// ---------------------------------------------------------------------------\n// Types\n// ---------------------------------------------------------------------------\n\nexport interface AIConfig {\n mode: string;\n binary: string;\n phaseTimeoutMs: number;\n nvmNodeVersion: string;\n model?: string;\n}\n\ntype RunnerConstructor = new (binary: string, nvmNodeVersion: string, model?: string) => BaseAIRunner;\n\nexport interface RunnerCapabilities {\n /** Whether the runner natively supports plan mode (AI enters planning mindset) */\n nativePlanMode: boolean;\n}\n\n/**\n * Describes how to launch this agent inside a PTY session.\n * Only agents supporting interactive terminal mode declare a PtyProfile.\n * Agents using different protocols (e.g. codebuddy-acp with ACP/JSON-RPC) do NOT have one.\n */\nexport interface PtyProfile {\n /** Build PTY-mode arguments (no --output-format stream-json, no -p stdin) */\n buildPtyArgs: (opts: { model?: string; startMode?: string }) => string[];\n /** Key sequence to submit input. Defaults to '\\r' (CR).\n * cursor-agent uses Kitty keyboard protocol: '\\x1b[13u' */\n enterKey?: string;\n /** If true, text and Enter key must be sent in separate PTY writes with a\n * small delay (≥100ms) between them. Agents whose TUI uses input coalescing\n * (e.g. codebuddy) treat rapid text+Enter as paste, swallowing the Enter. */\n separateEnter?: boolean;\n /** Escape sequence to cycle interactive mode (e.g. '\\x1b[Z' = Shift+Tab).\n * If set, PtyRunner can toggle plan mode within a running session. */\n modeCycleKey?: string;\n /** Detect the current interactive mode from PTY output after a modeCycleKey press.\n * Returns a mode name string (e.g. 'plan', 'bypass', 'accept-edits'). */\n detectMode?: (stripped: string) => string | undefined;\n /** The mode name that detectMode returns when plan mode is active */\n planModeName?: string;\n /** The default mode name after agent startup (before any mode switching) */\n defaultModeName?: string;\n}\n\nexport interface RunnerRegistryEntry {\n ctor?: RunnerConstructor;\n /** 自定义工厂函数(优先于 ctor),用于需要额外依赖注入的 runner(如 PtyRunner) */\n factoryFn?: (binary: string, nvmNodeVersion: string, model?: string) => AIRunner;\n defaultBinary: string;\n binaryEnvKey: string;\n capabilities: RunnerCapabilities;\n /** If set, this runner can be used as an agent inside PtyRunner */\n ptyProfile?: PtyProfile;\n}\n\n// ---------------------------------------------------------------------------\n// Registry\n// ---------------------------------------------------------------------------\n\nconst AI_RUNNER_REGISTRY: Record<string, RunnerRegistryEntry> = {};\n\nexport function registerAIRunner(mode: string, entry: RunnerRegistryEntry): void {\n AI_RUNNER_REGISTRY[mode] = entry;\n}\n\nexport function getRegisteredRunnerModes(): string[] {\n return Object.keys(AI_RUNNER_REGISTRY);\n}\n\nexport function isRegisteredRunner(mode: string): boolean {\n return mode in AI_RUNNER_REGISTRY;\n}\n\n// ---------------------------------------------------------------------------\n// Resolve helpers (replace config.ts switch/case)\n// ---------------------------------------------------------------------------\n\nexport function resolveRunnerMode(raw: string): string {\n return raw || 'claude-internal';\n}\n\nexport function getDefaultBinary(mode: string): string {\n const entry = AI_RUNNER_REGISTRY[mode];\n return entry?.defaultBinary ?? mode;\n}\n\nexport function getBinaryEnvKey(mode: string): string | undefined {\n return AI_RUNNER_REGISTRY[mode]?.binaryEnvKey;\n}\n\nexport function getRunnerCapabilities(mode: string): RunnerCapabilities | undefined {\n return AI_RUNNER_REGISTRY[mode]?.capabilities;\n}\n\nexport function getPtyProfile(agentMode: string): PtyProfile | undefined {\n return AI_RUNNER_REGISTRY[agentMode]?.ptyProfile;\n}\n\n/**\n * Whether the runner will use deterministic plan file copy (PtyRunner.runNativePlanMode)\n * instead of prompting the agent to write the plan file.\n *\n * True when: runner doesn't natively handle plan mode AND the PTY profile supports\n * interactive mode switching (Shift+Tab between plan/bypass).\n */\nexport function usesDeterministicPlanCopy(agentMode: string): boolean {\n const caps = AI_RUNNER_REGISTRY[agentMode]?.capabilities;\n const profile = AI_RUNNER_REGISTRY[agentMode]?.ptyProfile;\n return !caps?.nativePlanMode && !!profile?.modeCycleKey && !!profile?.planModeName;\n}\n\n/** Get registry entry for an agent mode (used by PtyRunner to resolve binary/envKey) */\nexport function getRegistryEntry(mode: string): RunnerRegistryEntry | undefined {\n return AI_RUNNER_REGISTRY[mode];\n}\n\n// ---------------------------------------------------------------------------\n// Factory\n// ---------------------------------------------------------------------------\n\nexport function createAIRunner(ai: AIConfig): AIRunner {\n const entry = AI_RUNNER_REGISTRY[ai.mode];\n if (!entry) {\n throw new RunnerNotRegisteredError(ai.mode, getRegisteredRunnerModes());\n }\n const resolvedModel = ai.model ? resolveModelForRunner(ai.mode, ai.model) : undefined;\n if (entry.factoryFn) {\n return entry.factoryFn(ai.binary, ai.nvmNodeVersion, resolvedModel);\n }\n return new entry.ctor!(ai.binary, ai.nvmNodeVersion, resolvedModel);\n}\n\n// ---------------------------------------------------------------------------\n// Startup validation\n// ---------------------------------------------------------------------------\n\nexport function validateRunnerRegistry(modes: string[]): void {\n const missing = modes.filter((m) => !isRegisteredRunner(m));\n if (missing.length > 0) {\n throw new RunnerNotRegisteredError(\n missing.join(', '),\n getRegisteredRunnerModes(),\n );\n }\n}\n\n// ---------------------------------------------------------------------------\n// Binary availability check\n// ---------------------------------------------------------------------------\n\n/** Check if a binary is available on the system PATH. */\nexport function isBinaryAvailable(binary: string): Promise<boolean> {\n return new Promise((resolve) => {\n const proc = spawn('which', [binary], { stdio: ['ignore', 'pipe', 'ignore'] });\n proc.on('close', (code) => resolve(code === 0));\n proc.on('error', () => resolve(false));\n });\n}\n\n// ---------------------------------------------------------------------------\n// Built-in registrations\n// ---------------------------------------------------------------------------\n\nimport { ClaudeInternalRunner } from './ClaudeInternalRunner.js';\nimport { CursorAgentRunner } from './CursorAgentRunner.js';\nimport { CodebuddyRunner } from './CodebuddyRunner.js';\nimport { CodebuddyAcpRunner } from './CodebuddyAcpRunner.js';\n\n// ---------------------------------------------------------------------------\n// Shared PTY mode detection helpers\n// ---------------------------------------------------------------------------\n\n/** Detect interactive mode from PTY output after Shift+Tab press.\n * Agents share the \"⏸ plan mode on\" indicator (claude-internal, codebuddy). */\nfunction detectClaudeMode(stripped: string): string | undefined {\n if (/plan mode on/i.test(stripped)) return 'plan';\n if (/accept edits on/i.test(stripped)) return 'accept-edits';\n if (/bypass permissions on/i.test(stripped)) return 'bypass';\n // \"? for shortcuts\" is a transient hint, not a mode indicator\n return undefined;\n}\n\nfunction detectCodebuddyMode(stripped: string): string | undefined {\n if (/plan mode on/i.test(stripped)) return 'plan';\n if (/delegate mode on/i.test(stripped)) return 'delegate';\n if (/bypass permissions on/i.test(stripped)) return 'bypass';\n return undefined;\n}\n\nfunction detectCursorAgentMode(stripped: string): string | undefined {\n // cursor-agent uses \"≡ Plan\" as plan mode indicator\n if (/≡\\s*Plan\\b/i.test(stripped)) return 'plan';\n if (/≡\\s*Auto/i.test(stripped)) return 'auto';\n return undefined;\n}\n\n// ---------------------------------------------------------------------------\n// Built-in registrations\n// ---------------------------------------------------------------------------\n\nconst SHIFT_TAB = '\\x1b[Z'; // CSI Z — universal mode cycle key\n\n// ---------------------------------------------------------------------------\n// CLI mode maps: internal mode name (from detectMode) → CLI arguments\n// ---------------------------------------------------------------------------\n\n/** claude-internal mode indicators (kept for reference in detectClaudeMode) */\n// CLI modes: plan=['--permission-mode','plan'], bypass=['--dangerously-skip-permissions']\n// Not used in buildPtyArgs — bypass start is hardcoded, modes toggled at runtime via Shift+Tab\n\n/** codebuddy mode indicators */\n// CLI modes: plan=['--permission-mode','plan'], bypass=['-y']\n\n/** cursor-agent: --mode values */\nconst CURSOR_CLI_MODES: Record<string, string[]> = {\n plan: ['--mode', 'plan'],\n ask: ['--mode', 'ask'],\n};\n\nregisterAIRunner('claude-internal', {\n ctor: ClaudeInternalRunner,\n defaultBinary: 'claude-internal',\n binaryEnvKey: 'CLAUDE_BINARY',\n capabilities: { nativePlanMode: false },\n ptyProfile: {\n // Always start in bypass mode — plan mode is toggled at runtime via\n // Shift+Tab (ensurePlanMode). Starting with --permission-mode plan\n // restricts the mode cycle to plan↔accept-edits only, making bypass\n // unreachable and preventing the commit-to-file step.\n buildPtyArgs: ({ model }) => [\n '--dangerously-skip-permissions',\n // '--effort', 'max',\n ...(model ? ['--model', model] : []),\n ],\n modeCycleKey: SHIFT_TAB,\n detectMode: detectClaudeMode,\n planModeName: 'plan',\n defaultModeName: 'bypass',\n },\n});\n\nregisterAIRunner('cursor-agent', {\n ctor: CursorAgentRunner,\n defaultBinary: 'cursor-agent',\n binaryEnvKey: 'CURSOR_BINARY',\n capabilities: { nativePlanMode: true },\n ptyProfile: {\n buildPtyArgs: ({ model, startMode }) => [\n 'agent', '--force',\n ...((startMode && CURSOR_CLI_MODES[startMode]) ?? []),\n ...(model ? ['--model', model] : []),\n ],\n enterKey: '\\x1b[13u', // Kitty keyboard protocol Enter\n modeCycleKey: SHIFT_TAB,\n detectMode: detectCursorAgentMode,\n planModeName: 'plan',\n defaultModeName: 'auto',\n },\n});\n\nregisterAIRunner('codebuddy', {\n ctor: CodebuddyRunner,\n defaultBinary: 'codebuddy',\n binaryEnvKey: 'CODEBUDDY_BINARY',\n capabilities: { nativePlanMode: false },\n ptyProfile: {\n // Always start in bypass — same reason as claude-internal above.\n buildPtyArgs: ({ model }) => [\n '-y',\n ...(model ? ['--model', model] : []),\n ],\n modeCycleKey: SHIFT_TAB,\n detectMode: detectCodebuddyMode,\n planModeName: 'plan',\n defaultModeName: 'bypass',\n // Codebuddy's TUI uses input coalescing (multiline CleanTextInput) —\n // text+Enter sent in a single PTY write is treated as pasted text,\n // with \\r becoming a newline instead of triggering message submission.\n separateEnter: true,\n },\n});\n\nregisterAIRunner('codebuddy-acp', {\n ctor: CodebuddyAcpRunner,\n defaultBinary: 'codebuddy',\n binaryEnvKey: 'CODEBUDDY_BINARY',\n capabilities: { nativePlanMode: true },\n});\n","// ---------------------------------------------------------------------------\n// 模型名称映射:规范名 (AI_MODEL 配置值) → 各 Runner CLI 接受的模型 ID\n// ---------------------------------------------------------------------------\n\nimport { logger as rootLogger } from '../logger.js';\n\nconst logger = rootLogger.child('ModelMapping');\n\ntype RunnerModelMap = Record<string, string>;\n\n/**\n * 每个 Runner 的模型名映射表。\n * key = runner mode(如 'codebuddy'),value = { 规范名 → CLI 模型名 }。\n * 未列出的 runner(如 claude-internal、cursor-agent)表示无需映射,直接透传。\n */\nconst MODEL_MAPS: Record<string, RunnerModelMap> = {\n codebuddy: {\n // Claude 系列\n 'Claude-4.6-Opus': 'claude-opus-4.6',\n 'claude-4.6-opus-high-thinking': 'claude-opus-4.6',\n 'claude-opus-4.6-1m': 'claude-opus-4.6-1m',\n 'Claude-Sonnet-4.6': 'claude-sonnet-4.6',\n 'claude-sonnet-4.6-1m': 'claude-sonnet-4.6-1m',\n 'Claude-4.5': 'claude-4.5',\n 'Claude-Opus-4.5': 'claude-opus-4.5',\n 'Claude-Haiku-4.5': 'claude-haiku-4.5',\n // GPT 系列\n 'GPT-5.4': 'gpt-5.4',\n 'GPT-5.3': 'gpt-5.3',\n 'GPT-5.3-Codex': 'gpt-5.3-codex',\n 'GPT-5.2': 'gpt-5.2',\n 'GPT-5.2-Codex': 'gpt-5.2-codex',\n 'GPT-5.1': 'gpt-5.1',\n 'GPT-5.1-Codex': 'gpt-5.1-codex',\n 'GPT-5.1-Codex-Max': 'gpt-5.1-codex-max',\n 'GPT-5.1-Codex-Mini': 'gpt-5.1-codex-mini',\n // Gemini 系列\n 'Gemini-2.5-Pro': 'gemini-2.5-pro',\n 'Gemini-3.0-Flash': 'gemini-3.0-flash',\n 'Gemini-3.1-Pro': 'gemini-3.1-pro',\n 'Gemini-3.1-Flash-Lite': 'gemini-3.1-flash-lite',\n // GLM 系列\n 'GLM-5.0-Turbo': 'glm-5.0-turbo-ioa',\n 'GLM-5.0': 'glm-5.0-ioa',\n 'GLM-4.7': 'glm-4.7-ioa',\n // 其他国产模型\n 'MiniMax-M2.7': 'minimax-m2.7-ioa',\n 'MiniMax-M2.5': 'minimax-m2.5-ioa',\n 'Kimi-K2.5': 'kimi-k2.5-ioa',\n 'DeepSeek-V3-2': 'deepseek-v3-2-volc-ioa',\n 'Hunyuan-2.0': 'hunyuan-2.0-thinking-ioa',\n },\n // claude-internal 和 cursor-agent 无需映射,直接透传\n};\n\n// codebuddy-acp 复用 codebuddy 的模型映射\nMODEL_MAPS['codebuddy-acp'] = MODEL_MAPS['codebuddy'];\n\n/**\n * 根据 runner mode 将规范模型名映射为该 CLI 接受的模型 ID。\n * 如果该 runner 没有映射表,则原样返回。\n * 如果有映射表但找不到对应条目,返回 undefined(由调用方使用默认模型)。\n */\nexport function resolveModelForRunner(runnerMode: string, model: string): string | undefined {\n const map = MODEL_MAPS[runnerMode];\n if (!map) return model;\n const resolved = map[model];\n if (resolved) return resolved;\n logger.warn('Model not in mapping table, will use runner default', {\n runnerMode,\n requestedModel: model,\n availableModels: Object.keys(map),\n });\n return undefined;\n}\n","import { spawn, type ChildProcess, type SpawnOptions } from 'node:child_process';\nimport { logger as rootLogger } from '../logger.js';\nimport { isShuttingDown } from '../shutdown/ShutdownSignal.js';\nimport type { RunOptions, RunResult, StreamEvent } from './AIRunner.js';\n\nconst logger = rootLogger.child('AIRunner');\n\nconst SIGKILL_GRACE_MS = 10_000;\nconst IDLE_CHECK_INTERVAL_MS = 5_000;\nconst RESULT_EXIT_GRACE_MS = 30_000;\n\ninterface ActiveChild {\n child: ChildProcess;\n workDir: string;\n}\n\nexport abstract class BaseAIRunner {\n protected abstract getBinary(): string;\n protected abstract buildArgs(options: RunOptions): string[];\n protected abstract getSpawnOptions(options: RunOptions): SpawnOptions;\n\n private activeChildren = new Map<ChildProcess, ActiveChild>();\n\n async run(options: RunOptions): Promise<RunResult> {\n if (isShuttingDown()) {\n logger.warn('AI runner skipped — service is shutting down');\n return { success: false, output: 'Service shutting down', exitCode: null };\n }\n\n const { prompt, workDir, timeoutMs, sessionId, continueSession, idleTimeoutMs, onStreamEvent } = options;\n\n logger.info('Running AI runner', {\n workDir,\n timeoutMs,\n idleTimeoutMs,\n continueSession: !!continueSession,\n sessionId,\n });\n\n return new Promise<RunResult>((resolve) => {\n const chunks: Buffer[] = [];\n const stderrChunks: Buffer[] = [];\n let timedOut = false;\n let timeoutType: 'wall-clock' | 'idle' | undefined;\n let lineBuffer = '';\n let killTimer: ReturnType<typeof setTimeout> | undefined;\n let lastActivityTime = Date.now();\n let resultGraceTimer: ReturnType<typeof setTimeout> | undefined;\n\n const binary = this.getBinary();\n const args = this.buildArgs(options);\n const spawnOpts = this.getSpawnOptions(options);\n\n const child = spawn(binary, args, {\n ...spawnOpts,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n this.activeChildren.set(child, { child, workDir });\n\n const timer = setTimeout(() => {\n timedOut = true;\n timeoutType = 'wall-clock';\n child.kill('SIGTERM');\n logger.warn('AI runner timed out', { timeoutMs });\n\n killTimer = setTimeout(() => {\n if (child.exitCode === null) {\n child.kill('SIGKILL');\n child.stdout?.destroy();\n child.stderr?.destroy();\n logger.warn('AI runner force-killed (SIGKILL fallback)', { workDir });\n }\n }, SIGKILL_GRACE_MS);\n }, timeoutMs);\n\n // Idle timeout: kill process if no stdout/stderr activity for idleTimeoutMs\n const idleCheckInterval = idleTimeoutMs\n ? setInterval(() => {\n const idleMs = Date.now() - lastActivityTime;\n if (idleMs >= idleTimeoutMs) {\n timedOut = true;\n timeoutType = 'idle';\n child.kill('SIGTERM');\n logger.warn('AI runner idle timed out', {\n idleTimeoutMs,\n idleSinceMs: idleMs,\n });\n clearInterval(idleCheckInterval!);\n\n killTimer = setTimeout(() => {\n if (child.exitCode === null) {\n child.kill('SIGKILL');\n child.stdout?.destroy();\n child.stderr?.destroy();\n logger.warn('AI runner force-killed after idle timeout (SIGKILL fallback)', { workDir });\n }\n }, SIGKILL_GRACE_MS);\n }\n }, IDLE_CHECK_INTERVAL_MS)\n : undefined;\n\n const flushInterval = onStreamEvent\n ? setInterval(() => {\n if (lineBuffer.trim()) {\n onStreamEvent({ type: 'partial', content: lineBuffer.trim(), timestamp: new Date().toISOString() });\n }\n }, 200)\n : undefined;\n\n child.stdout.on('data', (chunk: Buffer) => {\n lastActivityTime = Date.now();\n chunks.push(chunk);\n\n lineBuffer += chunk.toString();\n let newlineIdx: number;\n while ((newlineIdx = lineBuffer.indexOf('\\n')) !== -1) {\n const line = lineBuffer.slice(0, newlineIdx).trim();\n lineBuffer = lineBuffer.slice(newlineIdx + 1);\n if (!line) continue;\n\n if (onStreamEvent) {\n this.emitStreamLine(line, onStreamEvent);\n }\n\n // Detect result event: start grace timer to kill hanging process\n if (!resultGraceTimer) {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n if (parsed.type === 'result') {\n resultGraceTimer = setTimeout(() => {\n if (child.exitCode === null) {\n logger.warn('AI runner process did not exit after result event, sending SIGTERM', {\n graceMs: RESULT_EXIT_GRACE_MS,\n });\n child.kill('SIGTERM');\n\n killTimer = setTimeout(() => {\n if (child.exitCode === null) {\n child.kill('SIGKILL');\n child.stdout?.destroy();\n child.stderr?.destroy();\n logger.warn('AI runner force-killed after result grace (SIGKILL fallback)', { workDir });\n }\n }, SIGKILL_GRACE_MS);\n }\n }, RESULT_EXIT_GRACE_MS);\n }\n } catch {\n // not JSON, ignore\n }\n }\n }\n });\n\n child.stderr.on('data', (chunk: Buffer) => {\n lastActivityTime = Date.now();\n stderrChunks.push(chunk);\n const text = chunk.toString();\n logger.debug('AI runner stderr: ' + text);\n if (onStreamEvent) {\n onStreamEvent({ type: 'stderr', content: text, timestamp: new Date().toISOString() });\n }\n });\n\n child.on('close', (code) => {\n this.activeChildren.delete(child);\n clearTimeout(timer);\n if (killTimer) clearTimeout(killTimer);\n if (resultGraceTimer) clearTimeout(resultGraceTimer);\n if (idleCheckInterval) clearInterval(idleCheckInterval);\n if (flushInterval) clearInterval(flushInterval);\n\n if (onStreamEvent && lineBuffer.trim()) {\n this.emitStreamLine(lineBuffer.trim(), onStreamEvent);\n }\n\n const rawOutput = Buffer.concat(chunks as unknown as Uint8Array[]).toString('utf-8');\n const { output, resolvedSessionId, hasError, errorMessage: parsedErrorMessage } = this.parseOutput(rawOutput, sessionId);\n\n const success = code === 0 && !timedOut && !hasError;\n logger.info('AI runner finished', { exitCode: code, success, timedOut });\n\n const stderrText = stderrChunks.length > 0 ? Buffer.concat(stderrChunks as unknown as Uint8Array[]).toString('utf-8').trim() : '';\n const finalOutput = (!success && !output.trim() && stderrText) ? stderrText : output;\n\n // 组装真正的错误原因\n let errorMessage: string | undefined;\n if (!success) {\n const parts: string[] = [];\n if (timedOut) parts.push(timeoutType === 'idle' ? 'AI 长时间无响应,已超时终止' : '执行超时');\n if (parsedErrorMessage) parts.push(parsedErrorMessage);\n if (code !== 0 && code !== null) parts.push(`进程退出码: ${code}`);\n if (!parts.length && stderrText) parts.push(stderrText.slice(0, 500));\n errorMessage = parts.join(' | ') || undefined;\n }\n\n resolve({\n success,\n output: finalOutput,\n errorMessage,\n sessionId: resolvedSessionId ?? sessionId,\n exitCode: code,\n timeoutType,\n });\n });\n\n child.on('error', (err) => {\n this.activeChildren.delete(child);\n clearTimeout(timer);\n if (killTimer) clearTimeout(killTimer);\n if (resultGraceTimer) clearTimeout(resultGraceTimer);\n if (idleCheckInterval) clearInterval(idleCheckInterval);\n if (flushInterval) clearInterval(flushInterval);\n logger.error('AI runner spawn error', { error: err.message });\n resolve({\n success: false,\n output: err.message,\n errorMessage: err.message,\n exitCode: null,\n });\n });\n\n child.stdin.write(prompt);\n child.stdin.end();\n });\n }\n\n killAll(): void {\n for (const [child] of this.activeChildren) {\n this.forceKillChild(child);\n }\n logger.info('Killed all active AI runner children', { count: this.activeChildren.size });\n }\n\n killByWorkDir(targetWorkDir: string): number {\n let killed = 0;\n for (const [child, entry] of this.activeChildren) {\n if (entry.workDir === targetWorkDir) {\n this.forceKillChild(child);\n killed++;\n }\n }\n if (killed > 0) {\n logger.info('Killed AI runner children by workDir', { workDir: targetWorkDir, killed });\n }\n return killed;\n }\n\n private forceKillChild(child: ChildProcess): void {\n try {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n setTimeout(() => {\n if (child.exitCode === null) {\n child.kill('SIGKILL');\n }\n }, SIGKILL_GRACE_MS);\n }\n } catch {\n // process may have already exited\n }\n }\n\n private emitStreamLine(line: string, onStreamEvent: (event: StreamEvent) => void): void {\n try {\n const parsed = JSON.parse(line) as Record<string, unknown>;\n onStreamEvent({\n type: (typeof parsed.type === 'string' ? parsed.type : 'raw'),\n content: parsed,\n timestamp: new Date().toISOString(),\n });\n } catch {\n onStreamEvent({ type: 'raw', content: line, timestamp: new Date().toISOString() });\n }\n }\n\n /**\n * Handles both stream-json (one JSON object per line) and legacy single-JSON formats.\n */\n parseOutput(rawOutput: string, _sessionId?: string): { output: string; resolvedSessionId?: string; hasError?: boolean; errorMessage?: string } {\n let output = rawOutput;\n let resolvedSessionId: string | undefined;\n\n const events = this.tryParseStreamJson(rawOutput);\n if (events) {\n output = events\n .filter((item: { type?: string }) => item.type === 'result')\n .map((item: { result?: string }) => item.result ?? '')\n .join('\\n');\n const sessionItem = events.find(\n (item: { type?: string; session_id?: string }) => item.session_id != null,\n );\n if (sessionItem) {\n resolvedSessionId = (sessionItem as { session_id: string }).session_id;\n }\n if (!output) {\n output = this.extractAssistantText(events);\n }\n if (!output) {\n output = this.summarizeStreamEvents(events);\n }\n\n // 始终检查 error 事件,不论 output 是否有值\n const hasError = this.hasErrorEvents(events);\n const errorMessage = hasError ? this.extractErrorMessage(events) : undefined;\n return { output, resolvedSessionId, hasError, errorMessage };\n }\n\n try {\n const parsed = JSON.parse(rawOutput);\n if (Array.isArray(parsed)) {\n output = parsed\n .filter((item: { type?: string }) => item.type === 'result')\n .map((item: { result?: string }) => item.result ?? '')\n .join('\\n');\n const sessionItem = parsed.find(\n (item: { type?: string; session_id?: string }) => item.session_id != null,\n );\n if (sessionItem) {\n resolvedSessionId = sessionItem.session_id;\n }\n if (!output) {\n output = this.extractAssistantText(parsed);\n }\n // 始终检查 error 事件\n const hasError = this.hasErrorEvents(parsed);\n const errorMessage = hasError ? this.extractErrorMessage(parsed) : undefined;\n return { output, resolvedSessionId, hasError, errorMessage };\n } else if (parsed.result != null) {\n output = parsed.result;\n resolvedSessionId = parsed.session_id;\n }\n } catch {\n // raw text output\n }\n\n return { output, resolvedSessionId };\n }\n\n /**\n * Extract plain text from assistant events as fallback when result.result is empty.\n * Looks for message.content[].text in assistant-type events.\n */\n private extractAssistantText(events: Record<string, unknown>[]): string {\n const texts: string[] = [];\n for (const evt of events) {\n if (evt.type !== 'assistant') continue;\n const message = evt.message as { content?: Array<{ type?: string; text?: string }> } | undefined;\n if (!message?.content || !Array.isArray(message.content)) continue;\n for (const block of message.content) {\n if (block.type === 'text' && block.text) {\n texts.push(block.text);\n }\n }\n }\n return texts.join('');\n }\n\n private hasErrorEvents(events: Record<string, unknown>[]): boolean {\n return events.some(e => e.type === 'error' || e.subtype === 'error');\n }\n\n /** 提取 error 事件中的错误描述信息 */\n private extractErrorMessage(events: Record<string, unknown>[]): string {\n const errorEvents = events.filter(e => e.type === 'error' || e.subtype === 'error');\n if (errorEvents.length === 0) return '';\n return errorEvents.map(e => String(e.message ?? e.error ?? JSON.stringify(e))).join('; ');\n }\n\n private summarizeStreamEvents(events: Record<string, unknown>[]): string {\n const errorEvents = events.filter(\n (e) => e.type === 'error' || e.subtype === 'error',\n );\n if (errorEvents.length > 0) {\n const messages = errorEvents.map(\n (e) => String(e.message ?? e.error ?? JSON.stringify(e)),\n );\n return `AI runner 错误: ${messages.join('; ')}`;\n }\n\n const types = events.map((e) => String(e.type ?? 'unknown'));\n const typeCounts: Record<string, number> = {};\n for (const t of types) {\n typeCounts[t] = (typeCounts[t] ?? 0) + 1;\n }\n const summary = Object.entries(typeCounts)\n .map(([t, c]) => `${t}(${c})`)\n .join(', ');\n return `AI runner 未返回结果 (收到 ${events.length} 个事件: ${summary})`;\n }\n\n private tryParseStreamJson(raw: string): Record<string, unknown>[] | null {\n const lines = raw.split('\\n').filter((l) => l.trim());\n if (lines.length < 2) return null;\n\n const objects: Record<string, unknown>[] = [];\n for (const line of lines) {\n try {\n objects.push(JSON.parse(line) as Record<string, unknown>);\n } catch {\n return null;\n }\n }\n return objects;\n }\n}\n","import type { SpawnOptions } from 'node:child_process';\nimport { BaseAIRunner } from './BaseAIRunner.js';\nimport type { RunOptions } from './AIRunner.js';\n\nexport class ClaudeInternalRunner extends BaseAIRunner {\n private readonly binary: string;\n private readonly nvmNodeVersion: string;\n private readonly model?: string;\n\n constructor(binary: string, nvmNodeVersion: string, model?: string) {\n super();\n this.binary = binary;\n this.nvmNodeVersion = nvmNodeVersion;\n this.model = model;\n }\n\n protected getBinary(): string {\n return this.binary;\n }\n\n protected buildArgs(options: RunOptions): string[] {\n const args = ['-p', '-', '--output-format', 'stream-json', '--verbose'];\n if (options.mode === 'plan') {\n args.push('--permission-mode', 'plan', '--allowedTools', 'Read,Grep,Glob,WebSearch');\n } else {\n args.push('--dangerously-skip-permissions');\n }\n if (this.model) {\n args.push('--model', this.model);\n }\n if (options.continueSession && options.sessionId) {\n args.push('--resume', options.sessionId);\n }\n return args;\n }\n\n protected getSpawnOptions(options: RunOptions): SpawnOptions {\n const { CLAUDECODE, ...env } = process.env;\n return {\n cwd: options.workDir,\n env: {\n ...env,\n NODE_VERSION: this.nvmNodeVersion,\n },\n };\n }\n}\n","import type { SpawnOptions } from 'node:child_process';\nimport { BaseAIRunner } from './BaseAIRunner.js';\nimport type { RunOptions } from './AIRunner.js';\n\nexport class CursorAgentRunner extends BaseAIRunner {\n private readonly binary: string;\n private readonly nvmNodeVersion: string;\n private readonly model?: string;\n\n constructor(binary: string, nvmNodeVersion: string, model?: string) {\n super();\n this.binary = binary;\n this.nvmNodeVersion = nvmNodeVersion;\n this.model = model;\n }\n\n protected getBinary(): string {\n return this.binary;\n }\n\n protected buildArgs(options: RunOptions): string[] {\n const args = [\n 'agent',\n '-p',\n '--force',\n '--trust',\n '--output-format',\n 'stream-json',\n '--workspace',\n options.workDir,\n ];\n if (options.mode === 'plan') {\n args.push('--mode', 'plan');\n }\n if (this.model) {\n args.push('--model', this.model);\n }\n if (options.continueSession && options.sessionId) {\n args.push('--resume', options.sessionId);\n }\n return args;\n }\n\n protected getSpawnOptions(_options: RunOptions): SpawnOptions {\n return {\n cwd: process.cwd(),\n env: {\n ...process.env,\n NODE_VERSION: this.nvmNodeVersion,\n },\n };\n }\n}\n","import type { SpawnOptions } from 'node:child_process';\nimport { BaseAIRunner } from './BaseAIRunner.js';\nimport type { RunOptions } from './AIRunner.js';\n\nexport class CodebuddyRunner extends BaseAIRunner {\n private readonly binary: string;\n private readonly nvmNodeVersion: string;\n private readonly model?: string;\n\n constructor(binary: string, nvmNodeVersion: string, model?: string) {\n super();\n this.binary = binary;\n this.nvmNodeVersion = nvmNodeVersion;\n this.model = model;\n }\n\n protected getBinary(): string {\n return this.binary;\n }\n\n protected buildArgs(options: RunOptions): string[] {\n const args = ['-p', '-', '--output-format', 'stream-json', '--verbose'];\n if (this.model) {\n args.push('--model', this.model);\n }\n if (options.continueSession && options.sessionId) {\n args.push('--resume', options.sessionId);\n }\n // CodeBuddy 的 --permission-mode plan 设计为交互式审批,与 -p 非交互模式不兼容,\n // 会导致进程卡死。plan 阶段的行为约束通过 Prompt 层(planModeFallback)控制。\n args.push('-y');\n return args;\n }\n\n protected getSpawnOptions(options: RunOptions): SpawnOptions {\n // eslint-disable-next-line @typescript-eslint/no-unused-vars\n const { CLAUDECODE, ...env } = process.env;\n return {\n cwd: options.workDir,\n env: {\n ...env,\n NODE_VERSION: this.nvmNodeVersion,\n },\n };\n }\n}\n","/**\n * CodeBuddy ACP Runner — uses the Agent Client Protocol (JSON-RPC 2.0 over stdio)\n * for native plan-mode support with programmatic input/output control.\n *\n * Unlike CodebuddyRunner (pipe mode), this runner maintains a persistent session\n * with three-step handshake (initialize → session/new → session/prompt) and handles\n * permission requests from the agent.\n */\nimport { spawn, type ChildProcess } from 'node:child_process';\nimport { logger as rootLogger } from '../logger.js';\nimport { isShuttingDown } from '../shutdown/ShutdownSignal.js';\nimport type { RunOptions, RunResult, StreamEvent } from './AIRunner.js';\nimport { BaseAIRunner } from './BaseAIRunner.js';\nimport {\n AcpProtocol,\n isNotification,\n isAgentRequest,\n isResponse,\n isPermissionRequest,\n isSessionUpdate,\n type AcpInboundMessage,\n type AcpUpdatePayload,\n type AcpUpdateChunk,\n type AcpUpdateToolCall,\n type AcpUpdateToolCallUpdate,\n} from './acp/AcpProtocol.js';\n\nconst logger = rootLogger.child('CodebuddyAcpRunner');\n\nconst SIGKILL_GRACE_MS = 10_000;\nconst IDLE_CHECK_INTERVAL_MS = 5_000;\n\ninterface ActiveChild {\n child: ChildProcess;\n workDir: string;\n}\n\n/** Handshake FSM states */\ntype HandshakeState = 'init' | 'session_new' | 'prompting' | 'done';\n\nexport class CodebuddyAcpRunner extends BaseAIRunner {\n private readonly binary: string;\n private readonly nvmNodeVersion: string;\n private readonly model?: string;\n private acpActiveChildren = new Map<ChildProcess, ActiveChild>();\n\n constructor(binary: string, nvmNodeVersion: string, model?: string) {\n super();\n this.binary = binary;\n this.nvmNodeVersion = nvmNodeVersion;\n this.model = model;\n }\n\n // ── Overrides required by BaseAIRunner (kept for compatibility) ──\n\n protected getBinary(): string {\n return this.binary;\n }\n\n protected buildArgs(_options: RunOptions): string[] {\n const args = ['--acp', '--acp-transport', 'stdio', '--permission-mode', 'plan', '--verbose'];\n if (this.model) args.push('--model', this.model);\n return args;\n }\n\n protected getSpawnOptions(options: RunOptions): Record<string, unknown> {\n const { CLAUDECODE, ...env } = process.env;\n void CLAUDECODE;\n return {\n cwd: options.workDir,\n env: { ...env, NODE_VERSION: this.nvmNodeVersion },\n };\n }\n\n // ── Main entry: override BaseAIRunner.run() for ACP session lifecycle ──\n\n async run(options: RunOptions): Promise<RunResult> {\n if (isShuttingDown()) {\n logger.warn('ACP runner skipped — service is shutting down');\n return { success: false, output: 'Service shutting down', exitCode: null };\n }\n\n const { prompt, workDir, timeoutMs, idleTimeoutMs, onStreamEvent } = options;\n\n logger.info('Starting CodeBuddy ACP session', {\n workDir,\n timeoutMs,\n idleTimeoutMs,\n model: this.model,\n });\n\n return new Promise<RunResult>((resolve) => {\n const protocol = new AcpProtocol();\n let rpcId = 1;\n let sessionId: string | undefined;\n let handshake: HandshakeState = 'init';\n const outputChunks: string[] = [];\n let timedOut = false;\n let timeoutType: 'wall-clock' | 'idle' | undefined;\n let lastActivityTime = Date.now();\n let resolved = false;\n const stderrChunks: string[] = [];\n\n const safeResolve = (result: RunResult) => {\n if (resolved) return;\n resolved = true;\n cleanup();\n resolve(result);\n };\n\n const binary = this.getBinary();\n const args = this.buildArgs(options);\n const spawnOpts = this.getSpawnOptions(options);\n\n const child = spawn(binary, args, {\n ...(spawnOpts as Record<string, unknown>),\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n\n this.acpActiveChildren.set(child, { child, workDir });\n\n // ── Timers ──\n\n const wallTimer = setTimeout(() => {\n timedOut = true;\n timeoutType = 'wall-clock';\n logger.warn('ACP runner wall-clock timeout', { timeoutMs });\n killChild(child);\n }, timeoutMs);\n\n let killTimer: ReturnType<typeof setTimeout> | undefined;\n\n const idleInterval = idleTimeoutMs\n ? setInterval(() => {\n if (Date.now() - lastActivityTime >= idleTimeoutMs) {\n timedOut = true;\n timeoutType = 'idle';\n logger.warn('ACP runner idle timeout', { idleTimeoutMs });\n clearInterval(idleInterval!);\n killChild(child);\n }\n }, IDLE_CHECK_INTERVAL_MS)\n : undefined;\n\n const cleanup = () => {\n clearTimeout(wallTimer);\n if (killTimer) clearTimeout(killTimer);\n if (idleInterval) clearInterval(idleInterval);\n this.acpActiveChildren.delete(child);\n };\n\n const killChild = (proc: ChildProcess) => {\n try {\n proc.kill('SIGTERM');\n killTimer = setTimeout(() => {\n if (proc.exitCode === null) {\n proc.kill('SIGKILL');\n proc.stdout?.destroy();\n proc.stderr?.destroy();\n }\n }, SIGKILL_GRACE_MS);\n } catch { /* already exited */ }\n };\n\n // ── Send initialize as first message ──\n child.stdin!.write(protocol.encodeRequest('initialize', { protocolVersion: 1 }, rpcId++));\n\n // ── Stdout handler ──\n child.stdout!.on('data', (chunk: Buffer) => {\n lastActivityTime = Date.now();\n\n for (const msg of protocol.parseChunk(chunk)) {\n this.handleMessage(\n msg, child, protocol, handshake,\n () => rpcId++,\n (s) => { sessionId = s; },\n () => sessionId,\n (h) => { handshake = h; },\n () => handshake,\n workDir, prompt, outputChunks, onStreamEvent,\n (result) => safeResolve(result),\n options,\n );\n }\n });\n\n child.stderr!.on('data', (chunk: Buffer) => {\n lastActivityTime = Date.now();\n const text = chunk.toString();\n stderrChunks.push(text);\n logger.debug('ACP runner stderr: ' + text.slice(0, 500));\n if (onStreamEvent) {\n onStreamEvent({ type: 'stderr', content: text, timestamp: new Date().toISOString() });\n }\n });\n\n child.on('close', (code) => {\n // Flush remaining buffer\n for (const msg of protocol.flush()) {\n this.handleMessage(\n msg, child, protocol, handshake,\n () => rpcId++,\n (s) => { sessionId = s; },\n () => sessionId,\n (h) => { handshake = h; },\n () => handshake,\n workDir, prompt, outputChunks, onStreamEvent,\n (result) => safeResolve(result),\n options,\n );\n }\n\n const output = outputChunks.join('');\n const stderrText = stderrChunks.join('').trim();\n const success = code === 0 && !timedOut;\n\n let errorMessage: string | undefined;\n if (!success) {\n const parts: string[] = [];\n if (timedOut) parts.push(timeoutType === 'idle' ? 'AI 长时间无响应,已超时终止' : '执行超时');\n if (code !== 0 && code !== null) parts.push(`进程退出码: ${code}`);\n if (!parts.length && stderrText) parts.push(stderrText.slice(0, 500));\n errorMessage = parts.join(' | ') || undefined;\n }\n\n logger.info('ACP runner finished', { exitCode: code, success, timedOut });\n safeResolve({\n success,\n output: output || stderrText,\n errorMessage,\n sessionId,\n exitCode: code,\n timeoutType,\n });\n });\n\n child.on('error', (err) => {\n logger.error('ACP runner spawn error', { error: err.message });\n safeResolve({\n success: false,\n output: err.message,\n errorMessage: err.message,\n exitCode: null,\n });\n });\n });\n }\n\n // ── Message dispatch ──\n\n private handleMessage(\n msg: AcpInboundMessage,\n child: ChildProcess,\n protocol: AcpProtocol,\n _handshake: HandshakeState,\n nextId: () => number,\n setSessionId: (s: string) => void,\n getSessionId: () => string | undefined,\n setHandshake: (h: HandshakeState) => void,\n getHandshake: () => HandshakeState,\n workDir: string,\n prompt: string,\n outputChunks: string[],\n onStreamEvent: ((event: StreamEvent) => void) | undefined,\n onComplete: (result: RunResult) => void,\n options: RunOptions,\n ): void {\n if (isResponse(msg)) {\n this.handleResponse(\n msg, child, protocol, nextId, setSessionId, getSessionId,\n setHandshake, getHandshake, workDir, prompt, outputChunks,\n onStreamEvent, onComplete, options,\n );\n } else if (isNotification(msg)) {\n this.handleNotification(msg, outputChunks, onStreamEvent);\n } else if (isAgentRequest(msg)) {\n this.handleAgentRequest(msg, child, protocol, onStreamEvent, options);\n }\n }\n\n private handleResponse(\n msg: AcpInboundMessage,\n child: ChildProcess,\n protocol: AcpProtocol,\n nextId: () => number,\n setSessionId: (s: string) => void,\n getSessionId: () => string | undefined,\n setHandshake: (h: HandshakeState) => void,\n getHandshake: () => HandshakeState,\n workDir: string,\n prompt: string,\n outputChunks: string[],\n onStreamEvent: ((event: StreamEvent) => void) | undefined,\n _onComplete: (result: RunResult) => void,\n _options: RunOptions,\n ): void {\n const result = msg.result as Record<string, unknown> | undefined;\n const state = getHandshake();\n\n if (state === 'init' && result?.protocolVersion !== undefined) {\n // initialize response → send session/new\n setHandshake('session_new');\n child.stdin!.write(\n protocol.encodeRequest('session/new', { cwd: workDir, mcpServers: [] }, nextId()),\n );\n } else if (state === 'session_new' && result?.sessionId) {\n // session/new response → send session/prompt\n setSessionId(result.sessionId as string);\n setHandshake('prompting');\n child.stdin!.write(\n protocol.encodeRequest(\n 'session/prompt',\n {\n sessionId: result.sessionId,\n prompt: [{ type: 'text', text: prompt }],\n },\n nextId(),\n ),\n );\n } else if (state === 'prompting') {\n // session/prompt final response\n setHandshake('done');\n const stopReason = (result as Record<string, unknown> | undefined)?.stopReason as string | undefined;\n logger.info('ACP session/prompt completed', {\n stopReason,\n sessionId: getSessionId(),\n });\n if (onStreamEvent) {\n onStreamEvent({\n type: 'system',\n content: `ACP session completed: ${stopReason ?? 'unknown'}`,\n timestamp: new Date().toISOString(),\n });\n }\n // Collect final output text\n if (stopReason === 'refusal') {\n outputChunks.push('[REFUSED] Agent 拒绝执行');\n }\n }\n }\n\n private handleNotification(\n msg: AcpInboundMessage,\n outputChunks: string[],\n onStreamEvent: ((event: StreamEvent) => void) | undefined,\n ): void {\n if (!isSessionUpdate(msg)) return;\n\n const update = msg.params?.update as AcpUpdatePayload | undefined;\n if (!update) return;\n\n const event = this.mapUpdateToStreamEvent(update, outputChunks);\n if (event && onStreamEvent) {\n onStreamEvent(event);\n }\n }\n\n private handleAgentRequest(\n msg: AcpInboundMessage,\n child: ChildProcess,\n protocol: AcpProtocol,\n onStreamEvent: ((event: StreamEvent) => void) | undefined,\n options: RunOptions,\n ): void {\n if (!isPermissionRequest(msg)) {\n // Unknown agent request — send empty result to avoid blocking\n child.stdin!.write(protocol.encodeResponse(msg.id as number, {}));\n return;\n }\n\n const toolTitle = msg.params.toolCall.rawInput\n ? JSON.stringify(msg.params.toolCall.rawInput).slice(0, 200)\n : msg.params.toolCall.toolCallId;\n\n if (onStreamEvent) {\n onStreamEvent({\n type: 'system',\n content: `Permission requested: ${toolTitle}`,\n timestamp: new Date().toISOString(),\n });\n }\n\n if (options.onInputRequired) {\n const permissionContent = JSON.stringify({\n toolCallId: msg.params.toolCall.toolCallId,\n options: msg.params.options,\n rawInput: msg.params.toolCall.rawInput,\n });\n\n options.onInputRequired({ type: 'plan-approval', content: permissionContent })\n .then((decision) => {\n const optionId = decision === 'reject' ? 'reject' : 'allow';\n child.stdin!.write(\n protocol.encodeResponse(msg.id, {\n outcome: { outcome: 'selected', optionId },\n }),\n );\n })\n .catch((err) => {\n logger.warn('onInputRequired callback failed, auto-approving', { error: (err as Error).message });\n this.autoApprove(child, protocol, msg.id, msg.params.options);\n });\n return;\n }\n\n // No callback: auto-approve all permissions\n this.autoApprove(child, protocol, msg.id, msg.params.options);\n }\n\n private autoApprove(\n child: ChildProcess,\n protocol: AcpProtocol,\n requestId: number,\n options: Array<{ optionId: string; kind: string }>,\n ): void {\n const allowOption = options.find(\n (o) => o.kind === 'allow_always' || o.kind === 'allow_once',\n );\n child.stdin!.write(\n protocol.encodeResponse(requestId, {\n outcome: { outcome: 'selected', optionId: allowOption?.optionId ?? 'allow' },\n }),\n );\n }\n\n // ── StreamEvent mapping (reuses existing frontend log pipeline) ──\n\n private mapUpdateToStreamEvent(\n update: AcpUpdatePayload,\n outputChunks: string[],\n ): StreamEvent | null {\n switch (update.sessionUpdate) {\n case 'agent_message_chunk': {\n const chunk = update as AcpUpdateChunk;\n if (chunk.content.type === 'thinking') {\n return {\n type: 'thinking',\n content: { text: chunk.content.text },\n timestamp: new Date().toISOString(),\n };\n }\n outputChunks.push(chunk.content.text);\n return {\n type: 'assistant',\n content: {\n message: { content: [{ type: 'text', text: chunk.content.text }] },\n },\n timestamp: new Date().toISOString(),\n };\n }\n\n case 'tool_call': {\n const tc = update as AcpUpdateToolCall;\n return {\n type: 'tool_use',\n content: { tool: { name: tc.title, input: tc.rawInput ?? {} } },\n timestamp: new Date().toISOString(),\n };\n }\n\n case 'tool_call_update': {\n const tcu = update as AcpUpdateToolCallUpdate;\n return {\n type: 'tool_result',\n content: tcu.status,\n timestamp: new Date().toISOString(),\n };\n }\n\n default:\n return null;\n }\n }\n\n // ── Process management ──\n\n killAll(): void {\n for (const [child] of this.acpActiveChildren) {\n this.forceKill(child);\n }\n logger.info('Killed all ACP runner children', { count: this.acpActiveChildren.size });\n }\n\n killByWorkDir(targetWorkDir: string): number {\n let killed = 0;\n for (const [child, entry] of this.acpActiveChildren) {\n if (entry.workDir === targetWorkDir) {\n this.forceKill(child);\n killed++;\n }\n }\n if (killed > 0) {\n logger.info('Killed ACP runner children by workDir', { workDir: targetWorkDir, killed });\n }\n return killed;\n }\n\n private forceKill(child: ChildProcess): void {\n try {\n if (child.exitCode === null) {\n child.kill('SIGTERM');\n setTimeout(() => {\n if (child.exitCode === null) child.kill('SIGKILL');\n }, SIGKILL_GRACE_MS);\n }\n } catch { /* already exited */ }\n }\n}\n","/**\n * ACP (Agent Client Protocol) JSON-RPC 2.0 codec.\n *\n * Handles line-buffered parsing of newline-delimited JSON messages from\n * CodeBuddy's stdin/stdout ACP transport and encoding of outbound requests/responses.\n *\n * Protocol reference: https://agentclientprotocol.com/protocol/schema\n */\n\n// ---------------------------------------------------------------------------\n// Outbound types (Agent → Client)\n// ---------------------------------------------------------------------------\n\nexport interface AcpUpdateChunk {\n sessionUpdate: 'agent_message_chunk';\n content: { type: 'text' | 'thinking'; text: string };\n}\n\nexport interface AcpUpdateToolCall {\n sessionUpdate: 'tool_call';\n toolCallId: string;\n title: string;\n kind: string;\n status: string;\n content?: Array<{\n type: string;\n path?: string;\n oldText?: string | null;\n newText?: string;\n text?: string;\n }>;\n rawInput?: Record<string, unknown>;\n}\n\nexport interface AcpUpdateToolCallUpdate {\n sessionUpdate: 'tool_call_update';\n toolCallId: string;\n status: string;\n}\n\nexport interface AcpUpdateGeneric {\n sessionUpdate: string;\n [key: string]: unknown;\n}\n\nexport type AcpUpdatePayload =\n | AcpUpdateChunk\n | AcpUpdateToolCall\n | AcpUpdateToolCallUpdate\n | AcpUpdateGeneric;\n\nexport interface AcpSessionUpdate {\n jsonrpc: '2.0';\n method: 'session/update';\n params: {\n sessionId: string;\n update: AcpUpdatePayload;\n };\n}\n\nexport interface AcpPermissionOption {\n optionId: string;\n name: string;\n kind: string;\n}\n\nexport interface AcpPermissionRequest {\n jsonrpc: '2.0';\n id: number;\n method: 'session/request_permission';\n params: {\n sessionId: string;\n options: AcpPermissionOption[];\n toolCall: {\n toolCallId: string;\n rawInput?: Record<string, unknown>;\n };\n };\n}\n\nexport interface AcpResponse {\n jsonrpc: '2.0';\n id: number;\n result: Record<string, unknown>;\n}\n\nexport interface AcpError {\n jsonrpc: '2.0';\n id: number;\n error: { code: number; message: string; data?: unknown };\n}\n\n// Discriminated message type from the agent\nexport type AcpInboundMessage = Record<string, unknown>;\n\n// ---------------------------------------------------------------------------\n// Message classification helpers\n// ---------------------------------------------------------------------------\n\nexport function isNotification(msg: AcpInboundMessage): boolean {\n return typeof msg.method === 'string' && msg.id === undefined;\n}\n\nexport function isAgentRequest(msg: AcpInboundMessage): boolean {\n return typeof msg.method === 'string' && msg.id !== undefined;\n}\n\nexport function isResponse(msg: AcpInboundMessage): boolean {\n return msg.method === undefined && msg.id !== undefined;\n}\n\nexport function isPermissionRequest(msg: AcpInboundMessage): msg is AcpPermissionRequest & AcpInboundMessage {\n return isAgentRequest(msg) && msg.method === 'session/request_permission';\n}\n\nexport function isSessionUpdate(msg: AcpInboundMessage): msg is AcpSessionUpdate & AcpInboundMessage {\n return isNotification(msg) && msg.method === 'session/update';\n}\n\n// ---------------------------------------------------------------------------\n// Protocol codec\n// ---------------------------------------------------------------------------\n\nexport class AcpProtocol {\n private lineBuffer = '';\n\n /** Parse incoming data chunk into zero or more complete JSON-RPC messages. */\n parseChunk(chunk: Buffer | string): AcpInboundMessage[] {\n this.lineBuffer += typeof chunk === 'string' ? chunk : chunk.toString('utf-8');\n\n const messages: AcpInboundMessage[] = [];\n let newlineIdx: number;\n\n while ((newlineIdx = this.lineBuffer.indexOf('\\n')) !== -1) {\n const line = this.lineBuffer.slice(0, newlineIdx).trim();\n this.lineBuffer = this.lineBuffer.slice(newlineIdx + 1);\n\n if (!line) continue;\n\n try {\n messages.push(JSON.parse(line) as AcpInboundMessage);\n } catch {\n // Malformed line — skip silently (could be debug output from --verbose)\n }\n }\n\n return messages;\n }\n\n /** Flush any remaining buffered data (e.g. on stream end). */\n flush(): AcpInboundMessage[] {\n const remaining = this.lineBuffer.trim();\n this.lineBuffer = '';\n if (!remaining) return [];\n\n try {\n return [JSON.parse(remaining) as AcpInboundMessage];\n } catch {\n return [];\n }\n }\n\n /** Encode a JSON-RPC request (Client → Agent). */\n encodeRequest(method: string, params: Record<string, unknown>, id: number): string {\n return JSON.stringify({ jsonrpc: '2.0', method, params, id }) + '\\n';\n }\n\n /** Encode a JSON-RPC response (Client → Agent, replying to agent request). */\n encodeResponse(id: number, result: Record<string, unknown>): string {\n return JSON.stringify({ jsonrpc: '2.0', id, result }) + '\\n';\n }\n}\n"],"mappings":"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","names":["spawn","logger","logger","spawn","logger","SIGKILL_GRACE_MS","IDLE_CHECK_INTERVAL_MS","spawn","spawn"]}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import {
|
|
2
2
|
BraindumpOrchestrator,
|
|
3
3
|
BraindumpTracker
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-5M5SB6ZA.js";
|
|
5
5
|
import {
|
|
6
6
|
createSetupRouter
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-5JBADEKR.js";
|
|
8
8
|
import {
|
|
9
9
|
buildLockNoteBody,
|
|
10
10
|
buildReleaseNoteBody,
|
|
11
11
|
findAllLockNotes,
|
|
12
12
|
findLockNote
|
|
13
|
-
} from "./chunk-
|
|
13
|
+
} from "./chunk-EU4XFZ2T.js";
|
|
14
14
|
import {
|
|
15
15
|
TerminalManager
|
|
16
16
|
} from "./chunk-KC5S66OZ.js";
|
|
@@ -22,10 +22,12 @@ import {
|
|
|
22
22
|
PipelineOrchestrator,
|
|
23
23
|
PlanPersistence,
|
|
24
24
|
buildSingleRepoWorkspace,
|
|
25
|
+
clearPendingDialog,
|
|
25
26
|
createLifecycleManager,
|
|
26
27
|
getAllPipelineDefs,
|
|
27
28
|
getE2eEnabled,
|
|
28
29
|
getNoteSyncEnabled,
|
|
30
|
+
getPendingDialog,
|
|
29
31
|
getPipelineDef,
|
|
30
32
|
gongfengIssueToDemandSpec,
|
|
31
33
|
isMultiRepo,
|
|
@@ -36,7 +38,7 @@ import {
|
|
|
36
38
|
setE2eOverride,
|
|
37
39
|
setNoteSyncOverride,
|
|
38
40
|
validatePhaseRegistry
|
|
39
|
-
} from "./chunk-
|
|
41
|
+
} from "./chunk-IWSMQXBL.js";
|
|
40
42
|
import {
|
|
41
43
|
AsyncMutex,
|
|
42
44
|
BaseTracker,
|
|
@@ -45,7 +47,7 @@ import {
|
|
|
45
47
|
getExternalId,
|
|
46
48
|
getIid,
|
|
47
49
|
getTitle
|
|
48
|
-
} from "./chunk-
|
|
50
|
+
} from "./chunk-GPZX4DSY.js";
|
|
49
51
|
import {
|
|
50
52
|
IwikiImporter,
|
|
51
53
|
getProjectKnowledge,
|
|
@@ -57,11 +59,11 @@ import {
|
|
|
57
59
|
import {
|
|
58
60
|
setLocale,
|
|
59
61
|
t
|
|
60
|
-
} from "./chunk-
|
|
62
|
+
} from "./chunk-OBGEEGQ3.js";
|
|
61
63
|
import {
|
|
62
64
|
loadConfig,
|
|
63
65
|
reloadConfig
|
|
64
|
-
} from "./chunk-
|
|
66
|
+
} from "./chunk-FJTZKAJA.js";
|
|
65
67
|
import {
|
|
66
68
|
resolveDisplayHost
|
|
67
69
|
} from "./chunk-AKXDQH25.js";
|
|
@@ -74,15 +76,17 @@ import {
|
|
|
74
76
|
getDefaultBinary,
|
|
75
77
|
isBinaryAvailable,
|
|
76
78
|
isRegisteredRunner,
|
|
77
|
-
isShuttingDown,
|
|
78
79
|
resolveModelForRunner,
|
|
79
|
-
setShuttingDown,
|
|
80
80
|
validateRunnerRegistry
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-TFEPHOVE.js";
|
|
82
|
+
import {
|
|
83
|
+
isShuttingDown,
|
|
84
|
+
setShuttingDown
|
|
85
|
+
} from "./chunk-G7QI5WDI.js";
|
|
82
86
|
import {
|
|
83
87
|
SessionLimitError,
|
|
84
88
|
SessionNotFoundError
|
|
85
|
-
} from "./chunk-
|
|
89
|
+
} from "./chunk-2RWGZPNF.js";
|
|
86
90
|
import {
|
|
87
91
|
KnowledgeStore
|
|
88
92
|
} from "./chunk-DAX3FD2O.js";
|
|
@@ -1287,6 +1291,34 @@ function createApiRouter(trackerOrDeps, config, agentLogStore, orchestrator, mai
|
|
|
1287
1291
|
const planPersistence = new PlanPersistence(workDir, iid);
|
|
1288
1292
|
res.json(planPersistence.readReviewHistory());
|
|
1289
1293
|
});
|
|
1294
|
+
router.post("/api/issues/:iid/input-response", (req, res) => {
|
|
1295
|
+
const iid = parseInt(req.params.iid, 10);
|
|
1296
|
+
const record = tracker.get(iid);
|
|
1297
|
+
if (!record) {
|
|
1298
|
+
res.status(404).json({ error: "Issue not found" });
|
|
1299
|
+
return;
|
|
1300
|
+
}
|
|
1301
|
+
const { response } = req.body;
|
|
1302
|
+
if (!response) {
|
|
1303
|
+
res.status(400).json({ error: "Missing response field" });
|
|
1304
|
+
return;
|
|
1305
|
+
}
|
|
1306
|
+
eventBus.emitTyped("agent:inputResponse", { issueIid: iid, response });
|
|
1307
|
+
logger7.info("Agent input response forwarded", { iid, response });
|
|
1308
|
+
res.json({ success: true });
|
|
1309
|
+
});
|
|
1310
|
+
router.get("/api/issues/:iid/pending-dialog", (req, res) => {
|
|
1311
|
+
const iid = parseInt(req.params.iid, 10);
|
|
1312
|
+
const dialog = getPendingDialog(iid);
|
|
1313
|
+
res.json({ dialog: dialog ?? null });
|
|
1314
|
+
});
|
|
1315
|
+
router.delete("/api/issues/:iid/pending-dialog", (req, res) => {
|
|
1316
|
+
const iid = parseInt(req.params.iid, 10);
|
|
1317
|
+
clearPendingDialog(iid);
|
|
1318
|
+
eventBus.emitTyped("agent:dialogDismissed", { issueIid: iid });
|
|
1319
|
+
logger7.info("Pending dialog dismissed by user", { iid });
|
|
1320
|
+
res.json({ success: true });
|
|
1321
|
+
});
|
|
1290
1322
|
router.put("/api/issues/:iid/note-sync", (req, res) => {
|
|
1291
1323
|
const iid = parseInt(req.params.iid, 10);
|
|
1292
1324
|
const record = tracker.get(iid);
|
|
@@ -1617,7 +1649,7 @@ data: ${JSON.stringify({ time: (/* @__PURE__ */ new Date()).toISOString() })}
|
|
|
1617
1649
|
const issueId = getExternalId(record);
|
|
1618
1650
|
const iid = getIid(record);
|
|
1619
1651
|
const notes = await gongfeng.listIssueNotes(issueId);
|
|
1620
|
-
const { findLockNote: findLockNote2 } = await import("./LockNote-
|
|
1652
|
+
const { findLockNote: findLockNote2 } = await import("./LockNote-W2JNVMW7.js");
|
|
1621
1653
|
const existingLock = findLockNote2(notes);
|
|
1622
1654
|
if (!existingLock) {
|
|
1623
1655
|
const result = await claimer.tryClaim(
|
|
@@ -2426,7 +2458,7 @@ function createKnowledgeRouter(deps) {
|
|
|
2426
2458
|
heartbeat = setInterval(() => {
|
|
2427
2459
|
sendProgress({ step: "analyzing", current: 2, total, message: "AI \u5206\u6790\u4E2D...", elapsed: Date.now() - aiStart });
|
|
2428
2460
|
}, 3e3);
|
|
2429
|
-
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-
|
|
2461
|
+
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-TOHVJJ76.js");
|
|
2430
2462
|
const runner = createAIRunner2(config.ai);
|
|
2431
2463
|
const { analyze } = await import("./KnowledgeAnalyzer-MTTTSSHX.js");
|
|
2432
2464
|
const knowledge = await analyze({ workDir, aiRunner: runner, syncToProject: config.sync.knowledgeToProject });
|
|
@@ -2471,7 +2503,7 @@ function createKnowledgeRouter(deps) {
|
|
|
2471
2503
|
(async () => {
|
|
2472
2504
|
try {
|
|
2473
2505
|
sendProgress({ step: "collecting", current: 1, total, message: "\u68C0\u6D4B\u53D8\u66F4\u5E76\u6536\u96C6\u4FE1\u606F..." });
|
|
2474
|
-
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-
|
|
2506
|
+
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-TOHVJJ76.js");
|
|
2475
2507
|
const { analyzeIncremental } = await import("./KnowledgeAnalyzer-MTTTSSHX.js");
|
|
2476
2508
|
const runner = createAIRunner2(config.ai);
|
|
2477
2509
|
sendProgress({ step: "analyzing", current: 2, total, message: "\u589E\u91CF\u5206\u6790\u4E2D..." });
|
|
@@ -2755,7 +2787,7 @@ function createDomainModelRouter(deps) {
|
|
|
2755
2787
|
}
|
|
2756
2788
|
(async () => {
|
|
2757
2789
|
try {
|
|
2758
|
-
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-
|
|
2790
|
+
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-TOHVJJ76.js");
|
|
2759
2791
|
const runner = createAIRunner2(config.ai);
|
|
2760
2792
|
const model = await analyzer.analyze({
|
|
2761
2793
|
workDir: config.project.workDir,
|
|
@@ -2969,7 +3001,7 @@ function createSystemUseCaseRouter(deps) {
|
|
|
2969
3001
|
}
|
|
2970
3002
|
(async () => {
|
|
2971
3003
|
try {
|
|
2972
|
-
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-
|
|
3004
|
+
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-TOHVJJ76.js");
|
|
2973
3005
|
const runner = createAIRunner2(config.ai);
|
|
2974
3006
|
const model = await analyzer.analyze({
|
|
2975
3007
|
workDir: config.project.workDir,
|
|
@@ -3159,7 +3191,7 @@ function createSystemUseCaseRouter(deps) {
|
|
|
3159
3191
|
res.status(404).json({ error: "No domain model loaded \u2014 run domain analysis first" });
|
|
3160
3192
|
return;
|
|
3161
3193
|
}
|
|
3162
|
-
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-
|
|
3194
|
+
const { createAIRunner: createAIRunner2 } = await import("./ai-runner-TOHVJJ76.js");
|
|
3163
3195
|
const runner = createAIRunner2(config.ai);
|
|
3164
3196
|
const associations = await analyzer.suggestDomainAssociations(
|
|
3165
3197
|
useCaseModel,
|
|
@@ -8851,8 +8883,8 @@ async function main() {
|
|
|
8851
8883
|
let sharedTerminalManager;
|
|
8852
8884
|
if (config.ai.mode === "pty") {
|
|
8853
8885
|
const { TerminalManager: TerminalManager2 } = await import("./TerminalManager-RT2N7N5R.js");
|
|
8854
|
-
const { PtyRunner } = await import("./PtyRunner-
|
|
8855
|
-
const { registerAIRunner: regRunner, getPtyProfile } = await import("./AIRunnerRegistry-
|
|
8886
|
+
const { PtyRunner } = await import("./PtyRunner-NYASBTRP.js");
|
|
8887
|
+
const { registerAIRunner: regRunner, getPtyProfile } = await import("./AIRunnerRegistry-CFDNWSXC.js");
|
|
8856
8888
|
const allPtyAgents = /* @__PURE__ */ new Set([
|
|
8857
8889
|
config.pty.defaultAgent,
|
|
8858
8890
|
...Object.values(config.pty.phaseAgents)
|
|
@@ -8891,6 +8923,17 @@ async function main() {
|
|
|
8891
8923
|
phaseAgents: config.pty.phaseAgents
|
|
8892
8924
|
});
|
|
8893
8925
|
}
|
|
8926
|
+
if (config.ai.mode === "sdk") {
|
|
8927
|
+
const { SdkRunner } = await import("./SdkRunner-U2OTOMZU.js");
|
|
8928
|
+
const { registerAIRunner: regRunner } = await import("./AIRunnerRegistry-CFDNWSXC.js");
|
|
8929
|
+
regRunner("sdk", {
|
|
8930
|
+
factoryFn: (binary, nvmNodeVersion, model) => new SdkRunner(binary, nvmNodeVersion, model),
|
|
8931
|
+
defaultBinary: "claude",
|
|
8932
|
+
binaryEnvKey: "CLAUDE_BINARY",
|
|
8933
|
+
capabilities: { nativePlanMode: true }
|
|
8934
|
+
});
|
|
8935
|
+
logger.info("SDK runner registered");
|
|
8936
|
+
}
|
|
8894
8937
|
validatePhaseRegistry(allAiPhaseNames);
|
|
8895
8938
|
validateRunnerRegistry([config.ai.mode]);
|
|
8896
8939
|
const aiRunner = createAIRunner(config.ai);
|
|
@@ -9260,4 +9303,4 @@ function migrateKnowledgeDir(srcDir, destDir) {
|
|
|
9260
9303
|
export {
|
|
9261
9304
|
main
|
|
9262
9305
|
};
|
|
9263
|
-
//# sourceMappingURL=chunk-
|
|
9306
|
+
//# sourceMappingURL=chunk-XSX3PGQW.js.map
|