@cjhyy/code-shell-core 0.5.0-rc.0

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 (484) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +162 -0
  3. package/dist/agent/coordinator.d.ts +49 -0
  4. package/dist/agent/coordinator.js +77 -0
  5. package/dist/arena/arena.d.ts +43 -0
  6. package/dist/arena/arena.js +334 -0
  7. package/dist/arena/context/context-tools.d.ts +16 -0
  8. package/dist/arena/context/context-tools.js +231 -0
  9. package/dist/arena/detect-mode.d.ts +20 -0
  10. package/dist/arena/detect-mode.js +78 -0
  11. package/dist/arena/digest-builder.d.ts +25 -0
  12. package/dist/arena/digest-builder.js +120 -0
  13. package/dist/arena/index.d.ts +29 -0
  14. package/dist/arena/index.js +29 -0
  15. package/dist/arena/iterate/convergence.d.ts +25 -0
  16. package/dist/arena/iterate/convergence.js +103 -0
  17. package/dist/arena/iterate/formats/index.d.ts +22 -0
  18. package/dist/arena/iterate/formats/index.js +283 -0
  19. package/dist/arena/iterate/index.d.ts +11 -0
  20. package/dist/arena/iterate/index.js +9 -0
  21. package/dist/arena/iterate/iterative-arena.d.ts +23 -0
  22. package/dist/arena/iterate/iterative-arena.js +237 -0
  23. package/dist/arena/iterate/parse.d.ts +42 -0
  24. package/dist/arena/iterate/parse.js +123 -0
  25. package/dist/arena/iterate/phases/argue.d.ts +22 -0
  26. package/dist/arena/iterate/phases/argue.js +159 -0
  27. package/dist/arena/iterate/phases/revise.d.ts +16 -0
  28. package/dist/arena/iterate/phases/revise.js +62 -0
  29. package/dist/arena/iterate/phases/tournament.d.ts +34 -0
  30. package/dist/arena/iterate/phases/tournament.js +113 -0
  31. package/dist/arena/iterate/tools/web-tools.d.ts +13 -0
  32. package/dist/arena/iterate/tools/web-tools.js +54 -0
  33. package/dist/arena/iterate/types.d.ts +152 -0
  34. package/dist/arena/iterate/types.js +8 -0
  35. package/dist/arena/ledger.d.ts +47 -0
  36. package/dist/arena/ledger.js +151 -0
  37. package/dist/arena/lenses/architecture.d.ts +5 -0
  38. package/dist/arena/lenses/architecture.js +22 -0
  39. package/dist/arena/lenses/engineering.d.ts +5 -0
  40. package/dist/arena/lenses/engineering.js +22 -0
  41. package/dist/arena/lenses/general.d.ts +5 -0
  42. package/dist/arena/lenses/general.js +20 -0
  43. package/dist/arena/lenses/index.d.ts +16 -0
  44. package/dist/arena/lenses/index.js +47 -0
  45. package/dist/arena/lenses/product.d.ts +5 -0
  46. package/dist/arena/lenses/product.js +22 -0
  47. package/dist/arena/model-presets.d.ts +23 -0
  48. package/dist/arena/model-presets.js +44 -0
  49. package/dist/arena/phases/adjudication.d.ts +24 -0
  50. package/dist/arena/phases/adjudication.js +144 -0
  51. package/dist/arena/phases/build-consensus.d.ts +29 -0
  52. package/dist/arena/phases/build-consensus.js +86 -0
  53. package/dist/arena/phases/claim-registry.d.ts +26 -0
  54. package/dist/arena/phases/claim-registry.js +60 -0
  55. package/dist/arena/phases/cross-review.d.ts +45 -0
  56. package/dist/arena/phases/cross-review.js +224 -0
  57. package/dist/arena/phases/debate-rounds.d.ts +27 -0
  58. package/dist/arena/phases/debate-rounds.js +162 -0
  59. package/dist/arena/phases/participant-research.d.ts +38 -0
  60. package/dist/arena/phases/participant-research.js +317 -0
  61. package/dist/arena/phases/planning-detail-expansion.d.ts +38 -0
  62. package/dist/arena/phases/planning-detail-expansion.js +121 -0
  63. package/dist/arena/planner.d.ts +27 -0
  64. package/dist/arena/planner.js +312 -0
  65. package/dist/arena/providers/docs.d.ts +6 -0
  66. package/dist/arena/providers/docs.js +108 -0
  67. package/dist/arena/providers/git.d.ts +8 -0
  68. package/dist/arena/providers/git.js +174 -0
  69. package/dist/arena/providers/index.d.ts +32 -0
  70. package/dist/arena/providers/index.js +132 -0
  71. package/dist/arena/providers/none.d.ts +7 -0
  72. package/dist/arena/providers/none.js +11 -0
  73. package/dist/arena/providers/repo.d.ts +6 -0
  74. package/dist/arena/providers/repo.js +255 -0
  75. package/dist/arena/render/session.d.ts +17 -0
  76. package/dist/arena/render/session.js +190 -0
  77. package/dist/arena/render/terminal.d.ts +34 -0
  78. package/dist/arena/render/terminal.js +286 -0
  79. package/dist/arena/strategies/discussion.d.ts +25 -0
  80. package/dist/arena/strategies/discussion.js +143 -0
  81. package/dist/arena/strategies/index.d.ts +15 -0
  82. package/dist/arena/strategies/index.js +28 -0
  83. package/dist/arena/strategies/language-wrapper.d.ts +17 -0
  84. package/dist/arena/strategies/language-wrapper.js +102 -0
  85. package/dist/arena/strategies/lens-wrapper.d.ts +16 -0
  86. package/dist/arena/strategies/lens-wrapper.js +236 -0
  87. package/dist/arena/strategies/planning.d.ts +30 -0
  88. package/dist/arena/strategies/planning.js +225 -0
  89. package/dist/arena/strategies/review.d.ts +26 -0
  90. package/dist/arena/strategies/review.js +168 -0
  91. package/dist/arena/strategies/utils.d.ts +39 -0
  92. package/dist/arena/strategies/utils.js +647 -0
  93. package/dist/arena/tools/selector.d.ts +17 -0
  94. package/dist/arena/tools/selector.js +61 -0
  95. package/dist/arena/transitions.d.ts +48 -0
  96. package/dist/arena/transitions.js +92 -0
  97. package/dist/arena/types.d.ts +508 -0
  98. package/dist/arena/types.js +27 -0
  99. package/dist/cli/agent-server-stdio.d.ts +32 -0
  100. package/dist/cli/agent-server-stdio.js +116 -0
  101. package/dist/colorizer.d.ts +23 -0
  102. package/dist/colorizer.js +12 -0
  103. package/dist/context/compaction.d.ts +116 -0
  104. package/dist/context/compaction.js +534 -0
  105. package/dist/context/manager.d.ts +145 -0
  106. package/dist/context/manager.js +423 -0
  107. package/dist/context/token-counter.d.ts +27 -0
  108. package/dist/context/token-counter.js +91 -0
  109. package/dist/context/tool-result-storage.d.ts +96 -0
  110. package/dist/context/tool-result-storage.js +296 -0
  111. package/dist/cost-tracker.d.ts +64 -0
  112. package/dist/cost-tracker.js +314 -0
  113. package/dist/cron/scheduler.d.ts +34 -0
  114. package/dist/cron/scheduler.js +115 -0
  115. package/dist/data/deepseek-models.json +46 -0
  116. package/dist/data/gemini-models.json +67 -0
  117. package/dist/data/openai-models.json +175 -0
  118. package/dist/data/openrouter-models.d.ts +35 -0
  119. package/dist/data/openrouter-models.js +36 -0
  120. package/dist/data/openrouter-models.json +4626 -0
  121. package/dist/data/openrouter-sync.d.ts +16 -0
  122. package/dist/data/openrouter-sync.js +53 -0
  123. package/dist/data/static-catalogs.d.ts +25 -0
  124. package/dist/data/static-catalogs.js +26 -0
  125. package/dist/data/zai-models.json +56 -0
  126. package/dist/engine/cost-store.d.ts +22 -0
  127. package/dist/engine/cost-store.js +15 -0
  128. package/dist/engine/engine.d.ts +295 -0
  129. package/dist/engine/engine.js +1467 -0
  130. package/dist/engine/model-facade.d.ts +24 -0
  131. package/dist/engine/model-facade.js +194 -0
  132. package/dist/engine/parse-task.d.ts +59 -0
  133. package/dist/engine/parse-task.js +135 -0
  134. package/dist/engine/patch-orphaned-tools.d.ts +52 -0
  135. package/dist/engine/patch-orphaned-tools.js +95 -0
  136. package/dist/engine/query.d.ts +50 -0
  137. package/dist/engine/query.js +107 -0
  138. package/dist/engine/runtime.d.ts +50 -0
  139. package/dist/engine/runtime.js +59 -0
  140. package/dist/engine/streaming-tool-queue.d.ts +34 -0
  141. package/dist/engine/streaming-tool-queue.js +61 -0
  142. package/dist/engine/token-budget.d.ts +22 -0
  143. package/dist/engine/token-budget.js +40 -0
  144. package/dist/engine/tool-summary.d.ts +13 -0
  145. package/dist/engine/tool-summary.js +35 -0
  146. package/dist/engine/turn-loop.d.ts +122 -0
  147. package/dist/engine/turn-loop.js +602 -0
  148. package/dist/engine/turn-state.d.ts +20 -0
  149. package/dist/engine/turn-state.js +17 -0
  150. package/dist/exceptions.d.ts +61 -0
  151. package/dist/exceptions.js +116 -0
  152. package/dist/git/utils.d.ts +35 -0
  153. package/dist/git/utils.js +98 -0
  154. package/dist/git/worktree.d.ts +36 -0
  155. package/dist/git/worktree.js +139 -0
  156. package/dist/hooks/events.d.ts +114 -0
  157. package/dist/hooks/events.js +4 -0
  158. package/dist/hooks/inject.d.ts +19 -0
  159. package/dist/hooks/inject.js +29 -0
  160. package/dist/hooks/registry.d.ts +15 -0
  161. package/dist/hooks/registry.js +84 -0
  162. package/dist/hooks/shell-runner.d.ts +45 -0
  163. package/dist/hooks/shell-runner.js +173 -0
  164. package/dist/index.d.ts +117 -0
  165. package/dist/index.js +145 -0
  166. package/dist/llm/api-key-sanitize.d.ts +22 -0
  167. package/dist/llm/api-key-sanitize.js +81 -0
  168. package/dist/llm/capabilities/index.d.ts +20 -0
  169. package/dist/llm/capabilities/index.js +39 -0
  170. package/dist/llm/capabilities/rules.d.ts +26 -0
  171. package/dist/llm/capabilities/rules.js +215 -0
  172. package/dist/llm/capabilities/types.d.ts +114 -0
  173. package/dist/llm/capabilities/types.js +24 -0
  174. package/dist/llm/client-base.d.ts +29 -0
  175. package/dist/llm/client-base.js +137 -0
  176. package/dist/llm/client-factory.d.ts +10 -0
  177. package/dist/llm/client-factory.js +29 -0
  178. package/dist/llm/model-cache.d.ts +21 -0
  179. package/dist/llm/model-cache.js +46 -0
  180. package/dist/llm/model-fetcher.d.ts +29 -0
  181. package/dist/llm/model-fetcher.js +282 -0
  182. package/dist/llm/model-pool.d.ts +95 -0
  183. package/dist/llm/model-pool.js +246 -0
  184. package/dist/llm/provider-catalog.d.ts +32 -0
  185. package/dist/llm/provider-catalog.js +50 -0
  186. package/dist/llm/provider-kinds.d.ts +21 -0
  187. package/dist/llm/provider-kinds.js +132 -0
  188. package/dist/llm/providers/anthropic.d.ts +19 -0
  189. package/dist/llm/providers/anthropic.js +267 -0
  190. package/dist/llm/providers/openai.d.ts +64 -0
  191. package/dist/llm/providers/openai.js +606 -0
  192. package/dist/llm/retry.d.ts +12 -0
  193. package/dist/llm/retry.js +17 -0
  194. package/dist/llm/stream-watchdog.d.ts +42 -0
  195. package/dist/llm/stream-watchdog.js +70 -0
  196. package/dist/llm/token-counter.d.ts +17 -0
  197. package/dist/llm/token-counter.js +36 -0
  198. package/dist/llm/types.d.ts +37 -0
  199. package/dist/llm/types.js +4 -0
  200. package/dist/logging/logger.d.ts +109 -0
  201. package/dist/logging/logger.js +390 -0
  202. package/dist/logging/sanitize-messages.d.ts +42 -0
  203. package/dist/logging/sanitize-messages.js +150 -0
  204. package/dist/logging/session-recorder.d.ts +90 -0
  205. package/dist/logging/session-recorder.js +304 -0
  206. package/dist/lsp/client.d.ts +41 -0
  207. package/dist/lsp/client.js +166 -0
  208. package/dist/lsp/manager.d.ts +40 -0
  209. package/dist/lsp/manager.js +124 -0
  210. package/dist/lsp/servers.d.ts +16 -0
  211. package/dist/lsp/servers.js +60 -0
  212. package/dist/migrate-models.d.ts +45 -0
  213. package/dist/migrate-models.js +179 -0
  214. package/dist/onboarding.d.ts +189 -0
  215. package/dist/onboarding.js +625 -0
  216. package/dist/plugins/gitOps.d.ts +32 -0
  217. package/dist/plugins/gitOps.js +62 -0
  218. package/dist/plugins/installedPlugins.d.ts +15 -0
  219. package/dist/plugins/installedPlugins.js +56 -0
  220. package/dist/plugins/knownMarketplaces.d.ts +10 -0
  221. package/dist/plugins/knownMarketplaces.js +46 -0
  222. package/dist/plugins/loadPluginHooks.d.ts +52 -0
  223. package/dist/plugins/loadPluginHooks.js +162 -0
  224. package/dist/plugins/marketplaceManager.d.ts +49 -0
  225. package/dist/plugins/marketplaceManager.js +142 -0
  226. package/dist/plugins/parseMarketplaceInput.d.ts +16 -0
  227. package/dist/plugins/parseMarketplaceInput.js +73 -0
  228. package/dist/plugins/pluginCommandHook.d.ts +54 -0
  229. package/dist/plugins/pluginCommandHook.js +180 -0
  230. package/dist/plugins/pluginCommandsLoader.d.ts +25 -0
  231. package/dist/plugins/pluginCommandsLoader.js +114 -0
  232. package/dist/plugins/pluginInstaller.d.ts +36 -0
  233. package/dist/plugins/pluginInstaller.js +228 -0
  234. package/dist/plugins/schemas.d.ts +9 -0
  235. package/dist/plugins/schemas.js +136 -0
  236. package/dist/plugins/types.d.ts +75 -0
  237. package/dist/plugins/types.js +7 -0
  238. package/dist/plugins/varRewrite.d.ts +42 -0
  239. package/dist/plugins/varRewrite.js +129 -0
  240. package/dist/preset/index.d.ts +60 -0
  241. package/dist/preset/index.js +159 -0
  242. package/dist/product/define.d.ts +60 -0
  243. package/dist/product/define.js +123 -0
  244. package/dist/product/index.d.ts +5 -0
  245. package/dist/product/index.js +4 -0
  246. package/dist/product/types.d.ts +111 -0
  247. package/dist/product/types.js +21 -0
  248. package/dist/prompt/composer.d.ts +49 -0
  249. package/dist/prompt/composer.js +168 -0
  250. package/dist/prompt/instruction-scanner.d.ts +54 -0
  251. package/dist/prompt/instruction-scanner.js +187 -0
  252. package/dist/prompt/section-cache.d.ts +15 -0
  253. package/dist/prompt/section-cache.js +31 -0
  254. package/dist/prompt/section-loader.d.ts +26 -0
  255. package/dist/prompt/section-loader.js +53 -0
  256. package/dist/prompt/sections/base.md +35 -0
  257. package/dist/prompt/sections/coding.md +31 -0
  258. package/dist/prompt/sections/orchestration.md +16 -0
  259. package/dist/prompt/sections/tone.md +9 -0
  260. package/dist/protocol/chat-session-manager.d.ts +33 -0
  261. package/dist/protocol/chat-session-manager.js +65 -0
  262. package/dist/protocol/chat-session.d.ts +49 -0
  263. package/dist/protocol/chat-session.js +86 -0
  264. package/dist/protocol/client.d.ts +104 -0
  265. package/dist/protocol/client.js +260 -0
  266. package/dist/protocol/factories.d.ts +93 -0
  267. package/dist/protocol/factories.js +64 -0
  268. package/dist/protocol/helpers.d.ts +42 -0
  269. package/dist/protocol/helpers.js +55 -0
  270. package/dist/protocol/index.d.ts +4 -0
  271. package/dist/protocol/index.js +4 -0
  272. package/dist/protocol/server.d.ts +80 -0
  273. package/dist/protocol/server.js +855 -0
  274. package/dist/protocol/transport.d.ts +37 -0
  275. package/dist/protocol/transport.js +85 -0
  276. package/dist/protocol/types.d.ts +221 -0
  277. package/dist/protocol/types.js +61 -0
  278. package/dist/remote/bridge.d.ts +37 -0
  279. package/dist/remote/bridge.js +103 -0
  280. package/dist/run/ArtifactTracker.d.ts +38 -0
  281. package/dist/run/ArtifactTracker.js +132 -0
  282. package/dist/run/CheckpointWriter.d.ts +53 -0
  283. package/dist/run/CheckpointWriter.js +135 -0
  284. package/dist/run/EngineRunner.d.ts +72 -0
  285. package/dist/run/EngineRunner.js +119 -0
  286. package/dist/run/Evaluator.d.ts +56 -0
  287. package/dist/run/Evaluator.js +62 -0
  288. package/dist/run/FileRunStore.d.ts +39 -0
  289. package/dist/run/FileRunStore.js +176 -0
  290. package/dist/run/Heartbeat.d.ts +54 -0
  291. package/dist/run/Heartbeat.js +123 -0
  292. package/dist/run/RunApprovalBackend.d.ts +53 -0
  293. package/dist/run/RunApprovalBackend.js +85 -0
  294. package/dist/run/RunLock.d.ts +40 -0
  295. package/dist/run/RunLock.js +98 -0
  296. package/dist/run/RunManager.d.ts +82 -0
  297. package/dist/run/RunManager.js +587 -0
  298. package/dist/run/RunQueue.d.ts +27 -0
  299. package/dist/run/RunQueue.js +73 -0
  300. package/dist/run/RunStore.d.ts +25 -0
  301. package/dist/run/RunStore.js +9 -0
  302. package/dist/run/factory.d.ts +63 -0
  303. package/dist/run/factory.js +51 -0
  304. package/dist/run/index.d.ts +17 -0
  305. package/dist/run/index.js +23 -0
  306. package/dist/run/types.d.ts +136 -0
  307. package/dist/run/types.js +28 -0
  308. package/dist/runtime/safe-spawn.d.ts +118 -0
  309. package/dist/runtime/safe-spawn.js +268 -0
  310. package/dist/services/analytics.d.ts +29 -0
  311. package/dist/services/analytics.js +84 -0
  312. package/dist/services/auto-dream.d.ts +49 -0
  313. package/dist/services/auto-dream.js +124 -0
  314. package/dist/services/diagnostics.d.ts +41 -0
  315. package/dist/services/diagnostics.js +99 -0
  316. package/dist/services/extract-memories.d.ts +31 -0
  317. package/dist/services/extract-memories.js +71 -0
  318. package/dist/services/index.d.ts +11 -0
  319. package/dist/services/index.js +17 -0
  320. package/dist/services/memory-orchestrator.d.ts +60 -0
  321. package/dist/services/memory-orchestrator.js +133 -0
  322. package/dist/services/notifier.d.ts +25 -0
  323. package/dist/services/notifier.js +69 -0
  324. package/dist/services/oauth.d.ts +27 -0
  325. package/dist/services/oauth.js +153 -0
  326. package/dist/services/session-memory.d.ts +37 -0
  327. package/dist/services/session-memory.js +81 -0
  328. package/dist/session/file-history.d.ts +41 -0
  329. package/dist/session/file-history.js +115 -0
  330. package/dist/session/memory.d.ts +104 -0
  331. package/dist/session/memory.js +310 -0
  332. package/dist/session/session-manager.d.ts +41 -0
  333. package/dist/session/session-manager.js +261 -0
  334. package/dist/session/transcript.d.ts +39 -0
  335. package/dist/session/transcript.js +186 -0
  336. package/dist/settings/manager.d.ts +36 -0
  337. package/dist/settings/manager.js +187 -0
  338. package/dist/settings/schema.d.ts +1219 -0
  339. package/dist/settings/schema.js +246 -0
  340. package/dist/skills/frontmatter.d.ts +13 -0
  341. package/dist/skills/frontmatter.js +70 -0
  342. package/dist/skills/index.d.ts +7 -0
  343. package/dist/skills/index.js +6 -0
  344. package/dist/skills/scanner.d.ts +31 -0
  345. package/dist/skills/scanner.js +171 -0
  346. package/dist/state.d.ts +160 -0
  347. package/dist/state.js +267 -0
  348. package/dist/tool-system/builtin/agent-notifications.d.ts +84 -0
  349. package/dist/tool-system/builtin/agent-notifications.js +197 -0
  350. package/dist/tool-system/builtin/agent-registry.d.ts +67 -0
  351. package/dist/tool-system/builtin/agent-registry.js +126 -0
  352. package/dist/tool-system/builtin/agent-transcript-translator.d.ts +22 -0
  353. package/dist/tool-system/builtin/agent-transcript-translator.js +160 -0
  354. package/dist/tool-system/builtin/agent.d.ts +16 -0
  355. package/dist/tool-system/builtin/agent.js +364 -0
  356. package/dist/tool-system/builtin/apply-patch/applier.d.ts +26 -0
  357. package/dist/tool-system/builtin/apply-patch/applier.js +250 -0
  358. package/dist/tool-system/builtin/apply-patch/index.d.ts +20 -0
  359. package/dist/tool-system/builtin/apply-patch/index.js +101 -0
  360. package/dist/tool-system/builtin/apply-patch/parser.d.ts +17 -0
  361. package/dist/tool-system/builtin/apply-patch/parser.js +212 -0
  362. package/dist/tool-system/builtin/apply-patch/seek-sequence.d.ts +18 -0
  363. package/dist/tool-system/builtin/apply-patch/seek-sequence.js +123 -0
  364. package/dist/tool-system/builtin/apply-patch/types.d.ts +49 -0
  365. package/dist/tool-system/builtin/apply-patch/types.js +13 -0
  366. package/dist/tool-system/builtin/arena.d.ts +31 -0
  367. package/dist/tool-system/builtin/arena.js +416 -0
  368. package/dist/tool-system/builtin/ask-user.d.ts +20 -0
  369. package/dist/tool-system/builtin/ask-user.js +99 -0
  370. package/dist/tool-system/builtin/bash.d.ts +21 -0
  371. package/dist/tool-system/builtin/bash.js +149 -0
  372. package/dist/tool-system/builtin/brief.d.ts +6 -0
  373. package/dist/tool-system/builtin/brief.js +41 -0
  374. package/dist/tool-system/builtin/config.d.ts +6 -0
  375. package/dist/tool-system/builtin/config.js +67 -0
  376. package/dist/tool-system/builtin/cron.d.ts +10 -0
  377. package/dist/tool-system/builtin/cron.js +61 -0
  378. package/dist/tool-system/builtin/edit.d.ts +6 -0
  379. package/dist/tool-system/builtin/edit.js +100 -0
  380. package/dist/tool-system/builtin/file-cache.d.ts +11 -0
  381. package/dist/tool-system/builtin/file-cache.js +39 -0
  382. package/dist/tool-system/builtin/glob.d.ts +7 -0
  383. package/dist/tool-system/builtin/glob.js +76 -0
  384. package/dist/tool-system/builtin/grep.d.ts +7 -0
  385. package/dist/tool-system/builtin/grep.js +150 -0
  386. package/dist/tool-system/builtin/index.d.ts +20 -0
  387. package/dist/tool-system/builtin/index.js +449 -0
  388. package/dist/tool-system/builtin/lsp.d.ts +6 -0
  389. package/dist/tool-system/builtin/lsp.js +141 -0
  390. package/dist/tool-system/builtin/mcp-tools.d.ts +10 -0
  391. package/dist/tool-system/builtin/mcp-tools.js +102 -0
  392. package/dist/tool-system/builtin/memory.d.ts +26 -0
  393. package/dist/tool-system/builtin/memory.js +226 -0
  394. package/dist/tool-system/builtin/notebook-edit.d.ts +6 -0
  395. package/dist/tool-system/builtin/notebook-edit.js +124 -0
  396. package/dist/tool-system/builtin/plan.d.ts +15 -0
  397. package/dist/tool-system/builtin/plan.js +55 -0
  398. package/dist/tool-system/builtin/powershell.d.ts +11 -0
  399. package/dist/tool-system/builtin/powershell.js +64 -0
  400. package/dist/tool-system/builtin/read.d.ts +6 -0
  401. package/dist/tool-system/builtin/read.js +70 -0
  402. package/dist/tool-system/builtin/remote-trigger.d.ts +6 -0
  403. package/dist/tool-system/builtin/remote-trigger.js +54 -0
  404. package/dist/tool-system/builtin/repl.d.ts +11 -0
  405. package/dist/tool-system/builtin/repl.js +82 -0
  406. package/dist/tool-system/builtin/send-message.d.ts +6 -0
  407. package/dist/tool-system/builtin/send-message.js +47 -0
  408. package/dist/tool-system/builtin/skill-prompt.d.ts +20 -0
  409. package/dist/tool-system/builtin/skill-prompt.js +52 -0
  410. package/dist/tool-system/builtin/skill.d.ts +9 -0
  411. package/dist/tool-system/builtin/skill.js +55 -0
  412. package/dist/tool-system/builtin/sleep.d.ts +6 -0
  413. package/dist/tool-system/builtin/sleep.js +33 -0
  414. package/dist/tool-system/builtin/task.d.ts +48 -0
  415. package/dist/tool-system/builtin/task.js +139 -0
  416. package/dist/tool-system/builtin/tool-search.d.ts +11 -0
  417. package/dist/tool-system/builtin/tool-search.js +90 -0
  418. package/dist/tool-system/builtin/web-fetch.d.ts +10 -0
  419. package/dist/tool-system/builtin/web-fetch.js +328 -0
  420. package/dist/tool-system/builtin/web-search.d.ts +25 -0
  421. package/dist/tool-system/builtin/web-search.js +174 -0
  422. package/dist/tool-system/builtin/worktree.d.ts +10 -0
  423. package/dist/tool-system/builtin/worktree.js +95 -0
  424. package/dist/tool-system/builtin/write.d.ts +6 -0
  425. package/dist/tool-system/builtin/write.js +36 -0
  426. package/dist/tool-system/context.d.ts +165 -0
  427. package/dist/tool-system/context.js +18 -0
  428. package/dist/tool-system/executor.d.ts +49 -0
  429. package/dist/tool-system/executor.js +495 -0
  430. package/dist/tool-system/investigation-guard.d.ts +46 -0
  431. package/dist/tool-system/investigation-guard.js +155 -0
  432. package/dist/tool-system/mcp-manager.d.ts +67 -0
  433. package/dist/tool-system/mcp-manager.js +249 -0
  434. package/dist/tool-system/permission.d.ts +111 -0
  435. package/dist/tool-system/permission.js +774 -0
  436. package/dist/tool-system/registry.d.ts +32 -0
  437. package/dist/tool-system/registry.js +131 -0
  438. package/dist/tool-system/sandbox/bwrap.d.ts +13 -0
  439. package/dist/tool-system/sandbox/bwrap.js +63 -0
  440. package/dist/tool-system/sandbox/index.d.ts +78 -0
  441. package/dist/tool-system/sandbox/index.js +222 -0
  442. package/dist/tool-system/sandbox/off.d.ts +2 -0
  443. package/dist/tool-system/sandbox/off.js +8 -0
  444. package/dist/tool-system/sandbox/seatbelt.d.ts +18 -0
  445. package/dist/tool-system/sandbox/seatbelt.js +109 -0
  446. package/dist/tool-system/task-guard.d.ts +29 -0
  447. package/dist/tool-system/task-guard.js +70 -0
  448. package/dist/tool-system/validation.d.ts +5 -0
  449. package/dist/tool-system/validation.js +39 -0
  450. package/dist/types.d.ts +376 -0
  451. package/dist/types.js +4 -0
  452. package/dist/updater.d.ts +65 -0
  453. package/dist/updater.js +405 -0
  454. package/dist/utils/debug.d.ts +41 -0
  455. package/dist/utils/debug.js +110 -0
  456. package/dist/utils/earlyInput.d.ts +43 -0
  457. package/dist/utils/earlyInput.js +166 -0
  458. package/dist/utils/env.d.ts +24 -0
  459. package/dist/utils/env.js +104 -0
  460. package/dist/utils/envUtils.d.ts +51 -0
  461. package/dist/utils/envUtils.js +135 -0
  462. package/dist/utils/execFileNoThrow.d.ts +39 -0
  463. package/dist/utils/execFileNoThrow.js +74 -0
  464. package/dist/utils/format.d.ts +44 -0
  465. package/dist/utils/format.js +236 -0
  466. package/dist/utils/intl.d.ts +22 -0
  467. package/dist/utils/intl.js +83 -0
  468. package/dist/utils/lockfile.d.ts +15 -0
  469. package/dist/utils/lockfile.js +30 -0
  470. package/dist/utils/memoize.d.ts +19 -0
  471. package/dist/utils/memoize.js +14 -0
  472. package/dist/utils/semver.d.ts +6 -0
  473. package/dist/utils/semver.js +13 -0
  474. package/dist/utils/sliceAnsi.d.ts +12 -0
  475. package/dist/utils/sliceAnsi.js +62 -0
  476. package/dist/utils/systemTheme.d.ts +40 -0
  477. package/dist/utils/systemTheme.js +108 -0
  478. package/dist/utils/task-sanitizer.d.ts +6 -0
  479. package/dist/utils/task-sanitizer.js +24 -0
  480. package/dist/utils/theme.d.ts +93 -0
  481. package/dist/utils/theme.js +544 -0
  482. package/dist/utils/toolDisplay.d.ts +31 -0
  483. package/dist/utils/toolDisplay.js +188 -0
  484. package/package.json +72 -0
