@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.
Files changed (134) hide show
  1. package/dist/{AIRunnerRegistry-II3WWSFN.js → AIRunnerRegistry-CFDNWSXC.js} +6 -3
  2. package/dist/{LockNote-Z2CLDZNN.js → LockNote-W2JNVMW7.js} +3 -3
  3. package/dist/PtyRunner-NYASBTRP.js +33 -0
  4. package/dist/SdkRunner-U2OTOMZU.js +9 -0
  5. package/dist/ai-runner/AIRunner.d.ts +19 -1
  6. package/dist/ai-runner/AIRunner.d.ts.map +1 -1
  7. package/dist/ai-runner/AIRunnerRegistry.d.ts +8 -0
  8. package/dist/ai-runner/AIRunnerRegistry.d.ts.map +1 -1
  9. package/dist/ai-runner/PlanFileResolver.d.ts +53 -0
  10. package/dist/ai-runner/PlanFileResolver.d.ts.map +1 -0
  11. package/dist/ai-runner/PtyRunner.d.ts +45 -4
  12. package/dist/ai-runner/PtyRunner.d.ts.map +1 -1
  13. package/dist/ai-runner/SdkRunner.d.ts +22 -0
  14. package/dist/ai-runner/SdkRunner.d.ts.map +1 -0
  15. package/dist/ai-runner/index.d.ts +5 -2
  16. package/dist/ai-runner/index.d.ts.map +1 -1
  17. package/dist/ai-runner/sdk/ClaudeCodeSDK.d.ts +37 -0
  18. package/dist/ai-runner/sdk/ClaudeCodeSDK.d.ts.map +1 -0
  19. package/dist/ai-runner/sdk/Stream.d.ts +22 -0
  20. package/dist/ai-runner/sdk/Stream.d.ts.map +1 -0
  21. package/dist/ai-runner/sdk/types.d.ts +146 -0
  22. package/dist/ai-runner/sdk/types.d.ts.map +1 -0
  23. package/dist/{ai-runner-HLA44WI6.js → ai-runner-TOHVJJ76.js} +14 -5
  24. package/dist/{analyze-ZIXNC5GN.js → analyze-DBH4K3J7.js} +8 -6
  25. package/dist/{analyze-ZIXNC5GN.js.map → analyze-DBH4K3J7.js.map} +1 -1
  26. package/dist/{braindump-56WAY2RD.js → braindump-RYI4BGMG.js} +11 -9
  27. package/dist/{braindump-56WAY2RD.js.map → braindump-RYI4BGMG.js.map} +1 -1
  28. package/dist/{chunk-AVGZH64A.js → chunk-2RWGZPNF.js} +4 -1
  29. package/dist/chunk-2RWGZPNF.js.map +1 -0
  30. package/dist/chunk-4XMYOXGZ.js +1153 -0
  31. package/dist/chunk-4XMYOXGZ.js.map +1 -0
  32. package/dist/{chunk-UBQLXQ7I.js → chunk-5JBADEKR.js} +7 -7
  33. package/dist/{chunk-M5C2WILQ.js → chunk-5M5SB6ZA.js} +7 -5
  34. package/dist/{chunk-M5C2WILQ.js.map → chunk-5M5SB6ZA.js.map} +1 -1
  35. package/dist/{chunk-HDFNMVRQ.js → chunk-DVNAH2GV.js} +2 -2
  36. package/dist/{chunk-GXFG4JU6.js → chunk-EU4XFZ2T.js} +2 -2
  37. package/dist/{chunk-NZHKAPU6.js → chunk-FJTZKAJA.js} +9 -3
  38. package/dist/chunk-FJTZKAJA.js.map +1 -0
  39. package/dist/chunk-G7QI5WDI.js +14 -0
  40. package/dist/chunk-G7QI5WDI.js.map +1 -0
  41. package/dist/{chunk-2YQHKXLL.js → chunk-GPZX4DSY.js} +22 -6
  42. package/dist/chunk-GPZX4DSY.js.map +1 -0
  43. package/dist/{chunk-IP3QTP5A.js → chunk-IWSMQXBL.js} +189 -48
  44. package/dist/chunk-IWSMQXBL.js.map +1 -0
  45. package/dist/{chunk-O3WEV5W3.js → chunk-JMACM7AJ.js} +47 -9
  46. package/dist/chunk-JMACM7AJ.js.map +1 -0
  47. package/dist/chunk-MSL7ROVK.js +1 -0
  48. package/dist/{chunk-YCYVNRLF.js → chunk-OBGEEGQ3.js} +61 -19
  49. package/dist/chunk-OBGEEGQ3.js.map +1 -0
  50. package/dist/chunk-R32Q3RGK.js +666 -0
  51. package/dist/chunk-R32Q3RGK.js.map +1 -0
  52. package/dist/{chunk-SAMTXC4A.js → chunk-TFEPHOVE.js} +12 -17
  53. package/dist/chunk-TFEPHOVE.js.map +1 -0
  54. package/dist/{chunk-QZZGIZWC.js → chunk-XSX3PGQW.js} +63 -20
  55. package/dist/chunk-XSX3PGQW.js.map +1 -0
  56. package/dist/{chunk-2MESXJEZ.js → chunk-YNRKPQLS.js} +3 -3
  57. package/dist/cli/setup/PreflightChecker.d.ts +1 -0
  58. package/dist/cli/setup/PreflightChecker.d.ts.map +1 -1
  59. package/dist/cli/setup/env-metadata.d.ts.map +1 -1
  60. package/dist/cli.js +10 -9
  61. package/dist/cli.js.map +1 -1
  62. package/dist/{config-WTRSZLOC.js → config-23TBYFP5.js} +5 -4
  63. package/dist/config-schema.d.ts +6 -0
  64. package/dist/config-schema.d.ts.map +1 -1
  65. package/dist/config.d.ts +6 -0
  66. package/dist/config.d.ts.map +1 -1
  67. package/dist/{doctor-37JNBGDN.js → doctor-ZG3DO7J5.js} +3 -3
  68. package/dist/errors/AIExecutionError.d.ts +3 -0
  69. package/dist/errors/AIExecutionError.d.ts.map +1 -1
  70. package/dist/{errors-S3BWYA4I.js → errors-J3ZRP66W.js} +2 -2
  71. package/dist/events/EventBus.d.ts +1 -1
  72. package/dist/events/EventBus.d.ts.map +1 -1
  73. package/dist/i18n/locales/en.d.ts.map +1 -1
  74. package/dist/i18n/locales/zh-CN.d.ts.map +1 -1
  75. package/dist/index.d.ts.map +1 -1
  76. package/dist/index.js +16 -14
  77. package/dist/{init-QQDXGTPB.js → init-37DLQ5AJ.js} +9 -8
  78. package/dist/{init-QQDXGTPB.js.map → init-37DLQ5AJ.js.map} +1 -1
  79. package/dist/lib.js +10 -8
  80. package/dist/lib.js.map +1 -1
  81. package/dist/orchestrator/PendingDialogStore.d.ts +12 -0
  82. package/dist/orchestrator/PendingDialogStore.d.ts.map +1 -0
  83. package/dist/orchestrator/steps/FailureHandler.d.ts.map +1 -1
  84. package/dist/orchestrator/steps/PhaseLoopStep.d.ts.map +1 -1
  85. package/dist/persistence/PlanPersistence.d.ts +5 -0
  86. package/dist/persistence/PlanPersistence.d.ts.map +1 -1
  87. package/dist/persistence/TodolistExtractor.d.ts +31 -0
  88. package/dist/persistence/TodolistExtractor.d.ts.map +1 -0
  89. package/dist/phases/BasePhase.d.ts.map +1 -1
  90. package/dist/phases/PhaseOutcome.d.ts +2 -0
  91. package/dist/phases/PhaseOutcome.d.ts.map +1 -1
  92. package/dist/phases/PlanPhase.d.ts.map +1 -1
  93. package/dist/prompts/templates.d.ts +2 -2
  94. package/dist/prompts/templates.d.ts.map +1 -1
  95. package/dist/{restart-BMILTP5X.js → restart-C7QBXT44.js} +9 -8
  96. package/dist/{restart-BMILTP5X.js.map → restart-C7QBXT44.js.map} +1 -1
  97. package/dist/run.js +16 -14
  98. package/dist/run.js.map +1 -1
  99. package/dist/start-66JO56AW.js +16 -0
  100. package/dist/start-66JO56AW.js.map +1 -0
  101. package/dist/tracker/IssueTracker.d.ts +6 -0
  102. package/dist/tracker/IssueTracker.d.ts.map +1 -1
  103. package/dist/web/routes/api.d.ts.map +1 -1
  104. package/package.json +5 -1
  105. package/src/web/frontend/dist/assets/index-DJzC2saL.css +1 -0
  106. package/src/web/frontend/dist/assets/{index-D_oTMuJU.js → index-Mnu8M3ww.js} +57 -57
  107. package/src/web/frontend/dist/index.html +2 -2
  108. package/dist/PtyRunner-6UGI5STW.js +0 -22
  109. package/dist/chunk-2YQHKXLL.js.map +0 -1
  110. package/dist/chunk-AVGZH64A.js.map +0 -1
  111. package/dist/chunk-IP3QTP5A.js.map +0 -1
  112. package/dist/chunk-NZHKAPU6.js.map +0 -1
  113. package/dist/chunk-O3WEV5W3.js.map +0 -1
  114. package/dist/chunk-QZZGIZWC.js.map +0 -1
  115. package/dist/chunk-SAMTXC4A.js.map +0 -1
  116. package/dist/chunk-U237JSLB.js +0 -1
  117. package/dist/chunk-U6GWFTKA.js +0 -657
  118. package/dist/chunk-U6GWFTKA.js.map +0 -1
  119. package/dist/chunk-YCYVNRLF.js.map +0 -1
  120. package/dist/start-6QRW6IJI.js +0 -15
  121. package/src/web/frontend/dist/assets/index-COYziOhv.css +0 -1
  122. /package/dist/{AIRunnerRegistry-II3WWSFN.js.map → AIRunnerRegistry-CFDNWSXC.js.map} +0 -0
  123. /package/dist/{LockNote-Z2CLDZNN.js.map → LockNote-W2JNVMW7.js.map} +0 -0
  124. /package/dist/{PtyRunner-6UGI5STW.js.map → PtyRunner-NYASBTRP.js.map} +0 -0
  125. /package/dist/{ai-runner-HLA44WI6.js.map → SdkRunner-U2OTOMZU.js.map} +0 -0
  126. /package/dist/{chunk-U237JSLB.js.map → ai-runner-TOHVJJ76.js.map} +0 -0
  127. /package/dist/{chunk-UBQLXQ7I.js.map → chunk-5JBADEKR.js.map} +0 -0
  128. /package/dist/{chunk-HDFNMVRQ.js.map → chunk-DVNAH2GV.js.map} +0 -0
  129. /package/dist/{chunk-GXFG4JU6.js.map → chunk-EU4XFZ2T.js.map} +0 -0
  130. /package/dist/{config-WTRSZLOC.js.map → chunk-MSL7ROVK.js.map} +0 -0
  131. /package/dist/{chunk-2MESXJEZ.js.map → chunk-YNRKPQLS.js.map} +0 -0
  132. /package/dist/{errors-S3BWYA4I.js.map → config-23TBYFP5.js.map} +0 -0
  133. /package/dist/{doctor-37JNBGDN.js.map → doctor-ZG3DO7J5.js.map} +0 -0
  134. /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-AVGZH64A.js";
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
- "--effort",
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-SAMTXC4A.js.map
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-M5C2WILQ.js";
4
+ } from "./chunk-5M5SB6ZA.js";
5
5
  import {
6
6
  createSetupRouter
7
- } from "./chunk-UBQLXQ7I.js";
7
+ } from "./chunk-5JBADEKR.js";
8
8
  import {
9
9
  buildLockNoteBody,
10
10
  buildReleaseNoteBody,
11
11
  findAllLockNotes,
12
12
  findLockNote
13
- } from "./chunk-GXFG4JU6.js";
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-IP3QTP5A.js";
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-2YQHKXLL.js";
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-YCYVNRLF.js";
62
+ } from "./chunk-OBGEEGQ3.js";
61
63
  import {
62
64
  loadConfig,
63
65
  reloadConfig
64
- } from "./chunk-NZHKAPU6.js";
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-SAMTXC4A.js";
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-AVGZH64A.js";
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-Z2CLDZNN.js");
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-HLA44WI6.js");
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-HLA44WI6.js");
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-HLA44WI6.js");
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-HLA44WI6.js");
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-HLA44WI6.js");
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-6UGI5STW.js");
8855
- const { registerAIRunner: regRunner, getPtyProfile } = await import("./AIRunnerRegistry-II3WWSFN.js");
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-QZZGIZWC.js.map
9306
+ //# sourceMappingURL=chunk-XSX3PGQW.js.map