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

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 (396) hide show
  1. package/README.md +13 -10
  2. package/dist/agent/agent-definition-registry.d.ts +3 -0
  3. package/dist/agent/agent-definition-registry.js +3 -1
  4. package/dist/agent/agent-definition.d.ts +15 -0
  5. package/dist/agent/agent-definition.js +27 -3
  6. package/dist/arena/context/context-tools.js +47 -4
  7. package/dist/arena/ledger.js +9 -1
  8. package/dist/arena/strategies/utils.d.ts +1 -4
  9. package/dist/arena/strategies/utils.js +7 -84
  10. package/dist/automation/cron-expr.d.ts +10 -0
  11. package/dist/automation/cron-expr.js +23 -5
  12. package/dist/automation/runner.d.ts +21 -4
  13. package/dist/automation/runner.js +48 -12
  14. package/dist/automation/scheduler.d.ts +38 -0
  15. package/dist/automation/scheduler.js +89 -12
  16. package/dist/automation/store.js +5 -2
  17. package/dist/capability-control/disabled-lists.d.ts +25 -0
  18. package/dist/capability-control/disabled-lists.js +57 -0
  19. package/dist/capability-control/overlay.d.ts +15 -0
  20. package/dist/capability-control/overlay.js +27 -0
  21. package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
  22. package/dist/cc-orchestrator/agent-adapter.js +133 -0
  23. package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
  24. package/dist/cc-orchestrator/cc-capability.js +53 -0
  25. package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
  26. package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
  27. package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
  28. package/dist/cc-orchestrator/codex-session-history.js +187 -0
  29. package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
  30. package/dist/cc-orchestrator/external-agent-changes.js +214 -0
  31. package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
  32. package/dist/cc-orchestrator/external-agent-driver.js +69 -0
  33. package/dist/cc-orchestrator/index.d.ts +8 -0
  34. package/dist/cc-orchestrator/index.js +8 -0
  35. package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
  36. package/dist/cc-orchestrator/relevance-judge.js +29 -0
  37. package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
  38. package/dist/cc-orchestrator/session-discovery.js +125 -0
  39. package/dist/cc-orchestrator/session-history.d.ts +19 -0
  40. package/dist/cc-orchestrator/session-history.js +67 -0
  41. package/dist/cli/agent-server-stdio.d.ts +15 -1
  42. package/dist/cli/agent-server-stdio.js +115 -17
  43. package/dist/cli/agent-server-tcp.js +40 -26
  44. package/dist/context/compaction.d.ts +86 -0
  45. package/dist/context/compaction.js +279 -0
  46. package/dist/context/manager.d.ts +18 -0
  47. package/dist/context/manager.js +181 -48
  48. package/dist/context/token-counter.js +13 -0
  49. package/dist/cost-tracker.js +5 -61
  50. package/dist/credentials/cipher.d.ts +49 -0
  51. package/dist/credentials/cipher.js +45 -0
  52. package/dist/credentials/cookie-jar.d.ts +24 -0
  53. package/dist/credentials/cookie-jar.js +40 -0
  54. package/dist/credentials/index.d.ts +7 -0
  55. package/dist/credentials/index.js +5 -0
  56. package/dist/credentials/inject-credential-tool.d.ts +20 -0
  57. package/dist/credentials/inject-credential-tool.js +130 -0
  58. package/dist/credentials/store.d.ts +72 -0
  59. package/dist/credentials/store.js +184 -0
  60. package/dist/credentials/types.d.ts +56 -0
  61. package/dist/credentials/use-credential-tool.d.ts +29 -0
  62. package/dist/credentials/use-credential-tool.js +205 -0
  63. package/dist/credentials/use-gate.d.ts +56 -0
  64. package/dist/credentials/use-gate.js +52 -0
  65. package/dist/data/model-metadata.d.ts +77 -0
  66. package/dist/data/model-metadata.js +56 -0
  67. package/dist/data/model-metadata.json +216 -0
  68. package/dist/data/openrouter-models.d.ts +18 -7
  69. package/dist/data/openrouter-models.js +35 -8
  70. package/dist/engine/aux-key.d.ts +10 -0
  71. package/dist/engine/aux-key.js +11 -0
  72. package/dist/engine/dynamic-tool-defs.d.ts +19 -0
  73. package/dist/engine/dynamic-tool-defs.js +36 -0
  74. package/dist/engine/engine.d.ts +280 -141
  75. package/dist/engine/engine.js +1193 -245
  76. package/dist/engine/friendly-error.d.ts +18 -0
  77. package/dist/engine/friendly-error.js +63 -0
  78. package/dist/engine/goal.d.ts +145 -0
  79. package/dist/engine/goal.js +144 -0
  80. package/dist/engine/image-policy.d.ts +13 -0
  81. package/dist/engine/image-policy.js +24 -0
  82. package/dist/engine/model-connections-pool.d.ts +17 -0
  83. package/dist/engine/model-connections-pool.js +67 -0
  84. package/dist/engine/model-facade.d.ts +10 -0
  85. package/dist/engine/model-facade.js +15 -0
  86. package/dist/engine/patch-orphaned-tools.js +3 -0
  87. package/dist/engine/query.js +2 -0
  88. package/dist/engine/resolve-llm-config.d.ts +16 -0
  89. package/dist/engine/resolve-llm-config.js +44 -0
  90. package/dist/engine/runtime.d.ts +2 -0
  91. package/dist/engine/runtime.js +27 -1
  92. package/dist/engine/sandbox-cache-key.d.ts +10 -0
  93. package/dist/engine/sandbox-cache-key.js +9 -0
  94. package/dist/engine/sandbox-config.d.ts +31 -0
  95. package/dist/engine/sandbox-config.js +38 -0
  96. package/dist/engine/session-usage.d.ts +31 -0
  97. package/dist/engine/session-usage.js +81 -0
  98. package/dist/engine/steer-queue.d.ts +33 -0
  99. package/dist/engine/steer-queue.js +26 -0
  100. package/dist/engine/streaming-tool-queue.d.ts +12 -0
  101. package/dist/engine/streaming-tool-queue.js +50 -10
  102. package/dist/engine/turn-loop.d.ts +94 -4
  103. package/dist/engine/turn-loop.js +432 -54
  104. package/dist/engine/types.d.ts +175 -0
  105. package/dist/engine/types.js +13 -0
  106. package/dist/external-agents/config.d.ts +2 -0
  107. package/dist/external-agents/config.js +15 -0
  108. package/dist/external-agents/types.d.ts +31 -0
  109. package/dist/external-agents/types.js +1 -0
  110. package/dist/git/utils.d.ts +12 -0
  111. package/dist/git/utils.js +38 -6
  112. package/dist/git/worktree.d.ts +48 -0
  113. package/dist/git/worktree.js +86 -10
  114. package/dist/hooks/goal-stop-hook.d.ts +28 -0
  115. package/dist/hooks/goal-stop-hook.js +186 -9
  116. package/dist/hooks/registry.d.ts +8 -0
  117. package/dist/hooks/registry.js +19 -0
  118. package/dist/hooks/shell-runner.js +10 -21
  119. package/dist/index.d.ts +51 -7
  120. package/dist/index.js +62 -5
  121. package/dist/llm/capabilities/param-specs.d.ts +14 -0
  122. package/dist/llm/capabilities/param-specs.js +62 -0
  123. package/dist/llm/capabilities/rules.js +5 -1
  124. package/dist/llm/capabilities/types.d.ts +10 -0
  125. package/dist/llm/client-base.d.ts +28 -1
  126. package/dist/llm/client-base.js +119 -13
  127. package/dist/llm/model-cache.js +4 -2
  128. package/dist/llm/model-pool.d.ts +21 -0
  129. package/dist/llm/model-pool.js +21 -1
  130. package/dist/llm/provider-auth.d.ts +41 -0
  131. package/dist/llm/provider-auth.js +76 -0
  132. package/dist/llm/provider-catalog.d.ts +4 -0
  133. package/dist/llm/providers/anthropic.js +64 -14
  134. package/dist/llm/providers/openai.d.ts +36 -0
  135. package/dist/llm/providers/openai.js +257 -51
  136. package/dist/llm/reasoning-setting.d.ts +3 -3
  137. package/dist/llm/reasoning-setting.js +9 -1
  138. package/dist/llm/stream-watchdog.js +5 -1
  139. package/dist/llm/token-counter.js +9 -2
  140. package/dist/llm/types.d.ts +4 -0
  141. package/dist/logging/sanitize-messages.js +22 -0
  142. package/dist/lsp/manager.d.ts +1 -1
  143. package/dist/lsp/manager.js +40 -10
  144. package/dist/model-catalog/builtin.d.ts +12 -0
  145. package/dist/model-catalog/builtin.js +412 -0
  146. package/dist/model-catalog/gen-connections.d.ts +20 -0
  147. package/dist/model-catalog/gen-connections.js +28 -0
  148. package/dist/model-catalog/index.d.ts +41 -0
  149. package/dist/model-catalog/index.js +90 -0
  150. package/dist/model-catalog/params.d.ts +20 -0
  151. package/dist/model-catalog/params.js +45 -0
  152. package/dist/model-catalog/resolve.d.ts +48 -0
  153. package/dist/model-catalog/resolve.js +33 -0
  154. package/dist/model-catalog/save-entry.d.ts +32 -0
  155. package/dist/model-catalog/save-entry.js +104 -0
  156. package/dist/model-catalog/types.d.ts +561 -0
  157. package/dist/model-catalog/types.js +93 -0
  158. package/dist/model-catalog/upsert.d.ts +9 -0
  159. package/dist/model-catalog/upsert.js +8 -0
  160. package/dist/onboarding.d.ts +12 -82
  161. package/dist/onboarding.js +61 -326
  162. package/dist/plugins/gitOps.d.ts +19 -0
  163. package/dist/plugins/gitOps.js +73 -4
  164. package/dist/plugins/installer/checkUpdate.d.ts +16 -0
  165. package/dist/plugins/installer/checkUpdate.js +32 -0
  166. package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
  167. package/dist/plugins/installer/codex/convertCommands.js +46 -0
  168. package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
  169. package/dist/plugins/installer/codex/convertMcp.js +45 -5
  170. package/dist/plugins/installer/install.js +25 -1
  171. package/dist/plugins/installer/installFromArchive.d.ts +43 -0
  172. package/dist/plugins/installer/installFromArchive.js +134 -0
  173. package/dist/plugins/installer/installFromSource.js +8 -2
  174. package/dist/plugins/installer/loadPluginAgents.js +6 -2
  175. package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
  176. package/dist/plugins/installer/loadPluginMcp.js +35 -2
  177. package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
  178. package/dist/plugins/installer/pruneDisabled.js +73 -0
  179. package/dist/plugins/installer/types.d.ts +5 -2
  180. package/dist/plugins/installer/types.js +1 -0
  181. package/dist/plugins/installer/uninstall.js +4 -0
  182. package/dist/plugins/installer/unzip.d.ts +14 -0
  183. package/dist/plugins/installer/unzip.js +82 -0
  184. package/dist/plugins/installer/update.d.ts +14 -0
  185. package/dist/plugins/installer/update.js +53 -21
  186. package/dist/plugins/loadPluginHooks.d.ts +47 -1
  187. package/dist/plugins/loadPluginHooks.js +73 -1
  188. package/dist/plugins/marketplaceManager.d.ts +7 -0
  189. package/dist/plugins/marketplaceManager.js +20 -0
  190. package/dist/plugins/pluginCommandHook.js +4 -18
  191. package/dist/plugins/pluginContent.d.ts +30 -0
  192. package/dist/plugins/pluginContent.js +83 -0
  193. package/dist/plugins/pluginInstaller.d.ts +13 -0
  194. package/dist/plugins/pluginInstaller.js +42 -8
  195. package/dist/plugins/schemas.js +1 -0
  196. package/dist/plugins/types.d.ts +6 -0
  197. package/dist/preset/index.d.ts +11 -1
  198. package/dist/preset/index.js +115 -6
  199. package/dist/product/types.d.ts +1 -1
  200. package/dist/prompt/composer.d.ts +32 -0
  201. package/dist/prompt/composer.js +75 -21
  202. package/dist/prompt/instruction-scanner.js +5 -3
  203. package/dist/prompt/section-loader.js +1 -0
  204. package/dist/prompt/sections/base.md +2 -0
  205. package/dist/prompt/sections/browser.md +10 -0
  206. package/dist/prompt/sections/coding.md +4 -0
  207. package/dist/protocol/chat-session-manager.d.ts +9 -2
  208. package/dist/protocol/chat-session-manager.js +38 -0
  209. package/dist/protocol/chat-session.d.ts +69 -1
  210. package/dist/protocol/chat-session.js +102 -4
  211. package/dist/protocol/client.d.ts +31 -0
  212. package/dist/protocol/client.js +44 -0
  213. package/dist/protocol/server.d.ts +120 -7
  214. package/dist/protocol/server.js +753 -51
  215. package/dist/protocol/transport.js +3 -2
  216. package/dist/protocol/types.d.ts +60 -0
  217. package/dist/protocol/types.js +16 -0
  218. package/dist/quota/credentials.d.ts +3 -0
  219. package/dist/quota/credentials.js +80 -0
  220. package/dist/quota/index.d.ts +36 -0
  221. package/dist/quota/index.js +155 -0
  222. package/dist/quota/types.d.ts +48 -0
  223. package/dist/quota/types.js +13 -0
  224. package/dist/review/review-prompt.d.ts +28 -0
  225. package/dist/review/review-prompt.js +81 -0
  226. package/dist/run/FileRunStore.js +8 -3
  227. package/dist/run/RunApprovalBackend.js +25 -5
  228. package/dist/run/RunManager.d.ts +12 -0
  229. package/dist/run/RunManager.js +35 -0
  230. package/dist/run/factory.d.ts +1 -1
  231. package/dist/runtime/background-shell.d.ts +139 -0
  232. package/dist/runtime/background-shell.js +509 -0
  233. package/dist/runtime/output-clean.d.ts +24 -0
  234. package/dist/runtime/output-clean.js +41 -0
  235. package/dist/runtime/ring-file.d.ts +64 -0
  236. package/dist/runtime/ring-file.js +174 -0
  237. package/dist/runtime/safe-spawn.js +98 -39
  238. package/dist/runtime/spawn-common.d.ts +159 -0
  239. package/dist/runtime/spawn-common.js +404 -0
  240. package/dist/runtime/truncate-output.d.ts +22 -0
  241. package/dist/runtime/truncate-output.js +49 -0
  242. package/dist/runtime/utf8-cut.d.ts +11 -0
  243. package/dist/runtime/utf8-cut.js +23 -0
  244. package/dist/services/auto-dream.d.ts +4 -0
  245. package/dist/services/auto-dream.js +26 -26
  246. package/dist/services/diagnostics.d.ts +1 -2
  247. package/dist/services/diagnostics.js +12 -7
  248. package/dist/services/extract-memories.d.ts +14 -1
  249. package/dist/services/extract-memories.js +45 -6
  250. package/dist/services/memory-orchestrator.d.ts +21 -0
  251. package/dist/services/memory-orchestrator.js +125 -50
  252. package/dist/services/session-memory.js +24 -12
  253. package/dist/session/file-history.d.ts +124 -1
  254. package/dist/session/file-history.js +222 -6
  255. package/dist/session/memory.d.ts +116 -2
  256. package/dist/session/memory.js +250 -28
  257. package/dist/session/session-manager.d.ts +40 -0
  258. package/dist/session/session-manager.js +119 -3
  259. package/dist/session/simple-diff.d.ts +23 -0
  260. package/dist/session/simple-diff.js +84 -0
  261. package/dist/session/transcript.d.ts +29 -1
  262. package/dist/session/transcript.js +56 -2
  263. package/dist/session/undo-target.d.ts +67 -0
  264. package/dist/session/undo-target.js +144 -0
  265. package/dist/settings/disk-defaults.d.ts +9 -2
  266. package/dist/settings/disk-defaults.js +11 -2
  267. package/dist/settings/feature-flags.d.ts +64 -0
  268. package/dist/settings/feature-flags.js +61 -0
  269. package/dist/settings/manager.d.ts +68 -1
  270. package/dist/settings/manager.js +266 -29
  271. package/dist/settings/migrate-config.d.ts +45 -0
  272. package/dist/settings/migrate-config.js +125 -0
  273. package/dist/settings/schema-export.d.ts +25 -0
  274. package/dist/settings/schema-export.js +38 -0
  275. package/dist/settings/schema.d.ts +1186 -771
  276. package/dist/settings/schema.js +268 -97
  277. package/dist/skills/scanner.d.ts +9 -0
  278. package/dist/skills/scanner.js +30 -2
  279. package/dist/stt/resolve-transcribe.d.ts +31 -0
  280. package/dist/stt/resolve-transcribe.js +108 -0
  281. package/dist/stt/transcribe.d.ts +51 -0
  282. package/dist/stt/transcribe.js +65 -0
  283. package/dist/tool-system/browser-bridge.d.ts +226 -0
  284. package/dist/tool-system/browser-bridge.js +163 -0
  285. package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
  286. package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
  287. package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
  288. package/dist/tool-system/builtin/agent-notifications.js +9 -3
  289. package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
  290. package/dist/tool-system/builtin/agent-output-file.js +72 -0
  291. package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
  292. package/dist/tool-system/builtin/agent-registry.js +8 -0
  293. package/dist/tool-system/builtin/agent.d.ts +21 -1
  294. package/dist/tool-system/builtin/agent.js +489 -42
  295. package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
  296. package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
  297. package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
  298. package/dist/tool-system/builtin/apply-patch/index.js +0 -15
  299. package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
  300. package/dist/tool-system/builtin/background-jobs.js +124 -0
  301. package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
  302. package/dist/tool-system/builtin/background-shell-tools.js +108 -0
  303. package/dist/tool-system/builtin/background-work.d.ts +67 -0
  304. package/dist/tool-system/builtin/background-work.js +86 -0
  305. package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
  306. package/dist/tool-system/builtin/bash-output-style.js +40 -0
  307. package/dist/tool-system/builtin/bash.d.ts +5 -2
  308. package/dist/tool-system/builtin/bash.js +101 -64
  309. package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
  310. package/dist/tool-system/builtin/browser-tools.js +312 -0
  311. package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
  312. package/dist/tool-system/builtin/cancel-goal.js +64 -0
  313. package/dist/tool-system/builtin/check-quota.d.ts +15 -0
  314. package/dist/tool-system/builtin/check-quota.js +34 -0
  315. package/dist/tool-system/builtin/config.js +7 -0
  316. package/dist/tool-system/builtin/cron.d.ts +7 -0
  317. package/dist/tool-system/builtin/cron.js +64 -4
  318. package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
  319. package/dist/tool-system/builtin/drive-claude-code.js +157 -0
  320. package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
  321. package/dist/tool-system/builtin/edit-model-catalog.js +104 -0
  322. package/dist/tool-system/builtin/edit.js +20 -16
  323. package/dist/tool-system/builtin/eol.d.ts +29 -0
  324. package/dist/tool-system/builtin/eol.js +37 -0
  325. package/dist/tool-system/builtin/file-cache.d.ts +6 -0
  326. package/dist/tool-system/builtin/file-cache.js +8 -0
  327. package/dist/tool-system/builtin/generate-image.d.ts +35 -0
  328. package/dist/tool-system/builtin/generate-image.js +278 -50
  329. package/dist/tool-system/builtin/generate-video.d.ts +55 -0
  330. package/dist/tool-system/builtin/generate-video.js +364 -0
  331. package/dist/tool-system/builtin/glob.js +0 -7
  332. package/dist/tool-system/builtin/grep.d.ts +9 -0
  333. package/dist/tool-system/builtin/grep.js +106 -11
  334. package/dist/tool-system/builtin/image-providers.d.ts +86 -0
  335. package/dist/tool-system/builtin/image-providers.js +190 -0
  336. package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
  337. package/dist/tool-system/builtin/image-uploader.js +74 -0
  338. package/dist/tool-system/builtin/index.d.ts +10 -2
  339. package/dist/tool-system/builtin/index.js +251 -27
  340. package/dist/tool-system/builtin/mcp-tools.js +23 -3
  341. package/dist/tool-system/builtin/memory.js +45 -7
  342. package/dist/tool-system/builtin/notebook-edit.js +0 -7
  343. package/dist/tool-system/builtin/powershell.js +8 -2
  344. package/dist/tool-system/builtin/read.js +10 -10
  345. package/dist/tool-system/builtin/repl.js +4 -1
  346. package/dist/tool-system/builtin/skill.js +9 -0
  347. package/dist/tool-system/builtin/sleep.js +8 -2
  348. package/dist/tool-system/builtin/tool-search.js +25 -7
  349. package/dist/tool-system/builtin/video-providers.d.ts +154 -0
  350. package/dist/tool-system/builtin/video-providers.js +235 -0
  351. package/dist/tool-system/builtin/web-fetch.js +12 -2
  352. package/dist/tool-system/builtin/web-search.js +21 -7
  353. package/dist/tool-system/builtin/worktree.d.ts +2 -1
  354. package/dist/tool-system/builtin/worktree.js +31 -4
  355. package/dist/tool-system/builtin/write.js +0 -6
  356. package/dist/tool-system/context.d.ts +164 -6
  357. package/dist/tool-system/executor.d.ts +3 -1
  358. package/dist/tool-system/executor.js +197 -90
  359. package/dist/tool-system/investigation-guard.js +1 -1
  360. package/dist/tool-system/mcp-manager.d.ts +42 -4
  361. package/dist/tool-system/mcp-manager.js +203 -20
  362. package/dist/tool-system/mcp-stdio-diagnostics.d.ts +9 -0
  363. package/dist/tool-system/mcp-stdio-diagnostics.js +93 -0
  364. package/dist/tool-system/path-policy.d.ts +5 -0
  365. package/dist/tool-system/path-policy.js +307 -8
  366. package/dist/tool-system/permission.d.ts +39 -2
  367. package/dist/tool-system/permission.js +283 -70
  368. package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
  369. package/dist/tool-system/plan-mode-allowlist.js +24 -2
  370. package/dist/tool-system/registry.d.ts +1 -0
  371. package/dist/tool-system/registry.js +16 -2
  372. package/dist/tool-system/sandbox/index.d.ts +8 -0
  373. package/dist/tool-system/sandbox/index.js +7 -2
  374. package/dist/tool-system/sandbox/off.js +7 -1
  375. package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
  376. package/dist/tool-system/validate-tool-metadata.js +63 -0
  377. package/dist/types.d.ts +252 -7
  378. package/dist/updater.js +20 -9
  379. package/dist/utils/envUtils.d.ts +0 -9
  380. package/dist/utils/envUtils.js +3 -28
  381. package/dist/utils/exec.d.ts +48 -0
  382. package/dist/utils/exec.js +154 -0
  383. package/dist/utils/json.d.ts +12 -0
  384. package/dist/utils/json.js +92 -0
  385. package/dist/utils/theme.d.ts +1 -1
  386. package/dist/utils/theme.js +1 -1
  387. package/dist/utils/toolDisplay.js +0 -1
  388. package/package.json +13 -7
  389. package/dist/agent/coordinator.d.ts +0 -49
  390. package/dist/agent/coordinator.js +0 -77
  391. package/dist/settings/manager.test.js +0 -73
  392. package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
  393. package/dist/tool-system/builtin/remote-trigger.js +0 -54
  394. package/dist/tool-system/builtin/send-message.d.ts +0 -6
  395. package/dist/tool-system/builtin/send-message.js +0 -47
  396. /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