@@ -0,0 +1,82 @@
1
+ /**
2
+ * RunManager — the top-level coordinator for managed agent runs.
3
+ *
4
+ * It does NOT replace Engine. It wraps Engine.run() to provide:
5
+ * - Submit / queue / start / resume / cancel lifecycle
6
+ * - State machine validation
7
+ * - Event sourcing (append-only run events)
8
+ * - Checkpoint and approval coordination
9
+ * - Waiting states: waiting_input / waiting_approval with suspend/resume
10
+ * - Attach (live stream subscription)
11
+ * - Run locking, heartbeat, and crash recovery (Phase 4)
12
+ */
13
+ import type { RunStore } from "./RunStore.js";
14
+ import { type EngineRunnerConfig, type RunExecutor } from "./EngineRunner.js";
15
+ import { type Evaluator } from "./Evaluator.js";
16
+ import type { RunSnapshot, RunEvent, SubmitRunInput, ResumeRunInput, ListRunsQuery, RunStreamCallback, DetachFn } from "./types.js";
17
+ export interface RunManagerConfig {
18
+ store: RunStore;
19
+ /**
20
+ * Execution backend. Two ways to provide:
21
+ * - `EngineRunnerConfig` object → creates built-in EngineRunner (calls LLM Engine)
22
+ * - `RunExecutor` instance → custom executor (any backend: CI/CD, ETL, etc.)
23
+ */
24
+ executor: RunExecutor | EngineRunnerConfig;
25
+ concurrency?: number;
26
+ /** Base directory for runs (used by lock and heartbeat). */
27
+ runsDir?: string;
28
+ /** Heartbeat interval in ms. Default: 5000 */
29
+ heartbeatIntervalMs?: number;
30
+ /** Stale lock timeout in ms. Default: 60000 */
31
+ staleLockMs?: number;
32
+ /** Optional evaluator to run on completion. Default: NoopEvaluator */
33
+ evaluator?: Evaluator;
34
+ /** Tags applied to every submitted run unless already present. */
35
+ defaultTags?: string[];
36
+ /** Metadata merged into every submitted run. Submit input wins on conflicts. */
37
+ defaultMetadata?: Record<string, unknown>;
38
+ }
39
+ export declare class RunManager {
40
+ private readonly store;
41
+ private readonly queue;
42
+ private readonly runner;
43
+ private readonly lock;
44
+ private readonly heartbeat;
45
+ private readonly evaluator;
46
+ private readonly defaultTags;
47
+ private readonly defaultMetadata;
48
+ private readonly subscribers;
49
+ private readonly abortControllers;
50
+ /** Active execution handles — used to resolve pending approvals/input while Engine is suspended */
51
+ private readonly executionHandles;
52
+ constructor(config: RunManagerConfig);
53
+ submit(input: SubmitRunInput): Promise<RunSnapshot>;
54
+ start(runId: string): Promise<void>;
55
+ resume(runId: string, input?: ResumeRunInput): Promise<void>;
56
+ cancel(runId: string, reason?: string): Promise<void>;
57
+ get(runId: string): Promise<RunSnapshot | null>;
58
+ list(query?: ListRunsQuery): Promise<RunSnapshot[]>;
59
+ getEvents(runId: string): Promise<RunEvent[]>;
60
+ attach(runId: string, cb: RunStreamCallback): DetachFn;
61
+ /**
62
+ * Scan for runs stuck in "running" state and recover them.
63
+ *
64
+ * Call this on process startup. For each "running" run:
65
+ * - If heartbeat is stale AND process is dead → reset to "queued" or "blocked"
66
+ * - If heartbeat is recent OR process is alive → skip (still executing)
67
+ *
68
+ * Returns the IDs of recovered runs.
69
+ */
70
+ recover(): Promise<string[]>;
71
+ /**
72
+ * Graceful shutdown — stop all heartbeats and release all locks.
73
+ */
74
+ shutdown(): Promise<void>;
75
+ private executeRun;
76
+ private handleApprovalNeeded;
77
+ private handleInputNeeded;
78
+ private transition;
79
+ private emitRunEvent;
80
+ private notifySubscribers;
81
+ private getOrThrow;
82
+ }
@@ -0,0 +1,587 @@
1
+ /**
2
+ * RunManager — the top-level coordinator for managed agent runs.
3
+ *
4
+ * It does NOT replace Engine. It wraps Engine.run() to provide:
5
+ * - Submit / queue / start / resume / cancel lifecycle
6
+ * - State machine validation
7
+ * - Event sourcing (append-only run events)
8
+ * - Checkpoint and approval coordination
9
+ * - Waiting states: waiting_input / waiting_approval with suspend/resume
10
+ * - Attach (live stream subscription)
11
+ * - Run locking, heartbeat, and crash recovery (Phase 4)
12
+ */
13
+ import { nanoid } from "nanoid";
14
+ import { logger } from "../logging/logger.js";
15
+ import { RunQueue } from "./RunQueue.js";
16
+ import { EngineRunner } from "./EngineRunner.js";
17
+ import { CheckpointWriter } from "./CheckpointWriter.js";
18
+ import { ArtifactTracker } from "./ArtifactTracker.js";
19
+ import { RunLock } from "./RunLock.js";
20
+ import { Heartbeat } from "./Heartbeat.js";
21
+ import { NoopEvaluator } from "./Evaluator.js";
22
+ import { VALID_TRANSITIONS } from "./types.js";
23
+ export class RunManager {
24
+ store;
25
+ queue;
26
+ runner;
27
+ lock;
28
+ heartbeat;
29
+ evaluator;
30
+ defaultTags;
31
+ defaultMetadata;
32
+ subscribers = new Map();
33
+ abortControllers = new Map();
34
+ /** Active execution handles — used to resolve pending approvals/input while Engine is suspended */
35
+ executionHandles = new Map();
36
+ constructor(config) {
37
+ this.store = config.store;
38
+ this.queue = new RunQueue({ concurrency: config.concurrency ?? 1 });
39
+ // Accept either a RunExecutor instance or an EngineRunnerConfig
40
+ this.runner = isRunExecutor(config.executor)
41
+ ? config.executor
42
+ : new EngineRunner(config.executor);
43
+ this.lock = new RunLock({
44
+ runsDir: config.runsDir,
45
+ staleMs: config.staleLockMs,
46
+ });
47
+ this.heartbeat = new Heartbeat({
48
+ runsDir: config.runsDir,
49
+ intervalMs: config.heartbeatIntervalMs,
50
+ });
51
+ this.evaluator = config.evaluator ?? new NoopEvaluator();
52
+ this.defaultTags = config.defaultTags ?? [];
53
+ this.defaultMetadata = config.defaultMetadata ?? {};
54
+ // Wire queue executor
55
+ this.queue.setExecutor((runId) => this.executeRun(runId));
56
+ }
57
+ // ─── Submit ────────────────────────────────────────────────────
58
+ async submit(input) {
59
+ const now = Date.now();
60
+ const runId = nanoid(16);
61
+ const snapshot = {
62
+ runId,
63
+ objective: input.objective,
64
+ preset: input.preset ?? "terminal-coding",
65
+ cwd: input.cwd ?? process.cwd(),
66
+ status: "queued",
67
+ createdAt: now,
68
+ updatedAt: now,
69
+ startedAt: null,
70
+ finishedAt: null,
71
+ parentRunId: input.parentRunId ?? null,
72
+ sessionId: null,
73
+ childSessionIds: [],
74
+ attemptCount: 0,
75
+ latestCheckpointId: null,
76
+ latestApprovalId: null,
77
+ summary: null,
78
+ error: null,
79
+ tags: [...new Set([...this.defaultTags, ...(input.tags ?? [])])],
80
+ metadata: { ...this.defaultMetadata, ...(input.metadata ?? {}) },
81
+ };
82
+ await this.store.create(snapshot);
83
+ await this.emitRunEvent(runId, "run_created", { objective: input.objective });
84
+ await this.emitRunEvent(runId, "run_queued", {});
85
+ logger.info("run.submitted", { runId, objective: input.objective.slice(0, 120) });
86
+ // Enqueue for execution
87
+ this.queue.enqueue(runId);
88
+ return snapshot;
89
+ }
90
+ // ─── Start (manual, bypasses queue) ────────────────────────────
91
+ async start(runId) {
92
+ const run = await this.getOrThrow(runId);
93
+ if (run.status !== "queued") {
94
+ throw new Error(`Cannot start run ${runId}: current status is ${run.status}`);
95
+ }
96
+ if (!this.queue.isPending(runId) && !this.queue.isActive(runId)) {
97
+ this.queue.enqueue(runId);
98
+ }
99
+ }
100
+ // ─── Resume ────────────────────────────────────────────────────
101
+ async resume(runId, input) {
102
+ const run = await this.getOrThrow(runId);
103
+ if (run.status !== "waiting_input" &&
104
+ run.status !== "waiting_approval" &&
105
+ run.status !== "blocked") {
106
+ throw new Error(`Cannot resume run ${runId}: current status is ${run.status}`);
107
+ }
108
+ const handle = this.executionHandles.get(runId);
109
+ // Case 1: Engine is still suspended (in-process waiting)
110
+ // Resolve the pending promise so Engine continues
111
+ if (handle) {
112
+ if (run.status === "waiting_approval" && input?.approvalDecision) {
113
+ const { approvalId, approved, reason } = input.approvalDecision;
114
+ // Persist the approval decision
115
+ const approval = await this.store.getApproval(runId, approvalId);
116
+ if (approval && approval.status === "pending") {
117
+ approval.status = approved ? "approved" : "rejected";
118
+ approval.resolvedAt = Date.now();
119
+ await this.store.saveApproval(approval);
120
+ await this.emitRunEvent(runId, "approval_resolved", {
121
+ approvalId,
122
+ approved,
123
+ reason,
124
+ });
125
+ }
126
+ // Transition back to running and resolve the suspended Engine
127
+ await this.transition(run, "queued");
128
+ await this.transition(run, "running");
129
+ await this.emitRunEvent(runId, "run_resumed", {});
130
+ handle.resolveApproval(approved, reason);
131
+ return;
132
+ }
133
+ if (run.status === "waiting_input" && input?.userInput) {
134
+ await this.transition(run, "queued");
135
+ await this.transition(run, "running");
136
+ await this.emitRunEvent(runId, "run_resumed", { userInput: input.userInput });
137
+ handle.resolveInput(input.userInput);
138
+ return;
139
+ }
140
+ }
141
+ // Case 2: No active handle (process restarted, or blocked state)
142
+ // Re-queue the run for a fresh execution attempt
143
+ if (input?.approvalDecision) {
144
+ const { approvalId, approved, reason } = input.approvalDecision;
145
+ const approval = await this.store.getApproval(runId, approvalId);
146
+ if (approval && approval.status === "pending") {
147
+ approval.status = approved ? "approved" : "rejected";
148
+ approval.resolvedAt = Date.now();
149
+ await this.store.saveApproval(approval);
150
+ await this.emitRunEvent(runId, "approval_resolved", {
151
+ approvalId,
152
+ approved,
153
+ reason,
154
+ });
155
+ }
156
+ }
157
+ await this.transition(run, "queued");
158
+ await this.emitRunEvent(runId, "run_resumed", {
159
+ userInput: input?.userInput,
160
+ });
161
+ this.queue.enqueue(runId);
162
+ }
163
+ // ─── Cancel ────────────────────────────────────────────────────
164
+ async cancel(runId, reason) {
165
+ const run = await this.getOrThrow(runId);
166
+ if (run.status === "completed" || run.status === "failed" || run.status === "cancelled") {
167
+ throw new Error(`Cannot cancel run ${runId}: already in terminal state ${run.status}`);
168
+ }
169
+ // Abort active execution
170
+ const ac = this.abortControllers.get(runId);
171
+ if (ac)
172
+ ac.abort();
173
+ // If Engine is suspended on approval/input, reject it so the promise resolves
174
+ const handle = this.executionHandles.get(runId);
175
+ if (handle) {
176
+ if (handle.hasPendingApproval()) {
177
+ handle.resolveApproval(false, "run cancelled");
178
+ }
179
+ if (handle.hasPendingInput()) {
180
+ handle.resolveInput("(run cancelled)");
181
+ }
182
+ }
183
+ // Remove from pending queue
184
+ this.queue.cancel(runId);
185
+ await this.transition(run, "cancelled");
186
+ run.finishedAt = Date.now();
187
+ await this.store.update(run);
188
+ await this.emitRunEvent(runId, "run_cancelled", { reason });
189
+ logger.info("run.cancelled", { runId, reason });
190
+ }
191
+ // ─── Query ─────────────────────────────────────────────────────
192
+ async get(runId) {
193
+ return this.store.get(runId);
194
+ }
195
+ async list(query) {
196
+ return this.store.list(query);
197
+ }
198
+ async getEvents(runId) {
199
+ return this.store.listEvents(runId);
200
+ }
201
+ // ─── Attach (live stream) ──────────────────────────────────────
202
+ attach(runId, cb) {
203
+ if (!this.subscribers.has(runId)) {
204
+ this.subscribers.set(runId, new Set());
205
+ }
206
+ this.subscribers.get(runId).add(cb);
207
+ return () => {
208
+ const subs = this.subscribers.get(runId);
209
+ if (subs) {
210
+ subs.delete(cb);
211
+ if (subs.size === 0)
212
+ this.subscribers.delete(runId);
213
+ }
214
+ };
215
+ }
216
+ // ─── Crash Recovery ─────────────────────────────────────────────
217
+ /**
218
+ * Scan for runs stuck in "running" state and recover them.
219
+ *
220
+ * Call this on process startup. For each "running" run:
221
+ * - If heartbeat is stale AND process is dead → reset to "queued" or "blocked"
222
+ * - If heartbeat is recent OR process is alive → skip (still executing)
223
+ *
224
+ * Returns the IDs of recovered runs.
225
+ */
226
+ async recover() {
227
+ const runs = await this.store.list({ status: "running" });
228
+ const recovered = [];
229
+ for (const run of runs) {
230
+ const processAlive = this.heartbeat.isProcessAlive(run.runId);
231
+ const stale = this.heartbeat.isStale(run.runId);
232
+ if (processAlive && !stale) {
233
+ // Still actively running in another process — leave it alone
234
+ logger.info("run.recover.skip", { runId: run.runId, reason: "process alive" });
235
+ continue;
236
+ }
237
+ // Process is dead or heartbeat is stale — recover
238
+ logger.info("run.recover.resetting", {
239
+ runId: run.runId,
240
+ processAlive,
241
+ stale,
242
+ });
243
+ // Force-unlock the stale lock
244
+ await this.lock.forceUnlock(run.runId);
245
+ // Decide recovery action based on attempt count
246
+ if (run.attemptCount >= 3) {
247
+ // Too many retries — mark as blocked
248
+ run.error = "Exceeded max recovery attempts (3)";
249
+ run.status = "blocked";
250
+ run.updatedAt = Date.now();
251
+ await this.store.update(run);
252
+ await this.emitRunEvent(run.runId, "run_blocked", {
253
+ error: run.error,
254
+ recovered: true,
255
+ });
256
+ logger.warn("run.recover.blocked", { runId: run.runId });
257
+ }
258
+ else {
259
+ // Re-queue for retry
260
+ run.status = "queued";
261
+ run.updatedAt = Date.now();
262
+ await this.store.update(run);
263
+ await this.emitRunEvent(run.runId, "run_resumed", { recovered: true });
264
+ this.queue.enqueue(run.runId);
265
+ logger.info("run.recover.requeued", { runId: run.runId });
266
+ }
267
+ recovered.push(run.runId);
268
+ }
269
+ // Also check waiting runs with stale heartbeats (process died while waiting)
270
+ for (const status of ["waiting_input", "waiting_approval"]) {
271
+ const waitingRuns = await this.store.list({ status });
272
+ for (const run of waitingRuns) {
273
+ const stale = this.heartbeat.isStale(run.runId);
274
+ if (stale && !this.heartbeat.isProcessAlive(run.runId)) {
275
+ // The process died while the run was waiting — it stays in waiting
276
+ // state but we clean up the lock so it can be resumed
277
+ await this.lock.forceUnlock(run.runId);
278
+ logger.info("run.recover.unlock_waiting", { runId: run.runId, status });
279
+ }
280
+ }
281
+ }
282
+ return recovered;
283
+ }
284
+ /**
285
+ * Graceful shutdown — stop all heartbeats and release all locks.
286
+ */
287
+ async shutdown() {
288
+ this.heartbeat.stopAll();
289
+ await this.lock.releaseAll();
290
+ logger.info("run.shutdown");
291
+ }
292
+ // ─── Internal: Execute a run ───────────────────────────────────
293
+ async executeRun(runId) {
294
+ const run = await this.getOrThrow(runId);
295
+ // Acquire run lock — prevents concurrent execution by multiple workers
296
+ const acquired = await this.lock.acquire(runId);
297
+ if (!acquired) {
298
+ logger.warn("run.lock.failed", { runId, reason: "already locked by another worker" });
299
+ return;
300
+ }
301
+ // Start heartbeat so crash recovery can detect liveness
302
+ this.heartbeat.start(runId);
303
+ // Transition to running
304
+ await this.transition(run, "running");
305
+ run.startedAt = run.startedAt ?? Date.now();
306
+ run.attemptCount += 1;
307
+ await this.store.update(run);
308
+ await this.emitRunEvent(runId, "run_started", { attempt: run.attemptCount });
309
+ // Create abort controller for this execution
310
+ const ac = new AbortController();
311
+ this.abortControllers.set(runId, ac);
312
+ // Create checkpoint writer and artifact tracker
313
+ const checkpointWriter = new CheckpointWriter({
314
+ runId,
315
+ objective: run.objective,
316
+ store: this.store,
317
+ });
318
+ const artifactTracker = new ArtifactTracker({ runId, store: this.store });
319
+ // Build lifecycle hooks so Engine can notify us about approval/input needs
320
+ const lifecycleHooks = {
321
+ onApprovalNeeded: async (request) => {
322
+ return this.handleApprovalNeeded(runId, request);
323
+ },
324
+ onInputNeeded: async (question) => {
325
+ await this.handleInputNeeded(runId, question);
326
+ },
327
+ };
328
+ const context = {
329
+ signal: ac.signal,
330
+ onStream: async (event) => {
331
+ // Feed events to checkpoint writer and artifact tracker
332
+ await checkpointWriter.onStreamEvent(event);
333
+ await artifactTracker.onStreamEvent(event);
334
+ // Forward to run subscribers
335
+ this.notifySubscribers(runId, { type: "engine_stream", event });
336
+ },
337
+ };
338
+ try {
339
+ const { result, handle } = await this.runner.execute(run, context, lifecycleHooks,
340
+ // Store handle BEFORE Engine.run() awaits, so resume() can resolve
341
+ // pending approvals/input while Engine is suspended
342
+ (h) => this.executionHandles.set(runId, h));
343
+ // Refresh run state (may have been updated during execution)
344
+ const current = await this.getOrThrow(runId);
345
+ // If the run was moved to a waiting state during execution, don't finalize
346
+ if (current.status === "waiting_input" ||
347
+ current.status === "waiting_approval" ||
348
+ current.status === "cancelled") {
349
+ return;
350
+ }
351
+ // Link session
352
+ if (result.sessionId && current.sessionId !== result.sessionId) {
353
+ current.sessionId = result.sessionId;
354
+ checkpointWriter.setSessionId(result.sessionId);
355
+ await this.emitRunEvent(runId, "session_linked", {
356
+ sessionId: result.sessionId,
357
+ });
358
+ }
359
+ // Write final checkpoint with accumulated data from writer/tracker
360
+ const checkpoint = {
361
+ checkpointId: nanoid(12),
362
+ runId,
363
+ createdAt: Date.now(),
364
+ phase: "final",
365
+ objective: current.objective,
366
+ summary: result.text.slice(0, 500),
367
+ nextAction: null,
368
+ linkedSessionId: result.sessionId,
369
+ touchedTools: checkpointWriter.getTouchedTools(),
370
+ touchedArtifacts: artifactTracker.getRecordedPaths(),
371
+ waitingFor: null,
372
+ evaluator: null,
373
+ metadata: { turnCount: result.turnCount, reason: result.reason },
374
+ };
375
+ await this.store.saveCheckpoint(checkpoint);
376
+ current.latestCheckpointId = checkpoint.checkpointId;
377
+ await this.emitRunEvent(runId, "checkpoint_written", {
378
+ checkpointId: checkpoint.checkpointId,
379
+ phase: "final",
380
+ });
381
+ // Run evaluator on the final checkpoint
382
+ const artifacts = await this.store.listArtifactRefs(runId);
383
+ const evalContext = { run: current, checkpoint, artifacts };
384
+ try {
385
+ const evalResult = await this.evaluator.evaluate(evalContext);
386
+ checkpoint.evaluator = {
387
+ status: evalResult.verdict === "passed" ? "passed" : "failed",
388
+ findings: evalResult.findings,
389
+ };
390
+ await this.store.saveCheckpoint(checkpoint);
391
+ }
392
+ catch (evalErr) {
393
+ logger.warn("run.evaluator_error", {
394
+ runId,
395
+ error: evalErr instanceof Error ? evalErr.message : String(evalErr),
396
+ });
397
+ }
398
+ // Determine terminal state — evaluator verdict can override
399
+ const engineSuccess = result.reason === "completed";
400
+ const evalFailed = checkpoint.evaluator?.status === "failed";
401
+ const isSuccess = engineSuccess && !evalFailed;
402
+ current.summary = result.text.slice(0, 500);
403
+ if (isSuccess) {
404
+ await this.transition(current, "completed");
405
+ current.finishedAt = Date.now();
406
+ await this.store.update(current);
407
+ await this.emitRunEvent(runId, "run_completed", {
408
+ turnCount: result.turnCount,
409
+ reason: result.reason,
410
+ evaluator: checkpoint.evaluator,
411
+ });
412
+ logger.info("run.completed", { runId, turnCount: result.turnCount });
413
+ }
414
+ else {
415
+ current.error = evalFailed
416
+ ? `Evaluator failed: ${checkpoint.evaluator?.findings.join("; ")}`
417
+ : `Engine terminated: ${result.reason}`;
418
+ await this.transition(current, "failed");
419
+ current.finishedAt = Date.now();
420
+ await this.store.update(current);
421
+ await this.emitRunEvent(runId, "run_failed", {
422
+ reason: evalFailed ? "evaluator_failed" : result.reason,
423
+ error: current.error,
424
+ evaluator: checkpoint.evaluator,
425
+ });
426
+ logger.warn("run.failed", { runId, reason: evalFailed ? "evaluator" : result.reason });
427
+ }
428
+ }
429
+ catch (err) {
430
+ const current = await this.store.get(runId);
431
+ if (!current)
432
+ return;
433
+ // If aborted (cancelled), state is already handled
434
+ if (ac.signal.aborted)
435
+ return;
436
+ const errorMsg = err instanceof Error ? err.message : String(err);
437
+ current.error = errorMsg;
438
+ await this.transition(current, "blocked");
439
+ await this.store.update(current);
440
+ await this.emitRunEvent(runId, "run_blocked", { error: errorMsg });
441
+ logger.error("run.blocked", { runId, error: errorMsg });
442
+ }
443
+ finally {
444
+ this.abortControllers.delete(runId);
445
+ this.executionHandles.delete(runId);
446
+ this.heartbeat.stop(runId);
447
+ await this.lock.release(runId);
448
+ }
449
+ }
450
+ // ─── Lifecycle: Approval Needed ────────────────────────────────
451
+ async handleApprovalNeeded(runId, request) {
452
+ const approvalId = nanoid(12);
453
+ const run = await this.getOrThrow(runId);
454
+ // Create approval record
455
+ const approval = {
456
+ approvalId,
457
+ runId,
458
+ createdAt: Date.now(),
459
+ resolvedAt: null,
460
+ status: "pending",
461
+ category: "tool",
462
+ title: `Approve: ${request.toolName}`,
463
+ description: request.description,
464
+ payload: { toolName: request.toolName, args: request.args, riskLevel: request.riskLevel },
465
+ };
466
+ await this.store.saveApproval(approval);
467
+ run.latestApprovalId = approvalId;
468
+ // Write waiting checkpoint
469
+ const checkpoint = {
470
+ checkpointId: nanoid(12),
471
+ runId,
472
+ createdAt: Date.now(),
473
+ phase: "waiting_approval",
474
+ objective: run.objective,
475
+ summary: `Awaiting approval for ${request.toolName}: ${request.description}`,
476
+ nextAction: null,
477
+ linkedSessionId: run.sessionId,
478
+ touchedTools: [],
479
+ touchedArtifacts: [],
480
+ waitingFor: { kind: "approval", approvalId },
481
+ evaluator: null,
482
+ metadata: {},
483
+ };
484
+ await this.store.saveCheckpoint(checkpoint);
485
+ run.latestCheckpointId = checkpoint.checkpointId;
486
+ // Transition to waiting_approval
487
+ await this.transition(run, "waiting_approval");
488
+ await this.emitRunEvent(runId, "approval_requested", {
489
+ approvalId,
490
+ toolName: request.toolName,
491
+ description: request.description,
492
+ riskLevel: request.riskLevel,
493
+ });
494
+ await this.emitRunEvent(runId, "checkpoint_written", {
495
+ checkpointId: checkpoint.checkpointId,
496
+ phase: "waiting_approval",
497
+ });
498
+ logger.info("run.waiting_approval", { runId, approvalId, tool: request.toolName });
499
+ return { approvalId };
500
+ }
501
+ // ─── Lifecycle: Input Needed ───────────────────────────────────
502
+ async handleInputNeeded(runId, question) {
503
+ const run = await this.getOrThrow(runId);
504
+ // Write waiting checkpoint
505
+ const checkpoint = {
506
+ checkpointId: nanoid(12),
507
+ runId,
508
+ createdAt: Date.now(),
509
+ phase: "waiting_input",
510
+ objective: run.objective,
511
+ summary: `Awaiting user input: ${question.slice(0, 200)}`,
512
+ nextAction: null,
513
+ linkedSessionId: run.sessionId,
514
+ touchedTools: [],
515
+ touchedArtifacts: [],
516
+ waitingFor: { kind: "input", prompt: question },
517
+ evaluator: null,
518
+ metadata: {},
519
+ };
520
+ await this.store.saveCheckpoint(checkpoint);
521
+ run.latestCheckpointId = checkpoint.checkpointId;
522
+ // Transition to waiting_input
523
+ await this.transition(run, "waiting_input");
524
+ await this.emitRunEvent(runId, "checkpoint_written", {
525
+ checkpointId: checkpoint.checkpointId,
526
+ phase: "waiting_input",
527
+ question,
528
+ });
529
+ logger.info("run.waiting_input", { runId, question: question.slice(0, 120) });
530
+ }
531
+ // ─── State Machine ─────────────────────────────────────────────
532
+ async transition(run, to) {
533
+ const allowed = VALID_TRANSITIONS[run.status];
534
+ if (!allowed.includes(to)) {
535
+ throw new Error(`Invalid run state transition: ${run.status} -> ${to} (run ${run.runId})`);
536
+ }
537
+ run.status = to;
538
+ run.updatedAt = Date.now();
539
+ await this.store.update(run);
540
+ this.notifySubscribers(run.runId, {
541
+ type: "run_status_changed",
542
+ run: { ...run },
543
+ });
544
+ }
545
+ // ─── Event Sourcing ────────────────────────────────────────────
546
+ async emitRunEvent(runId, type, data) {
547
+ const event = {
548
+ eventId: nanoid(12),
549
+ runId,
550
+ type,
551
+ timestamp: Date.now(),
552
+ data,
553
+ };
554
+ await this.store.appendEvent(event);
555
+ this.notifySubscribers(runId, { type: "run_event", event });
556
+ }
557
+ // ─── Subscribers ───────────────────────────────────────────────
558
+ notifySubscribers(runId, event) {
559
+ const subs = this.subscribers.get(runId);
560
+ if (!subs)
561
+ return;
562
+ for (const cb of subs) {
563
+ try {
564
+ cb(event);
565
+ }
566
+ catch (err) {
567
+ // Remove broken subscriber to prevent repeated errors
568
+ subs.delete(cb);
569
+ logger.warn("run.subscriber_error", {
570
+ runId,
571
+ error: err instanceof Error ? err.message : String(err),
572
+ });
573
+ }
574
+ }
575
+ }
576
+ // ─── Helpers ───────────────────────────────────────────────────
577
+ async getOrThrow(runId) {
578
+ const run = await this.store.get(runId);
579
+ if (!run)
580
+ throw new Error(`Run not found: ${runId}`);
581
+ return run;
582
+ }
583
+ }
584
+ // ─── Type guard ─────────────────────────────────────────────────
585
+ function isRunExecutor(obj) {
586
+ return obj != null && typeof obj.execute === "function";
587
+ }