@cjhyy/code-shell-core 0.5.0-rc.1 → 0.6.0-rc.1

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 (528) hide show
  1. package/README.md +13 -10
  2. package/dist/agent/agent-definition-registry.d.ts +21 -3
  3. package/dist/agent/agent-definition-registry.js +49 -18
  4. package/dist/agent/agent-definition.d.ts +32 -0
  5. package/dist/agent/agent-definition.js +49 -4
  6. package/dist/arena/arena.js +11 -12
  7. package/dist/arena/context/context-tools.js +47 -6
  8. package/dist/arena/context/within-root.d.ts +7 -0
  9. package/dist/arena/context/within-root.js +15 -0
  10. package/dist/arena/iterate/phases/argue.js +8 -2
  11. package/dist/arena/iterate/phases/revise.js +1 -1
  12. package/dist/arena/iterate/phases/tournament.js +3 -3
  13. package/dist/arena/ledger.js +9 -1
  14. package/dist/arena/phases/adjudication.js +1 -4
  15. package/dist/arena/phases/build-consensus.js +1 -4
  16. package/dist/arena/phases/cross-review.js +2 -8
  17. package/dist/arena/phases/debate-rounds.js +1 -4
  18. package/dist/arena/phases/participant-research.js +1 -4
  19. package/dist/arena/phases/planning-detail-expansion.js +8 -10
  20. package/dist/arena/planner.js +0 -1
  21. package/dist/arena/providers/docs.d.ts +1 -0
  22. package/dist/arena/providers/docs.js +5 -2
  23. package/dist/arena/providers/repo.d.ts +1 -0
  24. package/dist/arena/providers/repo.js +5 -2
  25. package/dist/arena/strategies/utils.d.ts +1 -4
  26. package/dist/arena/strategies/utils.js +7 -51
  27. package/dist/arena/transitions.d.ts +7 -2
  28. package/dist/arena/transitions.js +9 -4
  29. package/dist/arena/types.d.ts +8 -2
  30. package/dist/automation/cron-expr.d.ts +41 -0
  31. package/dist/automation/cron-expr.js +169 -0
  32. package/dist/automation/index.d.ts +41 -0
  33. package/dist/automation/index.js +39 -0
  34. package/dist/automation/runner.d.ts +84 -0
  35. package/dist/automation/runner.js +92 -0
  36. package/dist/automation/scheduler.d.ts +194 -0
  37. package/dist/automation/scheduler.js +623 -0
  38. package/dist/automation/store.d.ts +39 -0
  39. package/dist/automation/store.js +122 -0
  40. package/dist/automation/write-policy.d.ts +34 -0
  41. package/dist/automation/write-policy.js +113 -0
  42. package/dist/automation/write-run.d.ts +51 -0
  43. package/dist/automation/write-run.js +38 -0
  44. package/dist/capability-control/disabled-lists.d.ts +25 -0
  45. package/dist/capability-control/disabled-lists.js +57 -0
  46. package/dist/capability-control/index.d.ts +5 -0
  47. package/dist/capability-control/index.js +3 -0
  48. package/dist/capability-control/overlay.d.ts +64 -0
  49. package/dist/capability-control/overlay.js +116 -0
  50. package/dist/capability-control/project.d.ts +65 -0
  51. package/dist/capability-control/project.js +147 -0
  52. package/dist/capability-control/service.d.ts +70 -0
  53. package/dist/capability-control/service.js +147 -0
  54. package/dist/capability-control/types.d.ts +62 -0
  55. package/dist/capability-control/types.js +17 -0
  56. package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
  57. package/dist/cc-orchestrator/agent-adapter.js +133 -0
  58. package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
  59. package/dist/cc-orchestrator/cc-capability.js +53 -0
  60. package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
  61. package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
  62. package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
  63. package/dist/cc-orchestrator/codex-session-history.js +187 -0
  64. package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
  65. package/dist/cc-orchestrator/external-agent-changes.js +214 -0
  66. package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
  67. package/dist/cc-orchestrator/external-agent-driver.js +69 -0
  68. package/dist/cc-orchestrator/index.d.ts +8 -0
  69. package/dist/cc-orchestrator/index.js +8 -0
  70. package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
  71. package/dist/cc-orchestrator/relevance-judge.js +29 -0
  72. package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
  73. package/dist/cc-orchestrator/session-discovery.js +125 -0
  74. package/dist/cc-orchestrator/session-history.d.ts +19 -0
  75. package/dist/cc-orchestrator/session-history.js +67 -0
  76. package/dist/cli/agent-server-stdio.d.ts +26 -1
  77. package/dist/cli/agent-server-stdio.js +221 -28
  78. package/dist/cli/agent-server-tcp.d.ts +20 -0
  79. package/dist/cli/agent-server-tcp.js +134 -0
  80. package/dist/cli/graceful-shutdown.d.ts +27 -0
  81. package/dist/cli/graceful-shutdown.js +30 -0
  82. package/dist/context/compaction.d.ts +56 -0
  83. package/dist/context/compaction.js +209 -15
  84. package/dist/context/manager.d.ts +0 -20
  85. package/dist/context/manager.js +25 -41
  86. package/dist/cost-tracker.js +5 -61
  87. package/dist/credentials/cipher.d.ts +49 -0
  88. package/dist/credentials/cipher.js +45 -0
  89. package/dist/credentials/cookie-jar.d.ts +24 -0
  90. package/dist/credentials/cookie-jar.js +40 -0
  91. package/dist/credentials/index.d.ts +7 -0
  92. package/dist/credentials/index.js +5 -0
  93. package/dist/credentials/inject-credential-tool.d.ts +20 -0
  94. package/dist/credentials/inject-credential-tool.js +130 -0
  95. package/dist/credentials/store.d.ts +72 -0
  96. package/dist/credentials/store.js +184 -0
  97. package/dist/credentials/types.d.ts +56 -0
  98. package/dist/credentials/use-credential-tool.d.ts +29 -0
  99. package/dist/credentials/use-credential-tool.js +205 -0
  100. package/dist/credentials/use-gate.d.ts +56 -0
  101. package/dist/credentials/use-gate.js +52 -0
  102. package/dist/cron/cron-runtime.d.ts +2 -0
  103. package/dist/cron/cron-runtime.js +2 -0
  104. package/dist/cron/cron-store.d.ts +2 -0
  105. package/dist/cron/cron-store.js +2 -0
  106. package/dist/cron/scheduler.d.ts +5 -32
  107. package/dist/cron/scheduler.js +5 -113
  108. package/dist/data/model-metadata.d.ts +77 -0
  109. package/dist/data/model-metadata.js +56 -0
  110. package/dist/data/model-metadata.json +216 -0
  111. package/dist/data/openrouter-models.d.ts +18 -7
  112. package/dist/data/openrouter-models.js +35 -8
  113. package/dist/data/openrouter-sync.js +1 -1
  114. package/dist/engine/aux-key.d.ts +10 -0
  115. package/dist/engine/aux-key.js +11 -0
  116. package/dist/engine/dynamic-tool-defs.d.ts +19 -0
  117. package/dist/engine/dynamic-tool-defs.js +36 -0
  118. package/dist/engine/engine.d.ts +431 -108
  119. package/dist/engine/engine.js +1630 -279
  120. package/dist/engine/friendly-error.d.ts +18 -0
  121. package/dist/engine/friendly-error.js +63 -0
  122. package/dist/engine/goal.d.ts +187 -0
  123. package/dist/engine/goal.js +196 -0
  124. package/dist/engine/image-compression.d.ts +81 -0
  125. package/dist/engine/image-compression.js +186 -0
  126. package/dist/engine/image-policy.d.ts +165 -0
  127. package/dist/engine/image-policy.js +189 -0
  128. package/dist/engine/model-connections-pool.d.ts +17 -0
  129. package/dist/engine/model-connections-pool.js +66 -0
  130. package/dist/engine/model-facade.d.ts +10 -0
  131. package/dist/engine/model-facade.js +25 -0
  132. package/dist/engine/patch-orphaned-tools.js +3 -0
  133. package/dist/engine/reactive-threshold.d.ts +13 -0
  134. package/dist/engine/reactive-threshold.js +17 -0
  135. package/dist/engine/resolve-llm-config.d.ts +16 -0
  136. package/dist/engine/resolve-llm-config.js +44 -0
  137. package/dist/engine/runtime.js +9 -1
  138. package/dist/engine/sandbox-cache-key.d.ts +10 -0
  139. package/dist/engine/sandbox-cache-key.js +9 -0
  140. package/dist/engine/sandbox-config.d.ts +31 -0
  141. package/dist/engine/sandbox-config.js +38 -0
  142. package/dist/engine/session-title.d.ts +13 -0
  143. package/dist/engine/session-title.js +34 -0
  144. package/dist/engine/session-usage.d.ts +19 -0
  145. package/dist/engine/session-usage.js +25 -0
  146. package/dist/engine/steer-queue.d.ts +32 -0
  147. package/dist/engine/steer-queue.js +26 -0
  148. package/dist/engine/streaming-tool-queue.d.ts +12 -0
  149. package/dist/engine/streaming-tool-queue.js +50 -10
  150. package/dist/engine/turn-loop.d.ts +94 -9
  151. package/dist/engine/turn-loop.js +775 -342
  152. package/dist/engine/types.d.ts +175 -0
  153. package/dist/engine/types.js +13 -0
  154. package/dist/external-agents/config.d.ts +2 -0
  155. package/dist/external-agents/config.js +15 -0
  156. package/dist/external-agents/types.d.ts +31 -0
  157. package/dist/external-agents/types.js +1 -0
  158. package/dist/git/parse-log.d.ts +13 -0
  159. package/dist/git/parse-log.js +21 -0
  160. package/dist/git/utils.d.ts +8 -6
  161. package/dist/git/utils.js +62 -26
  162. package/dist/git/worktree.d.ts +48 -0
  163. package/dist/git/worktree.js +111 -20
  164. package/dist/hooks/events.d.ts +23 -1
  165. package/dist/hooks/goal-stop-hook.d.ts +58 -0
  166. package/dist/hooks/goal-stop-hook.js +279 -0
  167. package/dist/hooks/hook-output.d.ts +33 -0
  168. package/dist/hooks/hook-output.js +79 -0
  169. package/dist/hooks/registry.d.ts +15 -0
  170. package/dist/hooks/registry.js +57 -1
  171. package/dist/hooks/shell-runner.d.ts +2 -0
  172. package/dist/hooks/shell-runner.js +48 -18
  173. package/dist/index.d.ts +79 -11
  174. package/dist/index.js +89 -6
  175. package/dist/llm/capabilities/param-specs.d.ts +14 -0
  176. package/dist/llm/capabilities/param-specs.js +62 -0
  177. package/dist/llm/capabilities/reasoning-control.d.ts +24 -0
  178. package/dist/llm/capabilities/reasoning-control.js +38 -0
  179. package/dist/llm/capabilities/rules.js +37 -3
  180. package/dist/llm/capabilities/types.d.ts +32 -2
  181. package/dist/llm/clamp-max-tokens.d.ts +11 -0
  182. package/dist/llm/clamp-max-tokens.js +17 -0
  183. package/dist/llm/client-base.d.ts +69 -5
  184. package/dist/llm/client-base.js +185 -25
  185. package/dist/llm/client-factory.d.ts +3 -3
  186. package/dist/llm/client-factory.js +2 -2
  187. package/dist/llm/model-cache.js +4 -2
  188. package/dist/llm/model-pool.d.ts +29 -11
  189. package/dist/llm/model-pool.js +36 -20
  190. package/dist/llm/provider-auth.d.ts +41 -0
  191. package/dist/llm/provider-auth.js +76 -0
  192. package/dist/llm/provider-catalog.d.ts +6 -2
  193. package/dist/llm/providers/anthropic.d.ts +32 -2
  194. package/dist/llm/providers/anthropic.js +207 -18
  195. package/dist/llm/providers/openai.d.ts +47 -2
  196. package/dist/llm/providers/openai.js +478 -71
  197. package/dist/llm/reasoning-setting.d.ts +51 -0
  198. package/dist/llm/reasoning-setting.js +40 -0
  199. package/dist/llm/stop-reason.d.ts +13 -0
  200. package/dist/llm/stop-reason.js +21 -0
  201. package/dist/llm/stream-watchdog.js +5 -1
  202. package/dist/llm/strip-vision.d.ts +32 -0
  203. package/dist/llm/strip-vision.js +94 -0
  204. package/dist/llm/token-counter.js +9 -2
  205. package/dist/llm/types.d.ts +9 -6
  206. package/dist/logging/logger.js +18 -4
  207. package/dist/logging/sanitize-messages.d.ts +10 -0
  208. package/dist/logging/sanitize-messages.js +112 -0
  209. package/dist/lsp/client.js +28 -8
  210. package/dist/lsp/manager.d.ts +1 -1
  211. package/dist/lsp/manager.js +42 -11
  212. package/dist/lsp/root-path.d.ts +9 -0
  213. package/dist/lsp/root-path.js +12 -0
  214. package/dist/model-catalog/builtin.d.ts +12 -0
  215. package/dist/model-catalog/builtin.js +407 -0
  216. package/dist/model-catalog/gen-connections.d.ts +20 -0
  217. package/dist/model-catalog/gen-connections.js +28 -0
  218. package/dist/model-catalog/index.d.ts +41 -0
  219. package/dist/model-catalog/index.js +90 -0
  220. package/dist/model-catalog/params.d.ts +20 -0
  221. package/dist/model-catalog/params.js +45 -0
  222. package/dist/model-catalog/resolve.d.ts +48 -0
  223. package/dist/model-catalog/resolve.js +33 -0
  224. package/dist/model-catalog/save-entry.d.ts +32 -0
  225. package/dist/model-catalog/save-entry.js +104 -0
  226. package/dist/model-catalog/types.d.ts +561 -0
  227. package/dist/model-catalog/types.js +93 -0
  228. package/dist/model-catalog/upsert.d.ts +9 -0
  229. package/dist/model-catalog/upsert.js +8 -0
  230. package/dist/onboarding.d.ts +12 -82
  231. package/dist/onboarding.js +75 -333
  232. package/dist/plugins/gitOps.d.ts +53 -0
  233. package/dist/plugins/gitOps.js +130 -5
  234. package/dist/plugins/installer/checkUpdate.d.ts +16 -0
  235. package/dist/plugins/installer/checkUpdate.js +32 -0
  236. package/dist/plugins/installer/codex/convertAgents.d.ts +7 -0
  237. package/dist/plugins/installer/codex/convertAgents.js +55 -0
  238. package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
  239. package/dist/plugins/installer/codex/convertCommands.js +46 -0
  240. package/dist/plugins/installer/codex/convertMcp.d.ts +11 -0
  241. package/dist/plugins/installer/codex/convertMcp.js +85 -0
  242. package/dist/plugins/installer/codex/convertSkills.d.ts +12 -0
  243. package/dist/plugins/installer/codex/convertSkills.js +33 -0
  244. package/dist/plugins/installer/detectFormat.d.ts +2 -0
  245. package/dist/plugins/installer/detectFormat.js +6 -0
  246. package/dist/plugins/installer/install.d.ts +7 -0
  247. package/dist/plugins/installer/install.js +123 -0
  248. package/dist/plugins/installer/installFromArchive.d.ts +43 -0
  249. package/dist/plugins/installer/installFromArchive.js +134 -0
  250. package/dist/plugins/installer/installFromSource.d.ts +13 -0
  251. package/dist/plugins/installer/installFromSource.js +51 -0
  252. package/dist/plugins/installer/list.d.ts +9 -0
  253. package/dist/plugins/installer/list.js +30 -0
  254. package/dist/plugins/installer/loadPluginAgents.d.ts +3 -0
  255. package/dist/plugins/installer/loadPluginAgents.js +27 -0
  256. package/dist/plugins/installer/loadPluginMcp.d.ts +14 -0
  257. package/dist/plugins/installer/loadPluginMcp.js +107 -0
  258. package/dist/plugins/installer/parseSource.d.ts +20 -0
  259. package/dist/plugins/installer/parseSource.js +74 -0
  260. package/dist/plugins/installer/paths.d.ts +5 -0
  261. package/dist/plugins/installer/paths.js +25 -0
  262. package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
  263. package/dist/plugins/installer/pruneDisabled.js +73 -0
  264. package/dist/plugins/installer/types.d.ts +52 -0
  265. package/dist/plugins/installer/types.js +28 -0
  266. package/dist/plugins/installer/uninstall.d.ts +2 -0
  267. package/dist/plugins/installer/uninstall.js +18 -0
  268. package/dist/plugins/installer/unzip.d.ts +14 -0
  269. package/dist/plugins/installer/unzip.js +82 -0
  270. package/dist/plugins/installer/update.d.ts +28 -0
  271. package/dist/plugins/installer/update.js +97 -0
  272. package/dist/plugins/loadPluginHooks.d.ts +54 -1
  273. package/dist/plugins/loadPluginHooks.js +83 -1
  274. package/dist/plugins/marketplaceManager.d.ts +15 -1
  275. package/dist/plugins/marketplaceManager.js +58 -4
  276. package/dist/plugins/pluginCommandHook.js +34 -14
  277. package/dist/plugins/pluginContent.d.ts +30 -0
  278. package/dist/plugins/pluginContent.js +83 -0
  279. package/dist/plugins/pluginInstaller.d.ts +34 -0
  280. package/dist/plugins/pluginInstaller.js +168 -35
  281. package/dist/plugins/schemas.js +41 -6
  282. package/dist/plugins/types.d.ts +10 -0
  283. package/dist/preset/index.d.ts +7 -1
  284. package/dist/preset/index.js +112 -6
  285. package/dist/product/types.d.ts +1 -1
  286. package/dist/prompt/composer.d.ts +31 -0
  287. package/dist/prompt/composer.js +95 -25
  288. package/dist/prompt/instruction-scanner.js +5 -3
  289. package/dist/prompt/section-loader.js +1 -0
  290. package/dist/prompt/sections/base.md +1 -0
  291. package/dist/prompt/sections/browser.md +10 -0
  292. package/dist/prompt/sections/coding.md +4 -0
  293. package/dist/prompt/sections/orchestration.md +8 -0
  294. package/dist/protocol/chat-session-manager.d.ts +15 -2
  295. package/dist/protocol/chat-session-manager.js +46 -0
  296. package/dist/protocol/chat-session.d.ts +82 -0
  297. package/dist/protocol/chat-session.js +121 -1
  298. package/dist/protocol/client.d.ts +27 -0
  299. package/dist/protocol/client.js +38 -0
  300. package/dist/protocol/redact.d.ts +50 -0
  301. package/dist/protocol/redact.js +71 -0
  302. package/dist/protocol/server.d.ts +153 -2
  303. package/dist/protocol/server.js +807 -39
  304. package/dist/protocol/tcp-transport.d.ts +45 -0
  305. package/dist/protocol/tcp-transport.js +74 -0
  306. package/dist/protocol/transport.js +3 -2
  307. package/dist/protocol/types.d.ts +69 -0
  308. package/dist/protocol/types.js +22 -0
  309. package/dist/quota/credentials.d.ts +3 -0
  310. package/dist/quota/credentials.js +80 -0
  311. package/dist/quota/index.d.ts +36 -0
  312. package/dist/quota/index.js +155 -0
  313. package/dist/quota/types.d.ts +48 -0
  314. package/dist/quota/types.js +13 -0
  315. package/dist/remote/bridge.d.ts +11 -2
  316. package/dist/remote/bridge.js +61 -33
  317. package/dist/review/review-prompt.d.ts +28 -0
  318. package/dist/review/review-prompt.js +81 -0
  319. package/dist/run/ArtifactTracker.js +5 -4
  320. package/dist/run/EngineRunner.d.ts +27 -1
  321. package/dist/run/EngineRunner.js +46 -8
  322. package/dist/run/FileRunStore.js +40 -11
  323. package/dist/run/RunApprovalBackend.js +25 -5
  324. package/dist/run/RunLock.d.ts +28 -2
  325. package/dist/run/RunLock.js +49 -7
  326. package/dist/run/RunManager.d.ts +12 -0
  327. package/dist/run/RunManager.js +86 -3
  328. package/dist/run/RunQueue.d.ts +1 -0
  329. package/dist/run/RunQueue.js +8 -2
  330. package/dist/run/factory.d.ts +8 -1
  331. package/dist/run/factory.js +1 -0
  332. package/dist/run/index.d.ts +2 -2
  333. package/dist/run/index.js +1 -1
  334. package/dist/run/redirect-target.d.ts +7 -0
  335. package/dist/run/redirect-target.js +13 -0
  336. package/dist/run/types.js +1 -1
  337. package/dist/runtime/background-shell.d.ts +139 -0
  338. package/dist/runtime/background-shell.js +495 -0
  339. package/dist/runtime/output-clean.d.ts +24 -0
  340. package/dist/runtime/output-clean.js +41 -0
  341. package/dist/runtime/ring-file.d.ts +64 -0
  342. package/dist/runtime/ring-file.js +174 -0
  343. package/dist/runtime/safe-spawn.js +15 -34
  344. package/dist/runtime/spawn-common.d.ts +148 -0
  345. package/dist/runtime/spawn-common.js +303 -0
  346. package/dist/runtime/truncate-output.d.ts +22 -0
  347. package/dist/runtime/truncate-output.js +49 -0
  348. package/dist/runtime/utf8-cut.d.ts +11 -0
  349. package/dist/runtime/utf8-cut.js +23 -0
  350. package/dist/services/auto-dream.d.ts +4 -0
  351. package/dist/services/auto-dream.js +26 -26
  352. package/dist/services/browser-open.d.ts +13 -0
  353. package/dist/services/browser-open.js +16 -0
  354. package/dist/services/diagnostics.d.ts +1 -2
  355. package/dist/services/diagnostics.js +12 -7
  356. package/dist/services/dream-consolidation.d.ts +57 -0
  357. package/dist/services/dream-consolidation.js +151 -0
  358. package/dist/services/extract-memories.d.ts +14 -1
  359. package/dist/services/extract-memories.js +45 -6
  360. package/dist/services/memory-orchestrator.d.ts +21 -0
  361. package/dist/services/memory-orchestrator.js +125 -32
  362. package/dist/services/notifier.d.ts +8 -0
  363. package/dist/services/notifier.js +39 -25
  364. package/dist/services/oauth.js +5 -7
  365. package/dist/services/session-memory-sort.d.ts +8 -0
  366. package/dist/services/session-memory-sort.js +9 -0
  367. package/dist/services/session-memory.js +30 -19
  368. package/dist/session/file-history.d.ts +124 -1
  369. package/dist/session/file-history.js +232 -9
  370. package/dist/session/memory.d.ts +116 -2
  371. package/dist/session/memory.js +250 -28
  372. package/dist/session/session-manager.d.ts +63 -1
  373. package/dist/session/session-manager.js +186 -5
  374. package/dist/session/simple-diff.d.ts +23 -0
  375. package/dist/session/simple-diff.js +84 -0
  376. package/dist/session/transcript.d.ts +25 -1
  377. package/dist/session/transcript.js +35 -2
  378. package/dist/session/undo-target.d.ts +67 -0
  379. package/dist/session/undo-target.js +144 -0
  380. package/dist/settings/disk-defaults.d.ts +42 -0
  381. package/dist/settings/disk-defaults.js +33 -0
  382. package/dist/settings/feature-flags.d.ts +64 -0
  383. package/dist/settings/feature-flags.js +61 -0
  384. package/dist/settings/manager.d.ts +101 -1
  385. package/dist/settings/manager.js +345 -15
  386. package/dist/settings/migrate-config.d.ts +45 -0
  387. package/dist/settings/migrate-config.js +125 -0
  388. package/dist/settings/personalization.d.ts +19 -0
  389. package/dist/settings/personalization.js +7 -0
  390. package/dist/settings/schema-export.d.ts +25 -0
  391. package/dist/settings/schema-export.js +38 -0
  392. package/dist/settings/schema.d.ts +1827 -396
  393. package/dist/settings/schema.js +361 -81
  394. package/dist/skills/scanner.d.ts +9 -0
  395. package/dist/skills/scanner.js +30 -2
  396. package/dist/stt/resolve-transcribe.d.ts +31 -0
  397. package/dist/stt/resolve-transcribe.js +108 -0
  398. package/dist/stt/transcribe.d.ts +51 -0
  399. package/dist/stt/transcribe.js +65 -0
  400. package/dist/tool-system/browser-bridge.d.ts +226 -0
  401. package/dist/tool-system/browser-bridge.js +163 -0
  402. package/dist/tool-system/builtin/add-marketplace.d.ts +12 -0
  403. package/dist/tool-system/builtin/add-marketplace.js +76 -0
  404. package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
  405. package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
  406. package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
  407. package/dist/tool-system/builtin/agent-notifications.js +9 -3
  408. package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
  409. package/dist/tool-system/builtin/agent-output-file.js +72 -0
  410. package/dist/tool-system/builtin/agent-registry.d.ts +23 -0
  411. package/dist/tool-system/builtin/agent-registry.js +16 -4
  412. package/dist/tool-system/builtin/agent.d.ts +50 -11
  413. package/dist/tool-system/builtin/agent.js +576 -73
  414. package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
  415. package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
  416. package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
  417. package/dist/tool-system/builtin/apply-patch/index.js +7 -3
  418. package/dist/tool-system/builtin/arena.js +6 -7
  419. package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
  420. package/dist/tool-system/builtin/background-jobs.js +124 -0
  421. package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
  422. package/dist/tool-system/builtin/background-shell-tools.js +108 -0
  423. package/dist/tool-system/builtin/background-work.d.ts +67 -0
  424. package/dist/tool-system/builtin/background-work.js +86 -0
  425. package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
  426. package/dist/tool-system/builtin/bash-output-style.js +40 -0
  427. package/dist/tool-system/builtin/bash.d.ts +5 -2
  428. package/dist/tool-system/builtin/bash.js +98 -62
  429. package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
  430. package/dist/tool-system/builtin/browser-tools.js +312 -0
  431. package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
  432. package/dist/tool-system/builtin/cancel-goal.js +64 -0
  433. package/dist/tool-system/builtin/check-quota.d.ts +15 -0
  434. package/dist/tool-system/builtin/check-quota.js +34 -0
  435. package/dist/tool-system/builtin/complete-goal.d.ts +25 -0
  436. package/dist/tool-system/builtin/complete-goal.js +45 -0
  437. package/dist/tool-system/builtin/config.js +7 -0
  438. package/dist/tool-system/builtin/cron.d.ts +7 -0
  439. package/dist/tool-system/builtin/cron.js +105 -9
  440. package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
  441. package/dist/tool-system/builtin/drive-claude-code.js +157 -0
  442. package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
  443. package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
  444. package/dist/tool-system/builtin/edit.d.ts +2 -1
  445. package/dist/tool-system/builtin/edit.js +21 -12
  446. package/dist/tool-system/builtin/eol.d.ts +29 -0
  447. package/dist/tool-system/builtin/eol.js +37 -0
  448. package/dist/tool-system/builtin/file-cache.d.ts +6 -0
  449. package/dist/tool-system/builtin/file-cache.js +8 -0
  450. package/dist/tool-system/builtin/generate-image.d.ts +60 -0
  451. package/dist/tool-system/builtin/generate-image.js +374 -0
  452. package/dist/tool-system/builtin/generate-video.d.ts +55 -0
  453. package/dist/tool-system/builtin/generate-video.js +361 -0
  454. package/dist/tool-system/builtin/grep.js +6 -2
  455. package/dist/tool-system/builtin/image-providers.d.ts +86 -0
  456. package/dist/tool-system/builtin/image-providers.js +190 -0
  457. package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
  458. package/dist/tool-system/builtin/image-uploader.js +74 -0
  459. package/dist/tool-system/builtin/index.d.ts +24 -1
  460. package/dist/tool-system/builtin/index.js +310 -25
  461. package/dist/tool-system/builtin/mcp-tools.js +23 -3
  462. package/dist/tool-system/builtin/memory.js +45 -7
  463. package/dist/tool-system/builtin/notebook-edit.d.ts +2 -1
  464. package/dist/tool-system/builtin/notebook-edit.js +1 -1
  465. package/dist/tool-system/builtin/powershell.js +4 -1
  466. package/dist/tool-system/builtin/read.d.ts +2 -1
  467. package/dist/tool-system/builtin/read.js +11 -3
  468. package/dist/tool-system/builtin/repl.js +4 -1
  469. package/dist/tool-system/builtin/skill.js +9 -0
  470. package/dist/tool-system/builtin/sleep.js +12 -5
  471. package/dist/tool-system/builtin/task.js +4 -1
  472. package/dist/tool-system/builtin/tool-search.js +25 -7
  473. package/dist/tool-system/builtin/update-automation-memory.d.ts +24 -0
  474. package/dist/tool-system/builtin/update-automation-memory.js +60 -0
  475. package/dist/tool-system/builtin/video-providers.d.ts +154 -0
  476. package/dist/tool-system/builtin/video-providers.js +235 -0
  477. package/dist/tool-system/builtin/view-image.d.ts +18 -0
  478. package/dist/tool-system/builtin/view-image.js +96 -0
  479. package/dist/tool-system/builtin/web-fetch.js +12 -2
  480. package/dist/tool-system/builtin/web-search.d.ts +4 -1
  481. package/dist/tool-system/builtin/web-search.js +57 -10
  482. package/dist/tool-system/builtin/worktree.d.ts +2 -1
  483. package/dist/tool-system/builtin/worktree.js +31 -4
  484. package/dist/tool-system/builtin/write.d.ts +2 -1
  485. package/dist/tool-system/builtin/write.js +1 -1
  486. package/dist/tool-system/context.d.ts +166 -6
  487. package/dist/tool-system/executor.d.ts +3 -2
  488. package/dist/tool-system/executor.js +197 -119
  489. package/dist/tool-system/investigation-guard.d.ts +4 -1
  490. package/dist/tool-system/investigation-guard.js +20 -4
  491. package/dist/tool-system/mcp-manager.d.ts +78 -16
  492. package/dist/tool-system/mcp-manager.js +357 -28
  493. package/dist/tool-system/path-policy.d.ts +99 -0
  494. package/dist/tool-system/path-policy.js +578 -0
  495. package/dist/tool-system/permission.d.ts +36 -1
  496. package/dist/tool-system/permission.js +322 -117
  497. package/dist/tool-system/plan-mode-allowlist.d.ts +32 -0
  498. package/dist/tool-system/plan-mode-allowlist.js +65 -0
  499. package/dist/tool-system/registry.d.ts +1 -0
  500. package/dist/tool-system/registry.js +26 -1
  501. package/dist/tool-system/sandbox/index.d.ts +8 -0
  502. package/dist/tool-system/sandbox/index.js +7 -2
  503. package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
  504. package/dist/tool-system/validate-tool-metadata.js +63 -0
  505. package/dist/tool-system/validation.d.ts +10 -0
  506. package/dist/tool-system/validation.js +16 -3
  507. package/dist/types.d.ts +301 -15
  508. package/dist/updater.js +20 -9
  509. package/dist/utils/envUtils.d.ts +0 -9
  510. package/dist/utils/envUtils.js +3 -28
  511. package/dist/utils/exec.d.ts +40 -0
  512. package/dist/utils/exec.js +144 -0
  513. package/dist/utils/format.js +4 -2
  514. package/dist/utils/json.d.ts +12 -0
  515. package/dist/utils/json.js +92 -0
  516. package/dist/utils/lockfile.js +9 -2
  517. package/dist/utils/theme.d.ts +7 -1
  518. package/dist/utils/theme.js +5 -3
  519. package/dist/utils/toolDisplay.js +0 -1
  520. package/package.json +14 -7
  521. package/dist/agent/coordinator.d.ts +0 -49
  522. package/dist/agent/coordinator.js +0 -77
  523. package/dist/settings/manager.test.js +0 -73
  524. package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
  525. package/dist/tool-system/builtin/remote-trigger.js +0 -54
  526. package/dist/tool-system/builtin/send-message.d.ts +0 -6
  527. package/dist/tool-system/builtin/send-message.js +0 -47
  528. /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