@@ -31,8 +31,13 @@ export class PromptComposer {
31
31
  */
32
32
  buildUserContextMessage() {
33
33
  const instructions = this.getInstructions();
34
- const memoryContext = this.getMemoryContext();
35
- if (!instructions && !memoryContext)
34
+ // NOTE: memory is intentionally NOT here. It used to be, but memory mutates
35
+ // constantly (extraction, recall usage++/lastUsed, approve/demote), and this
36
+ // message sits in the cacheable system prefix — so every memory change
37
+ // invalidated the whole prefix and re-billed it. Memory now rides
38
+ // buildDynamicContextMessage (tail, past the cache breakpoint), same as the
39
+ // skills listing and git status which had the identical problem.
40
+ if (!instructions)
36
41
  return null;
37
42
  // Local date, not UTC — toISOString() is UTC and would show the wrong
38
43
  // "today" for users whose timezone has crossed midnight (review-2026-05-30).
@@ -40,10 +45,7 @@ export class PromptComposer {
40
45
  const ymd = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, "0")}-${String(now.getDate()).padStart(2, "0")}`;
41
46
  const currentDate = `Today's date is ${ymd}.`;
42
47
  let content = `<system-reminder>\n${currentDate}\n\n`;
43
- if (instructions)
44
- content += `${instructions}\n\n`;
45
- if (memoryContext)
46
- content += `${memoryContext}\n`;
48
+ content += `${instructions}\n`;
47
49
  content += `</system-reminder>`;
48
50
  return { role: "user", content };
49
51
  }
@@ -87,6 +89,46 @@ export class PromptComposer {
87
89
  }
88
90
  return gitStatus;
89
91
  }
92
+ /**
93
+ * Per-turn dynamic context, delivered as a trailing <system-reminder> user
94
+ * message rather than baked into the system prefix.
95
+ *
96
+ * Holds the two things that change *within* a session — the skills listing
97
+ * (changes when a skill is installed/disabled) and the git-status snapshot
98
+ * (changes whenever the working tree changes). Keeping them out of the
99
+ * system prompt means installing a skill or editing a file no longer
100
+ * invalidates the cached system prefix. Placed at the END of the messages
101
+ * array (after the user task) so it sits past the conversation's cache
102
+ * breakpoint — a change here never re-bills the history prefix.
103
+ */
104
+ async buildDynamicContextMessage() {
105
+ const skills = scanSkills(this.options.cwd, {
106
+ disabledSkills: this.options.disabledSkills,
107
+ disabledPlugins: this.options.disabledPlugins,
108
+ skillAllowlist: this.options.skillAllowlist,
109
+ });
110
+ const skillsListing = buildSkillListing(skills);
111
+ const gitStatus = await this.buildSystemContext();
112
+ // Memory rides here (tail, past the cache breakpoint) — not the system
113
+ // prefix — so a memory change (extraction / recall usage++ / approve) never
114
+ // re-bills the cached prefix. See buildUserContextMessage for the rationale.
115
+ const memoryContext = this.getMemoryContext();
116
+ const goalToolContext = this.buildGoalToolContext();
117
+ const parts = [skillsListing, gitStatus, memoryContext, goalToolContext].filter(Boolean);
118
+ if (parts.length === 0)
119
+ return null;
120
+ return {
121
+ role: "user",
122
+ content: `<system-reminder>\n${parts.join("\n\n")}\n</system-reminder>`,
123
+ };
124
+ }
125
+ buildGoalToolContext() {
126
+ if (!this.options.goalToolState)
127
+ return "";
128
+ return this.options.goalToolState.hasGoal
129
+ ? "当前存在 active goal。只有在目标完全完成时才可调用 complete_goal;只有用户明确要求取消/停止/放弃该目标时才可调用 cancel_goal。"
130
+ : "当前没有 active goal。不要调用 complete_goal/cancel_goal;如果误调用,系统会拒绝。";
131
+ }
90
132
  invalidateCache(sectionName) {
91
133
  this.sectionCache.invalidate(sectionName);
92
134
  if (!sectionName) {
@@ -129,25 +171,31 @@ export class PromptComposer {
129
171
  },
130
172
  });