@@ -1,9 +1,31 @@
1
1
  /**
2
2
  * Git worktree management — create/remove isolated worktrees for agents.
3
3
  */
4
- import { execSync } from "node:child_process";
4
+ import { execFileSync } from "node:child_process";
5
5
  import { existsSync, symlinkSync, lstatSync } from "node:fs";
6
- import { join, resolve } from "node:path";
6
+ import { join, resolve, dirname } from "node:path";
7
+ import { safeSpawnShell } from "../runtime/safe-spawn.js";
8
+ import { buildSandboxEnv, mergeShellEnv, defaultShellBinary } from "../runtime/spawn-common.js";
9
+ import { resolveExecutable } from "../utils/exec.js";
10
+ // git resolved via PATH×PATHEXT on Windows (.cmd/.exe shim); no-op on POSIX.
11
+ const GIT_BIN = resolveExecutable("git");
12
+ /**
13
+ * Pick the setup/cleanup script for the running platform, falling back to
14
+ * `default`. Empty/whitespace-only scripts are treated as absent so a project
15
+ * can leave a platform key blank without spawning an empty shell. `platform`
16
+ * defaults to `process.platform` so callers usually omit it; tests pass a
17
+ * fixed value.
18
+ */
19
+ export function selectPlatformScript(scripts, platform = process.platform) {
20
+ if (!scripts)
21
+ return undefined;
22
+ const key = platform === "darwin" ? "macos" : platform === "win32" ? "windows" : "linux";
23
+ // A blank platform key shouldn't shadow a real `default` — fall through.
24
+ const platformScript = scripts[key]?.trim() ? scripts[key] : undefined;
25
+ const candidate = platformScript ?? scripts.default;
26
+ const trimmed = candidate?.trim();
27
+ return trimmed ? candidate : undefined;
28
+ }
7
29
  /**
8
30
  * Validate worktree slug to prevent path traversal attacks.
9
31
  */
@@ -19,7 +41,7 @@ export function validateWorktreeSlug(slug) {
19
41
  * Find the canonical git root (resolves worktree → main repo).
20
42
  */
21
43
  export function findGitRoot(cwd) {
22
- return execSync("git rev-parse --show-toplevel", { cwd, encoding: "utf-8", timeout: 5000 }).trim();
44
+ return execFileSync(GIT_BIN, ["rev-parse", "--show-toplevel"], { cwd, encoding: "utf-8", timeout: 5000 }).trim();
23
45
  }
24
46
  /**
25
47
  * Create an isolated git worktree for an agent session.
@@ -32,7 +54,7 @@ export function createWorktree(cwd, slug, sessionId) {
32
54
  // Get current branch for later reference
33
55
  let originalBranch;
34
56
  try {
35
- originalBranch = execSync("git branch --show-current", {
57
+ originalBranch = execFileSync(GIT_BIN, ["branch", "--show-current"], {
36
58
  cwd: gitRoot,
37
59
  encoding: "utf-8",
38
60
  timeout: 5000,
@@ -41,8 +63,10 @@ export function createWorktree(cwd, slug, sessionId) {
41
63
  catch {
42
64
  // Detached HEAD
43
65
  }
44
- // Create the worktree
45
- execSync(`git worktree add -b "${branchName}" "${worktreePath}"`, {
66
+ // Create the worktree. Pre-fix this used a quoted command string; the argv
67
+ // form keeps branchName/worktreePath as literal positional arguments even
68
+ // if a future caller bypasses validateWorktreeSlug.
69
+ execFileSync(GIT_BIN, ["worktree", "add", "-b", branchName, worktreePath], {
46
70
  cwd: gitRoot,
47
71
  timeout: 30000,
48
72
  });
@@ -58,30 +82,91 @@ export function createWorktree(cwd, slug, sessionId) {
58
82
  createdAt: Date.now(),
59
83
  };
60
84
  }
85
+ /**
86
+ * Run a project's `localEnvironment.setupScripts` once, in the freshly-created
87
+ * worktree's root, right after `git worktree add`. This mirrors Codex's
88
+ * local-environment semantics: setup belongs to the *worktree* lifecycle, not
89
+ * the conversation — it runs when the isolated copy is born so e.g. `bun
90
+ * install` or `cp .env.example .env` happens before the agent works there.
91
+ *
92
+ * Failure is non-fatal by design (Beta decision 2026-06-08, "警告但继续"): a
93
+ * broken setup script shouldn't strand the agent outside a worktree it already
94
+ * created. The caller surfaces `output` as a warning and proceeds. cleanup
95
+ * scripts are intentionally NOT auto-run on exit (same decision).
96
+ *
97
+ * Reuses the same sandbox + env primitives as the Bash tool so the setup
98
+ * command sees the project's `localEnvironment.env` and runs under the same
99
+ * isolation the agent's later commands will.
100
+ */
101
+ export async function runWorktreeSetup(worktreePath, script, opts = {}) {
102
+ const trimmed = script?.trim();
103
+ if (!trimmed)
104
+ return { skipped: true, ok: true, output: "" };
105
+ const shell = defaultShellBinary();
106
+ const backend = opts.sandbox;
107
+ const baseEnv = backend && backend.name !== "off" ? buildSandboxEnv() : { ...process.env };
108
+ const env = mergeShellEnv(baseEnv, opts.shellEnv);
109
+ const result = await safeSpawnShell(trimmed, {
110
+ cwd: worktreePath,
111
+ env,
112
+ timeoutMs: opts.timeoutMs ?? 120_000,
113
+ maxOutputBytes: 1024 * 1024,
114
+ sandbox: backend,
115
+ shell,
116
+ signal: opts.signal,
117
+ });
118
+ const parts = [];
119
+ if (result.stdout)
120
+ parts.push(result.stdout);
121
+ if (result.stderr)
122
+ parts.push(result.stderr);
123
+ const output = parts.join("\n").trim();
124
+ if (result.aborted)
125
+ return { skipped: false, ok: false, output: output || "setup aborted" };
126
+ if (result.timedOut)
127
+ return { skipped: false, ok: false, output: output || "setup timed out" };
128
+ if (result.spawnFailed) {
129
+ return { skipped: false, ok: false, output: result.error ?? "failed to spawn setup script" };
130
+ }
131
+ return { skipped: false, ok: result.exitCode === 0, output, exitCode: result.exitCode };
132
+ }
61
133
  /**
62
134
  * Remove a worktree and optionally its branch.
63
135
  */
64
136
  export function removeWorktree(worktreePath, removeBranch = false) {
65
137
  try {
66
- const gitRoot = findGitRoot(worktreePath);
67
- execSync(`git worktree remove "${worktreePath}" --force`, {
68
- cwd: gitRoot,
69
- timeout: 30000,
70
- });
138
+ // The MAIN repo root, not the worktree's own toplevel. `git rev-parse
139
+ // --show-toplevel` from inside a worktree returns the worktree path, which
140
+ // is about to be deleted; the branch-delete must run from the main repo,
141
+ // which outlives the worktree. Derive it from the common git dir.
142
+ const commonDir = execFileSync(GIT_BIN, ["rev-parse", "--path-format=absolute", "--git-common-dir"], { cwd: worktreePath, encoding: "utf-8", timeout: 5000 }).trim();
143
+ const mainRoot = dirname(commonDir); // <main>/.git → <main>
144
+ // Capture the worktree's branch BEFORE removing the worktree — afterwards
145
+ // the directory is gone and `git branch --show-current` in it would fail
146
+ // (silently, leaving removeBranch a no-op).
147
+ let branch = "";
71
148
  if (removeBranch) {
72
- // Extract branch name from worktree
73
149
  try {
74
- const branch = execSync("git branch --show-current", {
150
+ branch = execFileSync(GIT_BIN, ["branch", "--show-current"], {
75
151
  cwd: worktreePath,
76
152
  encoding: "utf-8",
77
153
  timeout: 5000,
78
154
  }).trim();
79
- if (branch.startsWith("worktree/")) {
80
- execSync(`git branch -D "${branch}"`, { cwd: gitRoot, timeout: 10000 });
81
- }
82
155
  }
83
156
  catch {
84
- // Branch might already be removed
157
+ // Detached HEAD or unreadable — nothing to delete.
158
+ }
159
+ }
160
+ execFileSync(GIT_BIN, ["worktree", "remove", worktreePath, "--force"], {
161
+ cwd: mainRoot,
162
+ timeout: 30000,
163
+ });
164
+ if (removeBranch && branch.startsWith("worktree/")) {
165
+ try {
166
+ execFileSync(GIT_BIN, ["branch", "-D", branch], { cwd: mainRoot, timeout: 10000 });
167
+ }
168
+ catch {
169
+ // Branch might already be removed.
85
170
  }
86
171
  }
87
172
  }
@@ -93,7 +178,7 @@ export function removeWorktree(worktreePath, removeBranch = false) {
93
178
  * List active worktrees.
94
179
  */
95
180
  export function listWorktrees(cwd) {
96
- const raw = execSync("git worktree list --porcelain", {
181
+ const raw = execFileSync(GIT_BIN, ["worktree", "list", "--porcelain"], {
97
182
  cwd,
98
183
  encoding: "utf-8",
99
184
  timeout: 10000,
@@ -124,15 +209,21 @@ export function listWorktrees(cwd) {
124
209
  */
125
210
  function symlinkLargeDirectories(sourceRoot, worktreePath) {
126
211
  const largeDirs = ["node_modules", ".venv", "vendor", ".pnpm-store"];
212
+ // Windows directory symlinks need admin/Developer Mode and throw EPERM for a
213
+ // normal user; NTFS junctions don't and behave the same for our purpose
214
+ // (share node_modules into the worktree). Use "junction" on win32, "dir"
215
+ // elsewhere. Failure stays non-fatal — the worktree just doesn't share dirs.
216
+ const linkType = process.platform === "win32" ? "junction" : "dir";
127
217
  for (const dir of largeDirs) {
128
218
  const source = join(sourceRoot, dir);
129
219
  const target = join(worktreePath, dir);
130
220
  if (existsSync(source) && lstatSync(source).isDirectory() && !existsSync(target)) {
131
221
  try {
132
- symlinkSync(source, target, "dir");
222
+ symlinkSync(source, target, linkType);
133
223
  }
134
224
  catch {
135
- // Symlink might fail on some systems
225
+ // Symlink/junction might fail on some systems — non-fatal, the
226
+ // worktree just won't share this directory (more disk, still works).
136
227
  }
137
228
  }
138
229
  }
@@ -23,6 +23,21 @@
23
23
  * may return `messages` to inject a
24
24
  * per-turn reminder appended to the
25
25
  * conversation right before the model call.
26
+ * - on_stop (turn-loop.ts) — fires when the model
27
+ * returns no tool calls and the loop is
28
+ * about to return reason "completed". A
29
+ * handler returning `continueSession: true`
30
+ * (with `messages`) BLOCKS termination:
31
+ * the messages are injected as a
32
+ * <system-reminder> and the loop runs
33
+ * another turn instead of stopping. This
34
+ * is the seam Goal mode uses (see
35
+ * goal-stop-hook.ts). Bounded by a
36
+ * consecutive-block cap (maxStopBlocks)
37
+ * and maxTurns. ctx.data carries `goal`,
38
+ * `finalText`, `turnCount`. Distinct from
39
+ * HookResult.stop, which controls the hook
40
+ * CHAIN, not agent termination.
26
41
  * - pre_tool_use / post_tool_use (executor.ts) — pre_tool_use honors
27
42
  * `decision: "deny"` to short-circuit
28
43
  * the call (executor.ts:131).
@@ -72,7 +87,7 @@
72
87
  * ContextManager; current implementation only knows
73
88
  * after-the-fact (use post_compact instead).
74
89
  */
75
- export type HookEventName = "on_agent_start" | "on_agent_end" | "on_turn_start" | "on_turn_end" | "on_tool_start" | "on_tool_end" | "on_permission_check" | "on_session_start" | "on_session_end" | "pre_tool_use" | "post_tool_use" | "user_prompt_submit" | "pre_compact" | "post_compact" | "file_changed" | "notification";
90
+ export type HookEventName = "on_agent_start" | "on_agent_end" | "on_turn_start" | "on_turn_end" | "on_stop" | "on_tool_start" | "on_tool_end" | "on_permission_check" | "on_session_start" | "on_session_end" | "pre_tool_use" | "post_tool_use" | "user_prompt_submit" | "pre_compact" | "post_compact" | "file_changed" | "notification";
76
91
  export interface HookContext {
77
92
  eventName: HookEventName;
78
93
  data: Record<string, unknown>;
@@ -82,6 +97,13 @@ export interface HookContext {
82
97
  export interface HookResult {
83
98
  /** If true, stop the hook chain */
84
99
  stop?: boolean;
100
+ /**
101
+ * For on_stop: if true, BLOCK agent termination — the loop injects this
102
+ * result's `messages` and runs another turn instead of returning
103
+ * "completed". Distinct from `stop` (which only short-circuits the hook
104
+ * chain). Ignored for non-on_stop events. Bounded by maxStopBlocks.
105
+ */
106
+ continueSession?: boolean;
85
107
  /** Modified data to pass along */
86
108
  data?: Record<string, unknown>;
87
109
  /** Additional messages to inject */
@@ -0,0 +1,58 @@
1
+ import type { HookHandler } from "./registry.js";
2
+ import type { LLMResponse } from "../types.js";
3
+ import { type GoalConfig } from "../engine/goal.js";
4
+ /** Narrow LLM surface the judge needs — just a one-shot completion. */
5
+ export interface GoalJudgeLLM {
6
+ createMessage(options: {
7
+ systemPrompt: string;
8
+ messages: {
9
+ role: "user" | "assistant" | "system";
10
+ content: string;
11
+ }[];
12
+ stream?: boolean;
13
+ maxTokens?: number;
14
+ recordUsage?: boolean;
15
+ signal?: AbortSignal;
16
+ /** Reasoning control — the judge always asks for it OFF (see call site). */
17
+ reasoning?: import("../llm/reasoning-setting.js").ReasoningSetting;
18
+ }): Promise<LLMResponse>;
19
+ }
20
+ interface GoalLogger {
21
+ info: (msg: string, data?: Record<string, unknown>) => void;
22
+ warn: (msg: string, data?: Record<string, unknown>) => void;
23
+ error: (msg: string, data?: Record<string, unknown>) => void;
24
+ }
25
+ export interface GoalStopHookOptions {
26
+ llm: GoalJudgeLLM;
27
+ log: GoalLogger;
28
+ /** Override the goal instead of reading ctx.data.goal (mainly for tests). */
29
+ goal?: string | GoalConfig;
30
+ /**
31
+ * Re-check whether the session STILL has a live persisted goal, evaluated
32
+ * fresh each time the hook fires. The hook's `goal` above is frozen at
33
+ * creation, so a goal cleared mid-run (user hit 清除 while a long-lived
34
+ * run kept going) would otherwise be judged forever off the stale copy —
35
+ * the unregister path in Engine.clearGoal only fires for the one in-flight
36
+ * hook it tracks, which misses automation / resumed runs. When this returns
37
+ * false the hook allows the stop immediately without calling the judge.
38
+ * Injectable (reads SessionManager on the engine); omit to disable the
39
+ * re-check (tests / non-persistent callers).
40
+ */
41
+ isGoalActive?: (sessionId: string) => boolean;
42
+ /**
43
+ * Called once when the judge first returns met:true, before this handler
44
+ * returns. The engine uses it to clear the session's persisted activeGoal so
45
+ * a later bare send doesn't re-inherit a satisfied goal. Optional so tests /
46
+ * non-persistent callers can omit it.
47
+ */
48
+ onMet?: () => void;
49
+ /**
50
+ * Clock source for the current time fed to the judge. Injectable so tests
51
+ * pin a fixed instant (the judge prompt is a fresh sub-call, not part of the
52
+ * cached prefix, so a live clock here has no cache cost). Defaults to
53
+ * `() => new Date()`.
54
+ */
55
+ now?: () => Date;
56
+ }
57
+ export declare function createGoalStopHook(opts: GoalStopHookOptions): HookHandler;
58
+ export {};
@@ -0,0 +1,279 @@
1
+ import { normalizeGoal } from "../engine/goal.js";
2
+ import { listRunningBackgroundWork } from "../tool-system/builtin/background-work.js";
3
+ /**
4
+ * Render the current instant for the judge: a human-readable local time plus
5
+ * the numeric UTC offset and IANA zone, so the judge can reason about a
6
+ * wall-clock deadline written into the objective (e.g. "until 12:00"). An LLM
7
+ * has no clock — without this line it can never tell whether a time cutoff has
8
+ * passed. Falls back gracefully if Intl is unavailable.
9
+ */
10
+ function renderNow(now) {
11
+ const iso = now.toISOString(); // unambiguous UTC anchor
12
+ try {
13
+ const zone = Intl.DateTimeFormat().resolvedOptions().timeZone;
14
+ // e.g. "2026-07-01 12:11:32 GMT+8"
15
+ const local = now.toLocaleString("sv-SE", {
16
+ timeZoneName: "short",
17
+ });
18
+ return `${local} (时区 ${zone};UTC 基准 ${iso})`;
19
+ }
20
+ catch {
21
+ return iso;
22
+ }
23
+ }
24
+ const JUDGE_SYSTEM = "你是一个目标完成度裁判。给定一个目标、agent 最近的输出,以及当前在后台运行的任务清单," +
25
+ "判断目标状态。只返回一个 JSON 对象,形如 " +
26
+ '{"met": true|false, "waiting": true|false, "gaps": "若未达成,简述还差什么;达成则空串"}。' +
27
+ "三态语义:" +
28
+ "(1) met:true —— 目标已完全达成。" +
29
+ "(2) waiting:true —— 目标尚未达成,但剩下唯一要做的事就是等一个【会结束的】后台任务完成" +
30
+ "(如下载、视频渲染、会退出的脚本),它完成后系统会自动唤醒你继续。此时应允许停下来等。" +
31
+ "(3) 两者皆 false —— 目标未达成,且还有你能【主动去做】的事。" +
32
+ "关键:【常驻服务】(如 dev server、watch、`npm run dev`/`bun run dev` 这类永不退出的进程)" +
33
+ "不算‘在等的任务’——它永远在跑,目标若不依赖它就照常判断达成与否,绝不要因为它而返回 waiting。" +
34
+ "时间截止:若目标里写了明确的时间截止(如“到 12:00 停”“until 15:00”“干到今晚 22 点”)," +
35
+ "你会拿到【当前时间】(含时区),据此自行判断截止时刻是否已到、目标是否应当结束;解读截止以【当前时间】所在时区为准。" +
36
+ "关键——解读【相对/不完整的时间】(如只说“3点”“今晚”而没写日期):以【目标设定时间】为基准," +
37
+ "取其之后【最近的那个】时点。例如目标设定于 07-01 23:00、说“做到3点”,那就是 07-02 03:00;" +
38
+ "设定于 10:00、说“做到3点”,那就是当天 15:00(下午3点,设定后最近的3点)。" +
39
+ "绝不要因为“当前时间已过那个钟点”就把它顺延到第二天——只要当前时间已过【据设定时间算出的】截止时刻,就应当结束。" +
40
+ "(未提供【目标设定时间】时,退回仅凭当前时间按常理推断。)" +
41
+ "目标没有时间截止时,忽略当前时间,照常按内容判断。" +
42
+ "不要输出任何额外文字。宁可严格:只有确信目标已完全完成时才返回 met:true。";
43
+ /** Pull the first balanced JSON object out of possibly-prose text. */
44
+ function extractJson(text) {
45
+ const start = text.indexOf("{");
46
+ const end = text.lastIndexOf("}");
47
+ if (start === -1 || end === -1 || end <= start)
48
+ return null;
49
+ const slice = text.slice(start, end + 1);
50
+ try {
51
+ const parsed = JSON.parse(slice);
52
+ if (!parsed || typeof parsed !== "object")
53
+ return null;
54
+ const p = parsed;
55
+ if (typeof p.met !== "boolean")
56
+ return null;
57
+ const gaps = typeof p.gaps === "string" ? p.gaps : "";
58
+ const waiting = typeof p.waiting === "boolean" ? p.waiting : false;
59
+ return { met: p.met, waiting, gaps };
60
+ }
61
+ catch {
62
+ return null;
63
+ }
64
+ }
65
+ /** Render the running background tasks for the judge prompt. */
66
+ function renderBackgroundTasks(items) {
67
+ if (items.length === 0)
68
+ return "(无)";
69
+ const kindLabel = {
70
+ subagent: "后台子代理",
71
+ job: "后台任务",
72
+ shell: "后台命令",
73
+ };
74
+ return items
75
+ .map((i) => {
76
+ // A listening port strongly implies a long-lived service (dev server) —
77
+ // tell the judge so it doesn't classify it as a finite task to wait on.
78
+ const portNote = i.detectedPort != null
79
+ ? `(在 :${i.detectedPort} 监听端口,疑似常驻服务)`
80
+ : "";
81
+ return `- [${kindLabel[i.kind] ?? i.kind}] ${i.description}${portNote}`;
82
+ })
83
+ .join("\n");
84
+ }
85
+ export function createGoalStopHook(opts) {
86
+ const { llm, log } = opts;
87
+ const now = opts.now ?? (() => new Date());
88
+ // Per-run cache: if the model emits the same final text with the same set of
89
+ // running background tasks twice in a row (it stalls repeating itself), the
90
+ // verdict can't have changed — reuse it instead of paying for another judge
91
+ // call. Keyed on (finalText + rendered task list); a `met` verdict is never
92
+ // cached (it ends the run anyway and triggers the onMet side-effect).
93
+ let lastKey = null;
94
+ let lastResult = null;
95
+ return async (ctx) => {
96
+ // Accept string or GoalConfig from either the override or ctx.data.goal.
97
+ const g = normalizeGoal(opts.goal ?? ctx.data.goal);
98
+ // No goal → not Goal mode → allow stop.
99
+ if (!g)
100
+ return {};
101
+ const goal = g.objective;
102
+ const sessionId = ctx.data.sessionId;
103
+ // Re-check the LIVE goal each turn. `goal` above is frozen at hook creation,
104
+ // so a goal cleared mid-run (清除) on a long-lived run (automation / resumed)
105
+ // would keep being judged off the stale copy — Engine.clearGoal's unregister
106
+ // only reaches the single in-flight hook it tracks. If the persisted goal is
107
+ // gone, allow the stop now and skip the judge call entirely.
108
+ if (opts.isGoalActive &&
109
+ typeof sessionId === "string" &&
110
+ sessionId.length > 0 &&
111
+ !opts.isGoalActive(sessionId)) {
112
+ log.info("goal_stop.cleared_midrun", { cat: "goal" });
113
+ return {};
114
+ }
115
+ // Background work is no longer a mechanical short-circuit. Instead we list
116
+ // what's running and let the judge decide (s-mqe0ox7n-a8d11c26 bug): a
117
+ // boolean "has background work" can't tell a finite download/render (→ wait
118
+ // for the wakeup, allow stop) from a never-ending dev server (→ judge the
119
+ // goal normally). The judge sees each task's kind + command and returns a
120
+ // three-state verdict; `waiting:true` allows the stop without pushing.
121
+ const runningWork = typeof sessionId === "string" && sessionId.length > 0
122
+ ? listRunningBackgroundWork(sessionId)
123
+ : [];
124
+ const backgroundTasks = renderBackgroundTasks(runningWork);
125
+ const finalText = typeof ctx.data.finalText === "string" ? ctx.data.finalText : "";
126
+ const nowDate = now();
127
+ const nowLabel = renderNow(nowDate);
128
+ // The goal-set instant (when the user last set/replaced this goal), used by
129
+ // the judge to anchor relative deadlines ("做到3点"). renderNow renders any
130
+ // instant, not just "now". Absent for pre-field goals → line omitted, judge
131
+ // falls back to reasoning from current time alone.
132
+ const setAtLabel = typeof g.setAtMs === "number" && g.setAtMs > 0
133
+ ? renderNow(new Date(g.setAtMs))
134
+ : undefined;
135
+ // Verdict cache key: same goal + same final text + same running tasks +
136
+ // same MINUTE ⇒ verdict unchanged; skip the LLM call and replay it.
137
+ // The minute bucket is in the key on purpose: if a goal has a wall-clock
138
+ // deadline and the model stalls repeating identical output, a time-blind
139
+ // key would replay a stale "not met" forever and the deadline would never
140
+ // fire. Bucketing to the minute still absorbs same-minute repeats while
141
+ // re-judging once the clock advances past a cutoff.
142
+ const minuteBucket = nowDate.toISOString().slice(0, 16);
143
+ const cacheKey = `${goal} ${finalText} ${backgroundTasks} ${minuteBucket}`;
144
+ if (lastKey === cacheKey && lastResult) {
145
+ log.info("goal_stop.verdict_cache_hit", { cat: "goal" });
146
+ return lastResult;
147
+ }
148
+ const signal = ctx.data.signal;
149
+ let verdict = null;
150
+ let respText = "";
151
+ let respStopReason;
152
+ try {
153
+ const resp = await llm.createMessage({
154
+ systemPrompt: JUDGE_SYSTEM,
155
+ messages: [
156
+ {
157
+ role: "user",
158
+ content: `目标:\n${goal}\n\n` +
159
+ (setAtLabel ? `目标设定于:${setAtLabel}\n\n` : "") +
160
+ `当前时间:${nowLabel}\n\n` +
161
+ `agent 最近的输出:\n${finalText || "(无文本输出)"}\n\n` +
162
+ `当前在后台运行的任务:\n${backgroundTasks}\n\n` +
163
+ "判断目标状态,按要求只返回 JSON(met / waiting / gaps)。",
164
+ },
165
+ ],
166
+ stream: false,
167
+ // Headroom, not 400. A reasoning-capable aux model (e.g. DeepSeek V4)
168
+ // shares this budget between hidden reasoning tokens and the visible
169
+ // JSON. At 400 the reasoning ate the budget and the JSON got truncated
170
+ // (stopReason:"length") → extractJson returned null → the P0
171
+ // "unparseable" branch kept the run going forever, so a wall-clock
172
+ // deadline in the goal never fired. `reasoning:off` below is the real
173
+ // fix; 1500 is the belt-and-suspenders for models that ignore it.
174
+ maxTokens: 1500,
175
+ // Auxiliary sub-call — keep it out of the session cost/turn stats.
176
+ recordUsage: false,
177
+ // Turn thinking OFF. The judge only emits a tiny JSON verdict; reasoning
178
+ // tokens are pure waste here and (per above) actively caused truncation.
179
+ // On DeepSeek V4 / Anthropic-budget this genuinely disables thinking; on
180
+ // effort/adaptive/unknown models the field is a no-op (never a 400), so
181
+ // it is safe to always send — matching the aux summary/memory calls.
182
+ reasoning: { mode: "off" },
183
+ // Let a user Stop mid-judge abort this call rather than block on it.
184
+ signal,
185
+ });
186
+ respText = resp.text ?? "";
187
+ respStopReason = resp.stopReason;
188
+ verdict = extractJson(respText);
189
+ }
190
+ catch (err) {
191
+ log.warn("goal_stop.judge_failed", {
192
+ cat: "goal",
193
+ error: err.message,
194
+ });
195
+ // P0: do NOT silently allow stop on judge failure — in unattended runs
196
+ // that means the goal silently fails. Nudge to continue instead; the
197
+ // run-scoped budget guardrail (turn-loop) is the real safety backstop
198
+ // that prevents an unsatisfiable goal from looping forever.
199
+ return {
200
+ continueSession: true,
201
+ messages: [
202
+ "继续 —— 目标完成度无法判定,请继续推进直到明确完成(或调用 complete_goal 声明完成)。",
203
+ ],
204
+ };
205
+ }
206
+ if (!verdict) {
207
+ // Record enough to diagnose WHY the verdict didn't parse without having to
208
+ // reproduce it live: stopReason ("length" ⇒ the reply was truncated, the
209
+ // most common cause) plus a short preview of the raw text. Preview is
210
+ // capped so a runaway reply can't bloat the log line.
211
+ log.warn("goal_stop.unparseable", {
212
+ cat: "goal",
213
+ stopReason: respStopReason,
214
+ preview: respText.slice(0, 200),
215
+ });
216
+ // P0: same as the throw path — unparseable judge output must not be
217
+ // treated as "done". Continue instead of silently allowing the stop.
218
+ return {
219
+ continueSession: true,
220
+ messages: [
221
+ "继续 —— 目标完成度无法判定,请继续推进直到明确完成(或调用 complete_goal 声明完成)。",
222
+ ],
223
+ };
224
+ }
225
+ if (verdict.met) {
226
+ log.info("goal_stop.met", { cat: "goal" });
227
+ // Clear the persisted active goal (engine side-effect) so a later bare
228
+ // send doesn't re-inherit a satisfied goal. Isolated so a throwing
229
+ // callback can't block the stop.
230
+ try {
231
+ opts.onMet?.();
232
+ }
233
+ catch {
234
+ /* ignore */
235
+ }
236
+ // Surface the verdict so the loop can emit a goal_progress(met) event.
237
+ return { data: { goalVerdict: { met: true, gaps: "" } } };
238
+ }
239
+ // waiting: goal not met, but the only remaining work is a FINITE background
240
+ // task that will wake the session on completion. Allow the stop (no push) —
241
+ // forcing continueSession here is exactly the busy-loop bug. The completion
242
+ // notification wakes the idle session (server maybeWakeIdleSession) and the
243
+ // goal is re-judged on that woken turn.
244
+ //
245
+ // GUARD: only honor `waiting` when real background work is actually running.
246
+ // If the judge hallucinates waiting:true with an empty task list, allowing
247
+ // the stop would silently abandon the goal — NOTHING would ever wake the
248
+ // session (no notification to drain). So a baseless `waiting` falls through
249
+ // to not_met (continueSession), where the model is nudged to keep working.
250
+ if (verdict.waiting && runningWork.length > 0) {
251
+ log.info("goal_stop.waiting_on_background_task", { cat: "goal", sessionId });
252
+ const result = {
253
+ data: { goalVerdict: { met: false, gaps: verdict.gaps.trim() } },
254
+ };
255
+ lastKey = cacheKey;
256
+ lastResult = result;
257
+ return result;
258
+ }
259
+ if (verdict.waiting) {
260
+ log.warn("goal_stop.waiting_without_background_work", { cat: "goal", sessionId });
261
+ }
262
+ log.info("goal_stop.not_met", { cat: "goal", gaps: verdict.gaps });
263
+ const gaps = verdict.gaps.trim();
264
+ const result = {
265
+ continueSession: true,
266
+ messages: [
267
+ gaps
268
+ ? `继续 —— 目标尚未达成。还差:${gaps}`
269
+ : "继续 —— 目标尚未达成,请接着完成它。",
270
+ ],
271
+ // Structured verdict for the UI — the loop emits goal_progress(not_met)
272
+ // with this `gaps` instead of re-running the judge.
273
+ data: { goalVerdict: { met: false, gaps } },
274
+ };
275
+ lastKey = cacheKey;
276
+ lastResult = result;
277
+ return result;
278
+ };
279
+ }
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Shared output-handling primitives for hook runners.
3
+ *
4
+ * Two runners spawn child processes that produce HookResult JSON:
5
+ * - hooks/shell-runner.ts (user-configured shell hooks from settings)
6
+ * - plugins/pluginCommandHook.ts (hooks declared by installed plugins)
7
+ *
8
+ * Both need the same defences against:
9
+ * 1. Runaway output (a chatty / malicious handler eating engine RAM).
10
+ * 2. Schema drift (unknown decision values, typo'd top-level keys,
11
+ * non-string messages — silent no-ops are worse than rejections).
12
+ *
13
+ * Keeping the byte cap and validator in one module guarantees the two
14
+ * runners can't accidentally diverge on what counts as "valid".
15
+ */
16
+ import type { HookResult } from "./events.js";
17
+ /**
18
+ * Cap hook output to avoid runaway logging / OOM. 1 MiB is more than enough
19
+ * for any legitimate HookResult (which is typically < 1 KiB), while still
20
+ * absorbing chatty handlers without truncating their decision/messages
21
+ * payload. Past the cap callers kill the child and treat the hook as failed.
22
+ */
23
+ export declare const MAX_HOOK_OUTPUT_BYTES: number;
24
+ /**
25
+ * Permissive runtime check that a parsed object matches HookResult.
26
+ * Rejects unknown decision values, non-string/array fields, and unknown
27
+ * top-level keys (signalling a typo or hostile/garbage payload). Returns
28
+ * a normalized HookResult on success or null on failure — caller treats
29
+ * null the same as "no result, drop it".
30
+ *
31
+ * Exported so a unit test can pin the contract without spawning a shell.
32
+ */
33
+ export declare function validateHookResult(parsed: unknown): HookResult | null;