131
173
  }
132
- // Behavioral instructions — loaded from preset's section files
174
+ // Behavioral instructions — loaded from preset's section files. Pass the
175
+ // turn's effective tool names so tool-gated sections (e.g. "browser") drop
176
+ // when their tools are disabled: browser capability = tools + instructions
177
+ // as one on/off unit.
178
+ const activeToolNames = tools.map((t) => t.name);
133
179
  sections.push({
134
180
  name: "behavior",
181
+ // cacheBreak: this section's content varies by activeToolNames (tool-gated
182
+ // sections like "browser" drop when their tools are off). The cache is
183
+ // keyed by section NAME only, so without cacheBreak a reused composer could
184
+ // serve a stale behavior block across an on/off change. Recompute always —
185
+ // it's a cheap string join, and it makes the browser on/off unit correct
186
+ // regardless of composer lifetime.
187
+ cacheBreak: true,
135
188
  compute: () => {
136
189
  const preset = this.options.preset ?? resolveAgentPreset();
137
- return buildPresetSystemPrompt(preset);
138
- },
139
- });
140
- // Skills listing
141
- sections.push({
142
- name: "skills",
143
- compute: () => {
144
- const skills = scanSkills(this.options.cwd, {
145
- disabledSkills: this.options.disabledSkills,
146
- disabledPlugins: this.options.disabledPlugins,
147
- });
148
- return buildSkillListing(skills);
190
+ return buildPresetSystemPrompt(preset, { activeToolNames, platform: process.platform });
149
191
  },
150
192
  });
193
+ // Skills listing is intentionally NOT a system section: it changes when a
194
+ // skill is installed/disabled, which would invalidate the whole cached
195
+ // system prefix on every change. It rides in the per-turn dynamic-context
196
+ // message instead (buildDynamicContextMessage). Same reasoning keeps the
197
+ // git-status snapshot out of the system prefix — see buildSystemContext's
198
+ // callers.
151
199
  // Append system prompt
152
200
  if (this.options.appendSystemPrompt) {
153
201
  sections.push({
@@ -183,8 +231,14 @@ export class PromptComposer {
183
231
  }
184
232
  getMemoryContext() {
185
233
  try {
186
- const mm = new MemoryManager(this.options.cwd);
187
- return mm.buildMemoryContext();
234
+ // Two-layer injection (用户拍板): a compact index merging GLOBAL +
235
+ // PROJECT memories. Global memories are now surfaced every session
236
+ // regardless of cwd (the fix for "global memory never shows up"); the
237
+ // model reads full bodies on demand via MemoryRead.
238
+ return MemoryManager.buildInjectionIndex({
239
+ projectDir: this.options.cwd,
240
+ maxAgeDays: this.options.memoriesMaxAgeDays,
241
+ });
188
242
  }
189
243
  catch {
190
244
  return "";
@@ -17,7 +17,7 @@
17
17
  import { readFileSync, existsSync, readdirSync, statSync } from "node:fs";
18
18
  import { join, dirname, resolve } from "node:path";
19
19
  import { execSync } from "node:child_process";
20
- import { homedir } from "node:os";
20
+ import { userHome } from "../settings/manager.js";
21
21
  // ─── Public API ─────────────────────────────────────────────────────
22
22
  /**
23
23
  * Scan for instruction files from cwd up to the project root,
@@ -32,8 +32,10 @@ export function scanInstructions(cwd, options = {}) {
32
32
  const configDirs = [".codeshell", ...(options.scanDirs ?? []), ".claude"];
33
33
  const entries = [];
34
34
  // 1. User-level instructions
35
- const homeConfigDir = join(homedir(), ".code-shell");
36
- const homeCompatDir = join(homedir(), ".claude");
35
+ // userHome() (not raw homedir(), bun-cached) so a test/host HOME override
36
+ // scans the intended user-level dirs, not the developer's real ~/.code-shell.
37
+ const homeConfigDir = join(userHome(), ".code-shell");
38
+ const homeCompatDir = join(userHome(), ".claude");
37
39
  for (const name of allNames) {
38
40
  tryAddFile(join(homeConfigDir, name), "user", -1, entries);
39
41
  }
@@ -13,6 +13,7 @@ const BUILTIN_SECTIONS = {
13
13
  base: readSectionFile("base"),
14
14
  orchestration: readSectionFile("orchestration"),
15
15
  coding: readSectionFile("coding"),
16
+ browser: readSectionFile("browser"),
16
17
  tone: readSectionFile("tone"),
17
18
  };
18
19
  /** Registry for custom sections added at runtime. */
@@ -31,5 +31,7 @@ When you encounter an obstacle, do not use destructive actions as a shortcut to
31
31
  - To search for files use Glob instead of find or ls
32
32
  - To search the content of files, use Grep instead of grep or rg
33
33
  - Reserve using the Bash exclusively for system commands and terminal operations that require shell execution.
34
+ - Shell choice: use Bash for ordinary shell commands, git operations, package-manager commands, test/build scripts, and POSIX-style command lines. Use PowerShell only when the user explicitly asks for it or the task requires PowerShell-specific cmdlets, Windows APIs, registry access, or `.ps1` behavior.
35
+ - For long-lived processes that don't exit on their own — a dev server (`npm run dev`, `vite`), a watcher, a tunnel — call Bash with `run_in_background: true`. It returns a `shell_id` immediately instead of blocking until a timeout. Then use `BashOutput(shell_id)` to read its logs (e.g. to confirm it started or to see an error), `ListShells()` to see what's running, and `KillShell(shell_id)` to stop it. Never run such a command in the foreground — it will just block until it's killed. Plain one-shot commands (build, test, git) stay foreground.
34
36
  - Break down and manage multi-step work with the TodoWrite tool. Pass the complete todo list each call; rewrite it as items move pending → in_progress → completed.
35
37
  - You can call multiple tools in a single response. If you intend to call multiple tools and there are no dependencies between them, make all independent tool calls in parallel.
@@ -0,0 +1,10 @@
1
+ ## Browser automation (browser_observe / browser_act / browser_navigate)
2
+ - When a task needs you to operate a real web page — search a site, open a result, read/extract an article, fill a form — drive the built-in browser panel with the three browser tools. They run on the panel's logged-in session, so the user's existing logins are reused.
3
+ - You do NOT need the user to open the panel first: if none is open, just call `browser_navigate{url}` and the panel opens automatically. After navigating, `browser_act{action:"wait"}` then `browser_observe`.
4
+ - The loop is observe → act → re-observe: ALWAYS `browser_observe` first (default mode `snapshot`) to see the page's interactive elements (each tagged `[ref=eN]`), then `browser_act` on elements BY THAT ref: `{action:"click",ref}`, `{action:"type",ref,text}`, `{action:"select",ref,value}` (native `<select>`), `{action:"hover",ref}`. Refs are only valid for the most recent snapshot — after any navigation, content-loading click, or `{action:"scroll"}`, run `{action:"wait"}` then `browser_observe` again. If an action says a ref is stale, re-observe.
5
+ - To submit a search: `browser_act{action:"type",ref,text}` into the search box, then `browser_act{action:"press_key",key:"Enter"}`, then `{action:"wait"}` + `browser_observe`. `press_key` also does Tab / Escape / arrows / combos like `Control+a`.
6
+ - To extract/summarize page content, navigate/click to it, `browser_act{action:"wait"}`, then `browser_observe{mode:"read"}` — cleaned readable text to summarize (long pages truncate; `{action:"scroll"}` + read again). For the real link/image/video URLs the snapshot omits, use `browser_observe{mode:"extract"}` (each image/video tagged [ref=imgN/vidN]).
7
+ - To SEE an actual image's content (e.g. a 小红书 笔记配图 or product photo), `browser_observe{mode:"extract"}` to get image refs, then `browser_observe{mode:"image", refs:["img3"]}` — it loads the real pixels (works behind hotlink protection). A vidN ref grabs the video's current frame. To see the rendered layout/canvas/chart, `browser_observe{mode:"vision"}` (optionally `ref` for one region). Use images sparingly — they cost tokens; prefer snapshot/read. (Both need a vision-capable model; on a non-vision model they're skipped.) Do NOT repeat `vision` on the same page hoping for a clearer view — one screenshot is all you get. If snapshot/screenshot don't reveal what you need (infinite-scroll/canvas feeds), scroll + re-observe or extract the URLs and act on them — don't loop screenshots.
8
+ - Multiple tabs: `browser_act{action:"list_tabs"}` shows open tabs (tabId/url/title/active); `browser_act{action:"switch_tab", tabId}` makes another the active one (then re-observe). Any action also accepts `tabId` to target a specific tab (it switches first). Refs are per-tab — re-observe after switching.
9
+ - If `browser_observe` reports a sign-in is required (or you hit a login wall / 2FA), STOP and ask the user to log in manually in the browser panel, then continue — do not attempt to enter credentials yourself. Sensitive actions (payment, delete, entering card/password values) require user approval.
10
+ - These tools need the desktop app's browser panel; if they report unavailable, the environment has no panel (headless) — say so rather than retrying.
@@ -26,6 +26,10 @@ The default job in this preset is software engineering in the current working di
26
26
  - When referencing specific functions or pieces of code include the pattern file_path:line_number to allow the user to easily navigate to the source code location.
27
27
  - When referencing GitHub issues or pull requests, use the owner/repo#123 format so they render as clickable links.
28
28
 
29
+ ## Opening URLs and local previews
30
+ - To show the user a web page or a local dev-server preview, print the address in your reply as a bare URL or a markdown link (e.g. `http://localhost:5173` or [预览](http://localhost:5173)) — do NOT wrap it in backticks. The desktop app turns a link in your answer into a clickable link that opens inside its built-in browser panel; backtick-wrapped URLs render as plain code and are not clickable.
31
+ - Do NOT run shell commands to open a URL (`open <url>` on macOS, `xdg-open` on Linux, `start <url>` on Windows). Those launch the user's external system browser and bypass the in-app browser panel. Start the dev server, then just tell the user the address as a link.
32
+
29
33
  ## Coding tools
30
34
  - Use git/worktree/LSP/notebook tools when they help, but treat them as optional helpers rather than core assumptions.
31
35
  - If the user asks for help or feedback, point them to /help and the project repository.
@@ -1,8 +1,8 @@
1
1
  import { ChatSession } from "./chat-session.js";
2
2
  import type { Engine } from "../engine/engine.js";
3
3
  import type { EngineRuntime } from "../engine/runtime.js";
4
- import type { EngineConfig } from "../engine/engine.js";
5
- export type EngineConfigSlice = Pick<EngineConfig, "permissionMode" | "preset" | "customSystemPrompt" | "appendSystemPrompt" | "goal" | "maxTurns" | "maxContextTokens" | "cwd">;
4
+ import type { EngineConfig } from "../engine/types.js";
5
+ export type EngineConfigSlice = Pick<EngineConfig, "permissionMode" | "preset" | "customSystemPrompt" | "appendSystemPrompt" | "goal" | "maxTurns" | "maxContextTokens" | "cwd" | "projectTrusted">;
6
6
  export interface ChatSessionManagerOptions {
7
7
  /**
8
8
  * Shared runtime, supplied here so callers and engineFactory closures
@@ -17,6 +17,7 @@ export interface ChatSessionManagerOptions {
17
17
  }
18
18
  export declare class ChatSessionManager {
19
19
  private readonly sessions;
20
+ readonly runtime: EngineRuntime;
20
21
  private readonly factory;
21
22
  private readonly maxSessions;
22
23
  private readonly idleTtlMs;
@@ -33,6 +34,12 @@ export declare class ChatSessionManager {
33
34
  forEachSession(fn: (s: ChatSession) => void): void;
34
35
  close(sessionId: string): void;
35
36
  closeAll(): void;
37
+ /**
38
+ * Await-able shutdown. Cancels every session and reaps every background
39
+ * shell, *waiting* for the kill grace so a caller that exits the process
40
+ * immediately afterward (the TUI REPL) doesn't orphan detached dev servers.
41
+ */
42
+ closeAllAsync(): Promise<void>;
36
43
  sessionCount(): number;
37
44
  sweepIdle(): void;
38
45
  startIdleSweeper(intervalMs?: number): void;
@@ -1,11 +1,15 @@
1
1
  import { ChatSession } from "./chat-session.js";
2
+ import { backgroundShellManager } from "../runtime/background-shell.js";
3
+ import { clearAgentOutputFiles } from "../tool-system/builtin/agent-output-file.js";
2
4
  export class ChatSessionManager {
3
5
  sessions = new Map();
6
+ runtime;
4
7
  factory;
5
8
  maxSessions;
6
9
  idleTtlMs;
7
10
  sweeper = null;
8
11
  constructor(opts) {
12
+ this.runtime = opts.runtime;
9
13
  this.factory = opts.engineFactory;
10
14
  this.maxSessions = opts.maxSessions ?? 16;
11
15
  this.idleTtlMs = opts.idleTtlMs ?? 30 * 60 * 1000;
@@ -14,6 +18,17 @@ export class ChatSessionManager {
14
18
  const existing = this.sessions.get(sessionId);
15
19
  if (existing) {
16
20
  existing.lastActivityAt = Date.now();
21
+ // Re-apply the per-send permission mode so a pill change on an
22
+ // already-running session takes effect on the NEXT turn. Without this the
23
+ // engine kept whatever mode it was first created with — changing the pill
24
+ // on a resumed session was silently ignored at enforcement time (#11
25
+ // secondary: "档位 doesn't take effect after first send"). setPermissionMode
26
+ // reconfigures the live permission backend, so it's safe between turns.
27
+ if (slice.permissionMode &&
28
+ typeof existing.engine.getPermissionMode === "function" &&
29
+ existing.engine.getPermissionMode() !== slice.permissionMode) {
30
+ existing.engine.setPermissionMode(slice.permissionMode);
31
+ }
17
32
  return existing;
18
33
  }
19
34
  if (this.sessions.size >= this.maxSessions) {
@@ -47,8 +62,31 @@ export class ChatSessionManager {
47
62
  this.sessions.delete(sessionId);
48
63
  }
49
64
  closeAll() {
65
+ // Fire-and-forget variant for callers that can't await (e.g. AgentServer
66
+ // teardown inside a sync stop path). The TUI exit path uses closeAllAsync()
67
+ // below so the SIGTERM→SIGKILL grace actually completes before the process
68
+ // exits — otherwise startInkRepl's process.exit(0) races the kill and the
69
+ // detached shells leak as orphans.
70
+ void this.closeAllAsync();
71
+ }
72
+ /**
73
+ * Await-able shutdown. Cancels every session and reaps every background
74
+ * shell, *waiting* for the kill grace so a caller that exits the process
75
+ * immediately afterward (the TUI REPL) doesn't orphan detached dev servers.
76
+ */
77
+ async closeAllAsync() {
50
78
  for (const id of [...this.sessions.keys()])
51
79
  this.close(id);
80
+ // App/worker shutdown — reap every background shell so a detached
81
+ // `npm run dev` doesn't outlive the process as an orphan holding a port
82
+ // (design §6 / §难点1). NOTE: deliberately NOT in close()/sweepIdle() —
83
+ // an idle chat tab must keep its dev server alive (§6 "切走再回来 server 还在").
84
+ await backgroundShellManager.killAll();
85
+ // Background-agent output files are a debugging convenience, not durable
86
+ // state — wipe them on shutdown so ~/.code-shell/agents doesn't grow
87
+ // unbounded across runs. (notificationQueue, the real result path, is
88
+ // in-memory and already gone.)
89
+ await clearAgentOutputFiles();
52
90
  }
53
91
  sessionCount() {
54
92
  return this.sessions.size;
@@ -1,4 +1,5 @@
1
1
  import type { Engine, EngineResult } from "../engine/engine.js";
2
+ import type { ModelEntry } from "../llm/model-pool.js";
2
3
  import type { StreamEvent } from "../types.js";
3
4
  export interface ChatSessionOptions {
4
5
  id: string;
@@ -13,6 +14,12 @@ export interface TurnOpts {
13
14
  /** Goal mode for this turn — forwarded to engine.run (loop-until-done).
14
15
  * String objective or full GoalConfig (objective + optional budgets). */
15
16
  goal?: string | import("../engine/goal.js").GoalConfig;
17
+ /** Marks this turn as a synthetic system-reminder injection (background-job
18
+ * completion notification) rather than the user's own input — persisted so
19
+ * the disk reader skips it as a user bubble on replay. See Engine.run. */
20
+ injected?: boolean;
21
+ /** Stable id for this user-intent; forwarded to Engine.run for idempotency. */
22
+ clientMessageId?: string;
16
23
  }
17
24
  /**
18
25
  * One ChatSession per UI chat tab. Owns a single Engine, an AbortController
@@ -42,8 +49,32 @@ export declare class ChatSession {
42
49
  * session-isolation research flagged. null = nothing pending.
43
50
  */
44
51
  private pendingModel;
52
+ /**
53
+ * Set by cancel() so the in-flight turn's abort error resolves as a clean
54
+ * "cancelled" result instead of rejecting (which the RPC layer would surface
55
+ * as a scary red Error in the UI for what was a user-initiated Stop). The
56
+ * onboarding flow cancels + immediately re-runs the same task; without this
57
+ * the cancelled first run popped "Error: Request cancelled".
58
+ */
59
+ private cancelledActive;
60
+ /**
61
+ * Sticky flag: the user cancelled (Stop) and has not started a new turn
62
+ * since. cancel() leaves the session idle (active=null), so isBusy() can't
63
+ * distinguish "naturally idle" from "user just stopped me". A background-job
64
+ * completion that lands in this window must NOT auto-resume the session —
65
+ * that would defeat the Stop. Cleared the moment a real turn is enqueued
66
+ * (the user is engaging again) so normal wakeups resume working afterward.
67
+ */
68
+ private cancelledSinceLastTurn;
45
69
  constructor(opts: ChatSessionOptions);
46
70
  enqueueTurn(task: string, opts: TurnOpts): Promise<EngineResult>;
71
+ /**
72
+ * True when the user hit Stop and hasn't started a new turn since. The server
73
+ * consults this before auto-waking an idle session on a background-job
74
+ * completion, so a download finishing right after Stop doesn't restart the
75
+ * agent the user just halted.
76
+ */
77
+ wasCancelledSinceLastTurn(): boolean;
47
78
  /**
48
79
  * Abort the in-flight turn and drain queued turns.
49
80
  *
@@ -54,13 +85,50 @@ export declare class ChatSession {
54
85
  */
55
86
  cancel(): void;
56
87
  isBusy(): boolean;
88
+ /**
89
+ * Extend the in-flight goal run's turn/budget ceilings (TODO 3.1). Delegates
90
+ * to the engine, which forwards to the active TurnLoop. Returns null when no
91
+ * run is active (or the run has no extendable loop). Mirrors the cancel()
92
+ * mid-run control path.
93
+ */
94
+ extendGoalRun(opts: {
95
+ addTurns?: number;
96
+ addTokenBudget?: number;
97
+ addTimeBudgetMs?: number;
98
+ addStopBlocks?: number;
99
+ }): {
100
+ maxTurns: number;
101
+ tokenBudget?: number;
102
+ timeBudgetMs?: number;
103
+ maxStopBlocks: number;
104
+ } | null;
105
+ /**
106
+ * Read this session's persisted active goal (state.activeGoal), or undefined
107
+ * when none. Cheap — reads only state.json. The host calls this on session
108
+ * load to re-surface the goal block + Cancel button after a reload.
109
+ */
110
+ getGoal(): import("../engine/goal.js").GoalConfig | undefined;
111
+ /**
112
+ * Clear this session's persisted active goal (CC /goal clear). Works idle or
113
+ * mid-run. Returns true if a goal was actually cleared.
114
+ */
115
+ clearGoal(): boolean;
57
116
  /**
58
117
  * Switch this session's active model (per-session, not worker-global).
59
118
  * Applies immediately when idle; defers to the next run boundary when a
60
119
  * turn is in flight so a hot switch never mutates the model under a
61
120
  * running LLM client.
62
121
  */
63
- requestModelSwitch(key: string): void;
122
+ requestModelSwitch(key: string): ModelEntry;
123
+ /**
124
+ * Perform the actual model switch for this session: rotate the engine's model
125
+ * and reset the session's cumulative usage on disk — a different model has a
126
+ * different prompt cache, so the old cache-hit stats no longer apply. The
127
+ * renderer zeroes its own cumulative display when it issues the switch (it's
128
+ * renderer-initiated), so no stream event is needed here. Shared by the idle
129
+ * path and the deferred run-boundary path.
130
+ */
131
+ private applyModelSwitch;
64
132
  queueDepth(): number;
65
133
  private pump;
66
134
  }
@@ -1,3 +1,4 @@
1
+ import { isAbortError } from "../llm/client-base.js";
1
2
  /**
2
3
  * One ChatSession per UI chat tab. Owns a single Engine, an AbortController
3
4
  * for the active turn, and a FIFO queue so a fast second send waits for the
@@ -26,6 +27,23 @@ export class ChatSession {
26
27
  * session-isolation research flagged. null = nothing pending.
27
28
  */
28
29
  pendingModel = null;
30
+ /**
31
+ * Set by cancel() so the in-flight turn's abort error resolves as a clean
32
+ * "cancelled" result instead of rejecting (which the RPC layer would surface
33
+ * as a scary red Error in the UI for what was a user-initiated Stop). The
34
+ * onboarding flow cancels + immediately re-runs the same task; without this
35
+ * the cancelled first run popped "Error: Request cancelled".
36
+ */
37
+ cancelledActive = false;
38
+ /**
39
+ * Sticky flag: the user cancelled (Stop) and has not started a new turn
40
+ * since. cancel() leaves the session idle (active=null), so isBusy() can't
41
+ * distinguish "naturally idle" from "user just stopped me". A background-job
42
+ * completion that lands in this window must NOT auto-resume the session —
43
+ * that would defeat the Stop. Cleared the moment a real turn is enqueued
44
+ * (the user is engaging again) so normal wakeups resume working afterward.
45
+ */
46
+ cancelledSinceLastTurn = false;
29
47
  constructor(opts) {
30
48
  this.id = opts.id;
31
49
  this.engine = opts.engine;
@@ -33,11 +51,24 @@ export class ChatSession {
33
51
  }
34
52
  enqueueTurn(task, opts) {
35
53
  this.lastActivityAt = Date.now();
54
+ // The user (or a wakeup the guard already let through) is starting a turn —
55
+ // clear the post-Stop suppression so future background-job completions
56
+ // wake the session again.
57
+ this.cancelledSinceLastTurn = false;
36
58
  return new Promise((resolve, reject) => {
37
59
  this.queue.push({ task, opts, resolve, reject });
38
60
  this.pump();
39
61
  });
40
62
  }
63
+ /**
64
+ * True when the user hit Stop and hasn't started a new turn since. The server
65
+ * consults this before auto-waking an idle session on a background-job
66
+ * completion, so a download finishing right after Stop doesn't restart the
67
+ * agent the user just halted.
68
+ */
69
+ wasCancelledSinceLastTurn() {
70
+ return this.cancelledSinceLastTurn;
71
+ }
41
72
  /**
42
73
  * Abort the in-flight turn and drain queued turns.
43
74
  *
@@ -47,6 +78,12 @@ export class ChatSession {
47
78
  * are always rejected regardless.
48
79
  */
49
80
  cancel() {
81
+ // Mark the in-flight turn as user-cancelled so pump()'s catch resolves it
82
+ // as a clean aborted result rather than rejecting (→ UI Error).
83
+ if (this.active)
84
+ this.cancelledActive = true;
85
+ // Suppress auto-wakeup until the user engages again (see the field doc).
86
+ this.cancelledSinceLastTurn = true;
50
87
  this.controller?.abort();
51
88
  // Drain queued turns as cancelled
52
89
  const drained = this.queue.splice(0);
@@ -57,6 +94,30 @@ export class ChatSession {
57
94
  isBusy() {
58
95
  return this.active !== null;
59
96
  }
97
+ /**
98
+ * Extend the in-flight goal run's turn/budget ceilings (TODO 3.1). Delegates
99
+ * to the engine, which forwards to the active TurnLoop. Returns null when no
100
+ * run is active (or the run has no extendable loop). Mirrors the cancel()
101
+ * mid-run control path.
102
+ */
103
+ extendGoalRun(opts) {
104
+ return this.engine.extendGoalRun(opts);
105
+ }
106
+ /**
107
+ * Read this session's persisted active goal (state.activeGoal), or undefined
108
+ * when none. Cheap — reads only state.json. The host calls this on session
109
+ * load to re-surface the goal block + Cancel button after a reload.
110
+ */
111
+ getGoal() {
112
+ return this.engine.getGoal(this.id);
113
+ }
114
+ /**
115
+ * Clear this session's persisted active goal (CC /goal clear). Works idle or
116
+ * mid-run. Returns true if a goal was actually cleared.
117
+ */
118
+ clearGoal() {
119
+ return this.engine.clearGoal(this.id);
120
+ }
60
121
  /**
61
122
  * Switch this session's active model (per-session, not worker-global).
62
123
  * Applies immediately when idle; defers to the next run boundary when a
@@ -65,10 +126,27 @@ export class ChatSession {
65
126
  */
66
127
  requestModelSwitch(key) {
67
128
  if (this.isBusy()) {
129
+ const pool = this.engine.getModelPool();
130
+ const entry = pool.get(key);
131
+ if (!entry)
132
+ throw new Error(`Model not found: ${key}`);
68
133
  this.pendingModel = key;
69
- return;
134
+ return entry;
70
135
  }
71
- this.engine.switchModel(key);
136
+ return this.applyModelSwitch(key);
137
+ }
138
+ /**
139
+ * Perform the actual model switch for this session: rotate the engine's model
140
+ * and reset the session's cumulative usage on disk — a different model has a
141
+ * different prompt cache, so the old cache-hit stats no longer apply. The
142
+ * renderer zeroes its own cumulative display when it issues the switch (it's
143
+ * renderer-initiated), so no stream event is needed here. Shared by the idle
144
+ * path and the deferred run-boundary path.
145
+ */
146
+ applyModelSwitch(key) {
147
+ const entry = this.engine.switchModel(key);
148
+ this.engine.resetSessionUsage(this.id);
149
+ return entry;
72
150
  }
73
151
  queueDepth() {
74
152
  return this.queue.length;
@@ -80,6 +158,7 @@ export class ChatSession {
80
158
  if (!next)
81
159
  return;
82
160
  this.active = next;
161
+ this.cancelledActive = false;
83
162
  this.controller = new AbortController();
84
163
  try {
85
164
  const onStream = next.opts.onStream ?? this.defaultOnStream;
@@ -89,21 +168,40 @@ export class ChatSession {
89
168
  signal: this.controller.signal,
90
169
  onStream,
91
170
  goal: next.opts.goal,
171
+ injected: next.opts.injected,
172
+ clientMessageId: next.opts.clientMessageId,
92
173
  });
93
174
  this.lastActivityAt = Date.now();
94
175
  next.resolve(result);
95
176
  }
96
177
  catch (err) {
97
- next.reject(err);
178
+ // A user-initiated cancel (Stop, or the onboarding cancel+rerun flow)
179
+ // aborts the in-flight run. That's not a failure — resolve it as a clean
180
+ // aborted result so the RPC layer doesn't surface "Error: Request
181
+ // cancelled" in the UI. Only abort errors on a cancelled turn are
182
+ // swallowed this way; a genuine error still rejects.
183
+ if (this.cancelledActive && (isAbortError(err) || this.controller?.signal.aborted)) {
184
+ next.resolve({
185
+ text: "",
186
+ reason: "aborted_streaming",
187
+ sessionId: this.id,
188
+ turnCount: 0,
189
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
190
+ });
191
+ }
192
+ else {
193
+ next.reject(err);
194
+ }
98
195
  }
99
196
  finally {
100
197
  this.active = null;
101
198
  this.controller = null;
199
+ this.cancelledActive = false;
102
200
  // Run boundary: apply any model switch that was deferred because it was
103
201
  // requested mid-run. Done here (not in pump) so it still applies when
104
202
  // no further turn is queued.
105
203
  if (this.pendingModel !== null) {
106
- this.engine.switchModel(this.pendingModel);
204
+ this.applyModelSwitch(this.pendingModel);
107
205
  this.pendingModel = null;
108
206
  }
109
207
  // Drain the next turn if one is waiting.
@@ -23,6 +23,7 @@ export interface AgentRunOptions {
23
23
  cwd?: string;
24
24
  sessionId?: string;
25
25
  permissionMode?: PermissionMode;
26
+ model?: string;
26
27
  planMode?: boolean;
27
28
  }
28
29
  export type BackgroundAgentCompletedHandler = (sessionId: string, event: BackgroundAgentCompletedEvent) => void;
@@ -64,6 +65,36 @@ export declare class AgentClient {
64
65
  * Legacy form: cancel(reason?)
65
66
  */
66
67
  cancel(sessionId?: string, reason?: string): Promise<void>;
68
+ /**
69
+ * Clear a session's persisted active goal (CC `/goal clear`). Returns whether
70
+ * a goal was actually cleared (false = there was none).
71
+ */
72
+ goalClear(sessionId?: string): Promise<boolean>;
73
+ /**
74
+ * Read a session's persisted active goal objective, or null when there's
75
+ * none. The host calls this on session load to re-surface the goal block +
76
+ * Cancel button after a reload (a persistent goal isn't replayed from the
77
+ * transcript, so the live stream never re-announces it).
78
+ */
79
+ goalGet(sessionId: string): Promise<string | null>;
80
+ /**
81
+ * Steer an in-flight run: queue a user message spliced in at the next
82
+ * turn-loop step (不打断 — does not abort the current step). `id` is a stable
83
+ * host-side handle that rides through to the steer_injected event and lets
84
+ * unsteer() revoke a still-pending entry. Mirrors the server's handleSteer +
85
+ * the desktop preload's steer(); without it the SDK can't reach the method
86
+ * (request() is private) — the protocol was asymmetric after the steer merge.
87
+ */
88
+ steer(sessionId: string, text: string, id?: string, clientMessageId?: string): Promise<{
89
+ accepted: boolean;
90
+ id?: string;
91
+ }>;
92
+ /**
93
+ * Revoke a still-pending steer entry by id (before the loop consumes it).
94
+ * Returns false when the loop already consumed it (not an error — it will
95
+ * arrive as a normal user bubble).
96
+ */
97
+ unsteer(sessionId: string, id: string): Promise<boolean>;
67
98
  /**
68
99
  * Update runtime configuration on the server.
69
100
  */