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

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 (387) 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 +56 -0
  45. package/dist/context/compaction.js +186 -0
  46. package/dist/context/manager.js +25 -4
  47. package/dist/cost-tracker.js +5 -61
  48. package/dist/credentials/cipher.d.ts +49 -0
  49. package/dist/credentials/cipher.js +45 -0
  50. package/dist/credentials/cookie-jar.d.ts +24 -0
  51. package/dist/credentials/cookie-jar.js +40 -0
  52. package/dist/credentials/index.d.ts +7 -0
  53. package/dist/credentials/index.js +5 -0
  54. package/dist/credentials/inject-credential-tool.d.ts +20 -0
  55. package/dist/credentials/inject-credential-tool.js +130 -0
  56. package/dist/credentials/store.d.ts +72 -0
  57. package/dist/credentials/store.js +184 -0
  58. package/dist/credentials/types.d.ts +56 -0
  59. package/dist/credentials/use-credential-tool.d.ts +29 -0
  60. package/dist/credentials/use-credential-tool.js +205 -0
  61. package/dist/credentials/use-gate.d.ts +56 -0
  62. package/dist/credentials/use-gate.js +52 -0
  63. package/dist/data/model-metadata.d.ts +77 -0
  64. package/dist/data/model-metadata.js +56 -0
  65. package/dist/data/model-metadata.json +216 -0
  66. package/dist/data/openrouter-models.d.ts +18 -7
  67. package/dist/data/openrouter-models.js +35 -8
  68. package/dist/engine/aux-key.d.ts +10 -0
  69. package/dist/engine/aux-key.js +11 -0
  70. package/dist/engine/dynamic-tool-defs.d.ts +19 -0
  71. package/dist/engine/dynamic-tool-defs.js +36 -0
  72. package/dist/engine/engine.d.ts +267 -138
  73. package/dist/engine/engine.js +957 -191
  74. package/dist/engine/friendly-error.d.ts +18 -0
  75. package/dist/engine/friendly-error.js +63 -0
  76. package/dist/engine/goal.d.ts +145 -0
  77. package/dist/engine/goal.js +144 -0
  78. package/dist/engine/image-policy.d.ts +13 -0
  79. package/dist/engine/image-policy.js +24 -0
  80. package/dist/engine/model-connections-pool.d.ts +17 -0
  81. package/dist/engine/model-connections-pool.js +66 -0
  82. package/dist/engine/model-facade.d.ts +10 -0
  83. package/dist/engine/model-facade.js +25 -0
  84. package/dist/engine/patch-orphaned-tools.js +3 -0
  85. package/dist/engine/resolve-llm-config.d.ts +16 -0
  86. package/dist/engine/resolve-llm-config.js +44 -0
  87. package/dist/engine/runtime.js +2 -1
  88. package/dist/engine/sandbox-cache-key.d.ts +10 -0
  89. package/dist/engine/sandbox-cache-key.js +9 -0
  90. package/dist/engine/sandbox-config.d.ts +31 -0
  91. package/dist/engine/sandbox-config.js +38 -0
  92. package/dist/engine/session-usage.d.ts +19 -0
  93. package/dist/engine/session-usage.js +25 -0
  94. package/dist/engine/steer-queue.d.ts +32 -0
  95. package/dist/engine/steer-queue.js +26 -0
  96. package/dist/engine/streaming-tool-queue.d.ts +12 -0
  97. package/dist/engine/streaming-tool-queue.js +50 -10
  98. package/dist/engine/turn-loop.d.ts +67 -3
  99. package/dist/engine/turn-loop.js +292 -41
  100. package/dist/engine/types.d.ts +175 -0
  101. package/dist/engine/types.js +13 -0
  102. package/dist/external-agents/config.d.ts +2 -0
  103. package/dist/external-agents/config.js +15 -0
  104. package/dist/external-agents/types.d.ts +31 -0
  105. package/dist/external-agents/types.js +1 -0
  106. package/dist/git/utils.js +11 -6
  107. package/dist/git/worktree.d.ts +48 -0
  108. package/dist/git/worktree.js +86 -10
  109. package/dist/hooks/goal-stop-hook.d.ts +28 -0
  110. package/dist/hooks/goal-stop-hook.js +186 -9
  111. package/dist/hooks/registry.d.ts +8 -0
  112. package/dist/hooks/registry.js +19 -0
  113. package/dist/hooks/shell-runner.js +10 -21
  114. package/dist/index.d.ts +49 -6
  115. package/dist/index.js +60 -4
  116. package/dist/llm/capabilities/param-specs.d.ts +14 -0
  117. package/dist/llm/capabilities/param-specs.js +62 -0
  118. package/dist/llm/capabilities/rules.js +4 -0
  119. package/dist/llm/capabilities/types.d.ts +10 -0
  120. package/dist/llm/client-base.d.ts +28 -1
  121. package/dist/llm/client-base.js +119 -13
  122. package/dist/llm/model-cache.js +4 -2
  123. package/dist/llm/model-pool.d.ts +14 -0
  124. package/dist/llm/model-pool.js +13 -0
  125. package/dist/llm/provider-auth.d.ts +41 -0
  126. package/dist/llm/provider-auth.js +76 -0
  127. package/dist/llm/provider-catalog.d.ts +4 -0
  128. package/dist/llm/providers/anthropic.js +64 -14
  129. package/dist/llm/providers/openai.d.ts +36 -0
  130. package/dist/llm/providers/openai.js +257 -51
  131. package/dist/llm/reasoning-setting.d.ts +3 -3
  132. package/dist/llm/reasoning-setting.js +9 -1
  133. package/dist/llm/stream-watchdog.js +5 -1
  134. package/dist/llm/token-counter.js +9 -2
  135. package/dist/llm/types.d.ts +4 -0
  136. package/dist/logging/sanitize-messages.js +22 -0
  137. package/dist/lsp/manager.d.ts +1 -1
  138. package/dist/lsp/manager.js +40 -10
  139. package/dist/model-catalog/builtin.d.ts +12 -0
  140. package/dist/model-catalog/builtin.js +407 -0
  141. package/dist/model-catalog/gen-connections.d.ts +20 -0
  142. package/dist/model-catalog/gen-connections.js +28 -0
  143. package/dist/model-catalog/index.d.ts +41 -0
  144. package/dist/model-catalog/index.js +90 -0
  145. package/dist/model-catalog/params.d.ts +20 -0
  146. package/dist/model-catalog/params.js +45 -0
  147. package/dist/model-catalog/resolve.d.ts +48 -0
  148. package/dist/model-catalog/resolve.js +33 -0
  149. package/dist/model-catalog/save-entry.d.ts +32 -0
  150. package/dist/model-catalog/save-entry.js +104 -0
  151. package/dist/model-catalog/types.d.ts +561 -0
  152. package/dist/model-catalog/types.js +93 -0
  153. package/dist/model-catalog/upsert.d.ts +9 -0
  154. package/dist/model-catalog/upsert.js +8 -0
  155. package/dist/onboarding.d.ts +12 -82
  156. package/dist/onboarding.js +61 -326
  157. package/dist/plugins/gitOps.d.ts +19 -0
  158. package/dist/plugins/gitOps.js +73 -4
  159. package/dist/plugins/installer/checkUpdate.d.ts +16 -0
  160. package/dist/plugins/installer/checkUpdate.js +32 -0
  161. package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
  162. package/dist/plugins/installer/codex/convertCommands.js +46 -0
  163. package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
  164. package/dist/plugins/installer/codex/convertMcp.js +45 -5
  165. package/dist/plugins/installer/install.js +25 -1
  166. package/dist/plugins/installer/installFromArchive.d.ts +43 -0
  167. package/dist/plugins/installer/installFromArchive.js +134 -0
  168. package/dist/plugins/installer/installFromSource.js +8 -2
  169. package/dist/plugins/installer/loadPluginAgents.js +6 -2
  170. package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
  171. package/dist/plugins/installer/loadPluginMcp.js +35 -2
  172. package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
  173. package/dist/plugins/installer/pruneDisabled.js +73 -0
  174. package/dist/plugins/installer/types.d.ts +5 -2
  175. package/dist/plugins/installer/types.js +1 -0
  176. package/dist/plugins/installer/uninstall.js +4 -0
  177. package/dist/plugins/installer/unzip.d.ts +14 -0
  178. package/dist/plugins/installer/unzip.js +82 -0
  179. package/dist/plugins/installer/update.d.ts +14 -0
  180. package/dist/plugins/installer/update.js +53 -21
  181. package/dist/plugins/loadPluginHooks.d.ts +47 -1
  182. package/dist/plugins/loadPluginHooks.js +73 -1
  183. package/dist/plugins/marketplaceManager.d.ts +7 -0
  184. package/dist/plugins/marketplaceManager.js +20 -0
  185. package/dist/plugins/pluginCommandHook.js +4 -18
  186. package/dist/plugins/pluginContent.d.ts +30 -0
  187. package/dist/plugins/pluginContent.js +83 -0
  188. package/dist/plugins/pluginInstaller.d.ts +13 -0
  189. package/dist/plugins/pluginInstaller.js +42 -8
  190. package/dist/plugins/schemas.js +1 -0
  191. package/dist/plugins/types.d.ts +6 -0
  192. package/dist/preset/index.d.ts +7 -1
  193. package/dist/preset/index.js +96 -6
  194. package/dist/product/types.d.ts +1 -1
  195. package/dist/prompt/composer.d.ts +27 -0
  196. package/dist/prompt/composer.js +67 -21
  197. package/dist/prompt/instruction-scanner.js +5 -3
  198. package/dist/prompt/section-loader.js +1 -0
  199. package/dist/prompt/sections/base.md +1 -0
  200. package/dist/prompt/sections/browser.md +10 -0
  201. package/dist/prompt/sections/coding.md +4 -0
  202. package/dist/protocol/chat-session-manager.d.ts +8 -2
  203. package/dist/protocol/chat-session-manager.js +36 -0
  204. package/dist/protocol/chat-session.d.ts +65 -0
  205. package/dist/protocol/chat-session.js +94 -2
  206. package/dist/protocol/client.d.ts +27 -0
  207. package/dist/protocol/client.js +38 -0
  208. package/dist/protocol/server.d.ts +112 -0
  209. package/dist/protocol/server.js +586 -16
  210. package/dist/protocol/transport.js +3 -2
  211. package/dist/protocol/types.d.ts +46 -0
  212. package/dist/protocol/types.js +16 -0
  213. package/dist/quota/credentials.d.ts +3 -0
  214. package/dist/quota/credentials.js +80 -0
  215. package/dist/quota/index.d.ts +36 -0
  216. package/dist/quota/index.js +155 -0
  217. package/dist/quota/types.d.ts +48 -0
  218. package/dist/quota/types.js +13 -0
  219. package/dist/review/review-prompt.d.ts +28 -0
  220. package/dist/review/review-prompt.js +81 -0
  221. package/dist/run/FileRunStore.js +8 -3
  222. package/dist/run/RunApprovalBackend.js +25 -5
  223. package/dist/run/RunManager.d.ts +12 -0
  224. package/dist/run/RunManager.js +35 -0
  225. package/dist/run/factory.d.ts +1 -1
  226. package/dist/runtime/background-shell.d.ts +139 -0
  227. package/dist/runtime/background-shell.js +495 -0
  228. package/dist/runtime/output-clean.d.ts +24 -0
  229. package/dist/runtime/output-clean.js +41 -0
  230. package/dist/runtime/ring-file.d.ts +64 -0
  231. package/dist/runtime/ring-file.js +174 -0
  232. package/dist/runtime/safe-spawn.js +15 -34
  233. package/dist/runtime/spawn-common.d.ts +148 -0
  234. package/dist/runtime/spawn-common.js +303 -0
  235. package/dist/runtime/truncate-output.d.ts +22 -0
  236. package/dist/runtime/truncate-output.js +49 -0
  237. package/dist/runtime/utf8-cut.d.ts +11 -0
  238. package/dist/runtime/utf8-cut.js +23 -0
  239. package/dist/services/auto-dream.d.ts +4 -0
  240. package/dist/services/auto-dream.js +26 -26
  241. package/dist/services/diagnostics.d.ts +1 -2
  242. package/dist/services/diagnostics.js +12 -7
  243. package/dist/services/extract-memories.d.ts +14 -1
  244. package/dist/services/extract-memories.js +45 -6
  245. package/dist/services/memory-orchestrator.d.ts +21 -0
  246. package/dist/services/memory-orchestrator.js +125 -50
  247. package/dist/services/session-memory.js +24 -12
  248. package/dist/session/file-history.d.ts +124 -1
  249. package/dist/session/file-history.js +222 -6
  250. package/dist/session/memory.d.ts +116 -2
  251. package/dist/session/memory.js +250 -28
  252. package/dist/session/session-manager.d.ts +40 -0
  253. package/dist/session/session-manager.js +113 -3
  254. package/dist/session/simple-diff.d.ts +23 -0
  255. package/dist/session/simple-diff.js +84 -0
  256. package/dist/session/transcript.d.ts +25 -1
  257. package/dist/session/transcript.js +35 -2
  258. package/dist/session/undo-target.d.ts +67 -0
  259. package/dist/session/undo-target.js +144 -0
  260. package/dist/settings/disk-defaults.d.ts +9 -2
  261. package/dist/settings/disk-defaults.js +11 -2
  262. package/dist/settings/feature-flags.d.ts +64 -0
  263. package/dist/settings/feature-flags.js +61 -0
  264. package/dist/settings/manager.d.ts +68 -1
  265. package/dist/settings/manager.js +266 -29
  266. package/dist/settings/migrate-config.d.ts +45 -0
  267. package/dist/settings/migrate-config.js +125 -0
  268. package/dist/settings/schema-export.d.ts +25 -0
  269. package/dist/settings/schema-export.js +38 -0
  270. package/dist/settings/schema.d.ts +1186 -771
  271. package/dist/settings/schema.js +268 -97
  272. package/dist/skills/scanner.d.ts +9 -0
  273. package/dist/skills/scanner.js +30 -2
  274. package/dist/stt/resolve-transcribe.d.ts +31 -0
  275. package/dist/stt/resolve-transcribe.js +108 -0
  276. package/dist/stt/transcribe.d.ts +51 -0
  277. package/dist/stt/transcribe.js +65 -0
  278. package/dist/tool-system/browser-bridge.d.ts +226 -0
  279. package/dist/tool-system/browser-bridge.js +163 -0
  280. package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
  281. package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
  282. package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
  283. package/dist/tool-system/builtin/agent-notifications.js +9 -3
  284. package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
  285. package/dist/tool-system/builtin/agent-output-file.js +72 -0
  286. package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
  287. package/dist/tool-system/builtin/agent-registry.js +8 -0
  288. package/dist/tool-system/builtin/agent.d.ts +21 -1
  289. package/dist/tool-system/builtin/agent.js +489 -42
  290. package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
  291. package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
  292. package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
  293. package/dist/tool-system/builtin/apply-patch/index.js +0 -15
  294. package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
  295. package/dist/tool-system/builtin/background-jobs.js +124 -0
  296. package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
  297. package/dist/tool-system/builtin/background-shell-tools.js +108 -0
  298. package/dist/tool-system/builtin/background-work.d.ts +67 -0
  299. package/dist/tool-system/builtin/background-work.js +86 -0
  300. package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
  301. package/dist/tool-system/builtin/bash-output-style.js +40 -0
  302. package/dist/tool-system/builtin/bash.d.ts +5 -2
  303. package/dist/tool-system/builtin/bash.js +98 -62
  304. package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
  305. package/dist/tool-system/builtin/browser-tools.js +312 -0
  306. package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
  307. package/dist/tool-system/builtin/cancel-goal.js +64 -0
  308. package/dist/tool-system/builtin/check-quota.d.ts +15 -0
  309. package/dist/tool-system/builtin/check-quota.js +34 -0
  310. package/dist/tool-system/builtin/config.js +7 -0
  311. package/dist/tool-system/builtin/cron.d.ts +7 -0
  312. package/dist/tool-system/builtin/cron.js +55 -3
  313. package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
  314. package/dist/tool-system/builtin/drive-claude-code.js +157 -0
  315. package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
  316. package/dist/tool-system/builtin/edit-model-catalog.js +94 -0
  317. package/dist/tool-system/builtin/edit.js +20 -16
  318. package/dist/tool-system/builtin/eol.d.ts +29 -0
  319. package/dist/tool-system/builtin/eol.js +37 -0
  320. package/dist/tool-system/builtin/file-cache.d.ts +6 -0
  321. package/dist/tool-system/builtin/file-cache.js +8 -0
  322. package/dist/tool-system/builtin/generate-image.d.ts +35 -0
  323. package/dist/tool-system/builtin/generate-image.js +278 -50
  324. package/dist/tool-system/builtin/generate-video.d.ts +55 -0
  325. package/dist/tool-system/builtin/generate-video.js +361 -0
  326. package/dist/tool-system/builtin/glob.js +0 -7
  327. package/dist/tool-system/builtin/grep.js +6 -8
  328. package/dist/tool-system/builtin/image-providers.d.ts +86 -0
  329. package/dist/tool-system/builtin/image-providers.js +190 -0
  330. package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
  331. package/dist/tool-system/builtin/image-uploader.js +74 -0
  332. package/dist/tool-system/builtin/index.d.ts +7 -1
  333. package/dist/tool-system/builtin/index.js +249 -25
  334. package/dist/tool-system/builtin/mcp-tools.js +23 -3
  335. package/dist/tool-system/builtin/memory.js +45 -7
  336. package/dist/tool-system/builtin/notebook-edit.js +0 -7
  337. package/dist/tool-system/builtin/powershell.js +4 -1
  338. package/dist/tool-system/builtin/read.js +10 -10
  339. package/dist/tool-system/builtin/repl.js +4 -1
  340. package/dist/tool-system/builtin/skill.js +9 -0
  341. package/dist/tool-system/builtin/sleep.js +3 -2
  342. package/dist/tool-system/builtin/tool-search.js +25 -7
  343. package/dist/tool-system/builtin/video-providers.d.ts +154 -0
  344. package/dist/tool-system/builtin/video-providers.js +235 -0
  345. package/dist/tool-system/builtin/web-fetch.js +12 -2
  346. package/dist/tool-system/builtin/web-search.js +21 -7
  347. package/dist/tool-system/builtin/worktree.d.ts +2 -1
  348. package/dist/tool-system/builtin/worktree.js +31 -4
  349. package/dist/tool-system/builtin/write.js +0 -6
  350. package/dist/tool-system/context.d.ts +154 -6
  351. package/dist/tool-system/executor.d.ts +3 -1
  352. package/dist/tool-system/executor.js +172 -88
  353. package/dist/tool-system/investigation-guard.js +1 -1
  354. package/dist/tool-system/mcp-manager.d.ts +42 -4
  355. package/dist/tool-system/mcp-manager.js +186 -20
  356. package/dist/tool-system/path-policy.d.ts +5 -0
  357. package/dist/tool-system/path-policy.js +307 -8
  358. package/dist/tool-system/permission.d.ts +36 -1
  359. package/dist/tool-system/permission.js +281 -69
  360. package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
  361. package/dist/tool-system/plan-mode-allowlist.js +24 -2
  362. package/dist/tool-system/registry.d.ts +1 -0
  363. package/dist/tool-system/registry.js +16 -2
  364. package/dist/tool-system/sandbox/index.d.ts +8 -0
  365. package/dist/tool-system/sandbox/index.js +7 -2
  366. package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
  367. package/dist/tool-system/validate-tool-metadata.js +63 -0
  368. package/dist/types.d.ts +217 -6
  369. package/dist/updater.js +20 -9
  370. package/dist/utils/envUtils.d.ts +0 -9
  371. package/dist/utils/envUtils.js +3 -28
  372. package/dist/utils/exec.d.ts +40 -0
  373. package/dist/utils/exec.js +144 -0
  374. package/dist/utils/json.d.ts +12 -0
  375. package/dist/utils/json.js +92 -0
  376. package/dist/utils/theme.d.ts +1 -1
  377. package/dist/utils/theme.js +1 -1
  378. package/dist/utils/toolDisplay.js +0 -1
  379. package/package.json +13 -7
  380. package/dist/agent/coordinator.d.ts +0 -49
  381. package/dist/agent/coordinator.js +0 -77
  382. package/dist/settings/manager.test.js +0 -73
  383. package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
  384. package/dist/tool-system/builtin/remote-trigger.js +0 -54
  385. package/dist/tool-system/builtin/send-message.d.ts +0 -6
  386. package/dist/tool-system/builtin/send-message.js +0 -47
  387. /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,38 @@ 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 parts = [skillsListing, gitStatus, memoryContext].filter(Boolean);
117
+ if (parts.length === 0)
118
+ return null;
119
+ return {
120
+ role: "user",
121
+ content: `<system-reminder>\n${parts.join("\n\n")}\n</system-reminder>`,
122
+ };
123
+ }
90
124
  invalidateCache(sectionName) {
91
125
  this.sectionCache.invalidate(sectionName);
92
126
  if (!sectionName) {
@@ -129,25 +163,31 @@ export class PromptComposer {
129
163
  },
130
164
  });
131
165
  }
132
- // Behavioral instructions — loaded from preset's section files
166
+ // Behavioral instructions — loaded from preset's section files. Pass the
167
+ // turn's effective tool names so tool-gated sections (e.g. "browser") drop
168
+ // when their tools are disabled: browser capability = tools + instructions
169
+ // as one on/off unit.
170
+ const activeToolNames = tools.map((t) => t.name);
133
171
  sections.push({
134
172
  name: "behavior",
173
+ // cacheBreak: this section's content varies by activeToolNames (tool-gated
174
+ // sections like "browser" drop when their tools are off). The cache is
175
+ // keyed by section NAME only, so without cacheBreak a reused composer could
176
+ // serve a stale behavior block across an on/off change. Recompute always —
177
+ // it's a cheap string join, and it makes the browser on/off unit correct
178
+ // regardless of composer lifetime.
179
+ cacheBreak: true,
135
180
  compute: () => {
136
181
  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);
182
+ return buildPresetSystemPrompt(preset, activeToolNames);
149
183
  },
150
184
  });
185
+ // Skills listing is intentionally NOT a system section: it changes when a
186
+ // skill is installed/disabled, which would invalidate the whole cached
187
+ // system prefix on every change. It rides in the per-turn dynamic-context
188
+ // message instead (buildDynamicContextMessage). Same reasoning keeps the
189
+ // git-status snapshot out of the system prefix — see buildSystemContext's
190
+ // callers.
151
191
  // Append system prompt
152
192
  if (this.options.appendSystemPrompt) {
153
193
  sections.push({
@@ -183,8 +223,14 @@ export class PromptComposer {
183
223
  }
184
224
  getMemoryContext() {
185
225
  try {
186
- const mm = new MemoryManager(this.options.cwd);
187
- return mm.buildMemoryContext();
226
+ // Two-layer injection (用户拍板): a compact index merging GLOBAL +
227
+ // PROJECT memories. Global memories are now surfaced every session
228
+ // regardless of cwd (the fix for "global memory never shows up"); the
229
+ // model reads full bodies on demand via MemoryRead.
230
+ return MemoryManager.buildInjectionIndex({
231
+ projectDir: this.options.cwd,
232
+ maxAgeDays: this.options.memoriesMaxAgeDays,
233
+ });
188
234
  }
189
235
  catch {
190
236
  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,6 @@ 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
+ - 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
35
  - 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
36
  - 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
@@ -33,6 +33,12 @@ export declare class ChatSessionManager {
33
33
  forEachSession(fn: (s: ChatSession) => void): void;
34
34
  close(sessionId: string): void;
35
35
  closeAll(): void;
36
+ /**
37
+ * Await-able shutdown. Cancels every session and reaps every background
38
+ * shell, *waiting* for the kill grace so a caller that exits the process
39
+ * immediately afterward (the TUI REPL) doesn't orphan detached dev servers.
40
+ */
41
+ closeAllAsync(): Promise<void>;
36
42
  sessionCount(): number;
37
43
  sweepIdle(): void;
38
44
  startIdleSweeper(intervalMs?: number): void;
@@ -1,4 +1,6 @@
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();
4
6
  factory;
@@ -14,6 +16,17 @@ export class ChatSessionManager {
14
16
  const existing = this.sessions.get(sessionId);
15
17
  if (existing) {
16
18
  existing.lastActivityAt = Date.now();
19
+ // Re-apply the per-send permission mode so a pill change on an
20
+ // already-running session takes effect on the NEXT turn. Without this the
21
+ // engine kept whatever mode it was first created with — changing the pill
22
+ // on a resumed session was silently ignored at enforcement time (#11
23
+ // secondary: "档位 doesn't take effect after first send"). setPermissionMode
24
+ // reconfigures the live permission backend, so it's safe between turns.
25
+ if (slice.permissionMode &&
26
+ typeof existing.engine.getPermissionMode === "function" &&
27
+ existing.engine.getPermissionMode() !== slice.permissionMode) {
28
+ existing.engine.setPermissionMode(slice.permissionMode);
29
+ }
17
30
  return existing;
18
31
  }
19
32
  if (this.sessions.size >= this.maxSessions) {
@@ -47,8 +60,31 @@ export class ChatSessionManager {
47
60
  this.sessions.delete(sessionId);
48
61
  }
49
62
  closeAll() {
63
+ // Fire-and-forget variant for callers that can't await (e.g. AgentServer
64
+ // teardown inside a sync stop path). The TUI exit path uses closeAllAsync()
65
+ // below so the SIGTERM→SIGKILL grace actually completes before the process
66
+ // exits — otherwise startInkRepl's process.exit(0) races the kill and the
67
+ // detached shells leak as orphans.
68
+ void this.closeAllAsync();
69
+ }
70
+ /**
71
+ * Await-able shutdown. Cancels every session and reaps every background
72
+ * shell, *waiting* for the kill grace so a caller that exits the process
73
+ * immediately afterward (the TUI REPL) doesn't orphan detached dev servers.
74
+ */
75
+ async closeAllAsync() {
50
76
  for (const id of [...this.sessions.keys()])
51
77
  this.close(id);
78
+ // App/worker shutdown — reap every background shell so a detached
79
+ // `npm run dev` doesn't outlive the process as an orphan holding a port
80
+ // (design §6 / §难点1). NOTE: deliberately NOT in close()/sweepIdle() —
81
+ // an idle chat tab must keep its dev server alive (§6 "切走再回来 server 还在").
82
+ await backgroundShellManager.killAll();
83
+ // Background-agent output files are a debugging convenience, not durable
84
+ // state — wipe them on shutdown so ~/.code-shell/agents doesn't grow
85
+ // unbounded across runs. (notificationQueue, the real result path, is
86
+ // in-memory and already gone.)
87
+ await clearAgentOutputFiles();
52
88
  }
53
89
  sessionCount() {
54
90
  return this.sessions.size;
@@ -13,6 +13,10 @@ export interface TurnOpts {
13
13
  /** Goal mode for this turn — forwarded to engine.run (loop-until-done).
14
14
  * String objective or full GoalConfig (objective + optional budgets). */
15
15
  goal?: string | import("../engine/goal.js").GoalConfig;
16
+ /** Marks this turn as a synthetic system-reminder injection (background-job
17
+ * completion notification) rather than the user's own input — persisted so
18
+ * the disk reader skips it as a user bubble on replay. See Engine.run. */
19
+ injected?: boolean;
16
20
  }
17
21
  /**
18
22
  * One ChatSession per UI chat tab. Owns a single Engine, an AbortController
@@ -42,8 +46,32 @@ export declare class ChatSession {
42
46
  * session-isolation research flagged. null = nothing pending.
43
47
  */
44
48
  private pendingModel;
49
+ /**
50
+ * Set by cancel() so the in-flight turn's abort error resolves as a clean
51
+ * "cancelled" result instead of rejecting (which the RPC layer would surface
52
+ * as a scary red Error in the UI for what was a user-initiated Stop). The
53
+ * onboarding flow cancels + immediately re-runs the same task; without this
54
+ * the cancelled first run popped "Error: Request cancelled".
55
+ */
56
+ private cancelledActive;
57
+ /**
58
+ * Sticky flag: the user cancelled (Stop) and has not started a new turn
59
+ * since. cancel() leaves the session idle (active=null), so isBusy() can't
60
+ * distinguish "naturally idle" from "user just stopped me". A background-job
61
+ * completion that lands in this window must NOT auto-resume the session —
62
+ * that would defeat the Stop. Cleared the moment a real turn is enqueued
63
+ * (the user is engaging again) so normal wakeups resume working afterward.
64
+ */
65
+ private cancelledSinceLastTurn;
45
66
  constructor(opts: ChatSessionOptions);
46
67
  enqueueTurn(task: string, opts: TurnOpts): Promise<EngineResult>;
68
+ /**
69
+ * True when the user hit Stop and hasn't started a new turn since. The server
70
+ * consults this before auto-waking an idle session on a background-job
71
+ * completion, so a download finishing right after Stop doesn't restart the
72
+ * agent the user just halted.
73
+ */
74
+ wasCancelledSinceLastTurn(): boolean;
47
75
  /**
48
76
  * Abort the in-flight turn and drain queued turns.
49
77
  *
@@ -54,6 +82,34 @@ export declare class ChatSession {
54
82
  */
55
83
  cancel(): void;
56
84
  isBusy(): boolean;
85
+ /**
86
+ * Extend the in-flight goal run's turn/budget ceilings (TODO 3.1). Delegates
87
+ * to the engine, which forwards to the active TurnLoop. Returns null when no
88
+ * run is active (or the run has no extendable loop). Mirrors the cancel()
89
+ * mid-run control path.
90
+ */
91
+ extendGoalRun(opts: {
92
+ addTurns?: number;
93
+ addTokenBudget?: number;
94
+ addTimeBudgetMs?: number;
95
+ addStopBlocks?: number;
96
+ }): {
97
+ maxTurns: number;
98
+ tokenBudget?: number;
99
+ timeBudgetMs?: number;
100
+ maxStopBlocks: number;
101
+ } | null;
102
+ /**
103
+ * Read this session's persisted active goal (state.activeGoal), or undefined
104
+ * when none. Cheap — reads only state.json. The host calls this on session
105
+ * load to re-surface the goal block + Cancel button after a reload.
106
+ */
107
+ getGoal(): import("../engine/goal.js").GoalConfig | undefined;
108
+ /**
109
+ * Clear this session's persisted active goal (CC /goal clear). Works idle or
110
+ * mid-run. Returns true if a goal was actually cleared.
111
+ */
112
+ clearGoal(): boolean;
57
113
  /**
58
114
  * Switch this session's active model (per-session, not worker-global).
59
115
  * Applies immediately when idle; defers to the next run boundary when a
@@ -61,6 +117,15 @@ export declare class ChatSession {
61
117
  * running LLM client.
62
118
  */
63
119
  requestModelSwitch(key: string): void;
120
+ /**
121
+ * Perform the actual model switch for this session: rotate the engine's model
122
+ * and reset the session's cumulative usage on disk — a different model has a
123
+ * different prompt cache, so the old cache-hit stats no longer apply. The
124
+ * renderer zeroes its own cumulative display when it issues the switch (it's
125
+ * renderer-initiated), so no stream event is needed here. Shared by the idle
126
+ * path and the deferred run-boundary path.
127
+ */
128
+ private applyModelSwitch;
64
129
  queueDepth(): number;
65
130
  private pump;
66
131
  }
@@ -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
@@ -68,7 +129,19 @@ export class ChatSession {
68
129
  this.pendingModel = key;
69
130
  return;
70
131
  }
132
+ this.applyModelSwitch(key);
133
+ }
134
+ /**
135
+ * Perform the actual model switch for this session: rotate the engine's model
136
+ * and reset the session's cumulative usage on disk — a different model has a
137
+ * different prompt cache, so the old cache-hit stats no longer apply. The
138
+ * renderer zeroes its own cumulative display when it issues the switch (it's
139
+ * renderer-initiated), so no stream event is needed here. Shared by the idle
140
+ * path and the deferred run-boundary path.
141
+ */
142
+ applyModelSwitch(key) {
71
143
  this.engine.switchModel(key);
144
+ this.engine.resetSessionUsage(this.id);
72
145
  }
73
146
  queueDepth() {
74
147
  return this.queue.length;
@@ -80,6 +153,7 @@ export class ChatSession {
80
153
  if (!next)
81
154
  return;
82
155
  this.active = next;
156
+ this.cancelledActive = false;
83
157
  this.controller = new AbortController();
84
158
  try {
85
159
  const onStream = next.opts.onStream ?? this.defaultOnStream;
@@ -89,21 +163,39 @@ export class ChatSession {
89
163
  signal: this.controller.signal,
90
164
  onStream,
91
165
  goal: next.opts.goal,
166
+ injected: next.opts.injected,
92
167
  });
93
168
  this.lastActivityAt = Date.now();
94
169
  next.resolve(result);
95
170
  }
96
171
  catch (err) {
97
- next.reject(err);
172
+ // A user-initiated cancel (Stop, or the onboarding cancel+rerun flow)
173
+ // aborts the in-flight run. That's not a failure — resolve it as a clean
174
+ // aborted result so the RPC layer doesn't surface "Error: Request
175
+ // cancelled" in the UI. Only abort errors on a cancelled turn are
176
+ // swallowed this way; a genuine error still rejects.
177
+ if (this.cancelledActive && (isAbortError(err) || this.controller?.signal.aborted)) {
178
+ next.resolve({
179
+ text: "",
180
+ reason: "aborted_streaming",
181
+ sessionId: this.id,
182
+ turnCount: 0,
183
+ usage: { promptTokens: 0, completionTokens: 0, totalTokens: 0 },
184
+ });
185
+ }
186
+ else {
187
+ next.reject(err);
188
+ }
98
189
  }
99
190
  finally {
100
191
  this.active = null;
101
192
  this.controller = null;
193
+ this.cancelledActive = false;
102
194
  // Run boundary: apply any model switch that was deferred because it was
103
195
  // requested mid-run. Done here (not in pump) so it still applies when
104
196
  // no further turn is queued.
105
197
  if (this.pendingModel !== null) {
106
- this.engine.switchModel(this.pendingModel);
198
+ this.applyModelSwitch(this.pendingModel);
107
199
  this.pendingModel = null;
108
200
  }
109
201
  // Drain the next turn if one is waiting.
@@ -64,6 +64,33 @@ export declare class AgentClient {
64
64
  * Legacy form: cancel(reason?)
65
65
  */
66
66
  cancel(sessionId?: string, reason?: string): Promise<void>;
67
+ /**
68
+ * Clear a session's persisted active goal (CC `/goal clear`). Returns whether
69
+ * a goal was actually cleared (false = there was none).
70
+ */
71
+ goalClear(sessionId?: string): Promise<boolean>;
72
+ /**
73
+ * Read a session's persisted active goal objective, or null when there's
74
+ * none. The host calls this on session load to re-surface the goal block +
75
+ * Cancel button after a reload (a persistent goal isn't replayed from the
76
+ * transcript, so the live stream never re-announces it).
77
+ */
78
+ goalGet(sessionId: string): Promise<string | null>;
79
+ /**
80
+ * Steer an in-flight run: queue a user message spliced in at the next
81
+ * turn-loop step (不打断 — does not abort the current step). `id` is a stable
82
+ * host-side handle that rides through to the steer_injected event and lets
83
+ * unsteer() revoke a still-pending entry. Mirrors the server's handleSteer +
84
+ * the desktop preload's steer(); without it the SDK can't reach the method
85
+ * (request() is private) — the protocol was asymmetric after the steer merge.
86
+ */
87
+ steer(sessionId: string, text: string, id?: string): Promise<void>;
88
+ /**
89
+ * Revoke a still-pending steer entry by id (before the loop consumes it).
90
+ * Returns false when the loop already consumed it (not an error — it will
91
+ * arrive as a normal user bubble).
92
+ */
93
+ unsteer(sessionId: string, id: string): Promise<boolean>;
67
94
  /**
68
95
  * Update runtime configuration on the server.
69
96
  */
@@ -99,6 +99,44 @@ export class AgentClient {
99
99
  async cancel(sessionId, reason) {
100
100
  await this.request(Methods.Cancel, { sessionId, reason });
101
101
  }
102
+ /**
103
+ * Clear a session's persisted active goal (CC `/goal clear`). Returns whether
104
+ * a goal was actually cleared (false = there was none).
105
+ */
106
+ async goalClear(sessionId) {
107
+ const res = (await this.request(Methods.GoalClear, { sessionId }));
108
+ return res?.cleared === true;
109
+ }
110
+ /**
111
+ * Read a session's persisted active goal objective, or null when there's
112
+ * none. The host calls this on session load to re-surface the goal block +
113
+ * Cancel button after a reload (a persistent goal isn't replayed from the
114
+ * transcript, so the live stream never re-announces it).
115
+ */
116
+ async goalGet(sessionId) {
117
+ const res = (await this.request(Methods.GoalGet, { sessionId }));
118
+ return res?.goal ?? null;
119
+ }
120
+ /**
121
+ * Steer an in-flight run: queue a user message spliced in at the next
122
+ * turn-loop step (不打断 — does not abort the current step). `id` is a stable
123
+ * host-side handle that rides through to the steer_injected event and lets
124
+ * unsteer() revoke a still-pending entry. Mirrors the server's handleSteer +
125
+ * the desktop preload's steer(); without it the SDK can't reach the method
126
+ * (request() is private) — the protocol was asymmetric after the steer merge.
127
+ */
128
+ async steer(sessionId, text, id) {
129
+ await this.request(Methods.Steer, { sessionId, text, id });
130
+ }
131
+ /**
132
+ * Revoke a still-pending steer entry by id (before the loop consumes it).
133
+ * Returns false when the loop already consumed it (not an error — it will
134
+ * arrive as a normal user bubble).
135
+ */
136
+ async unsteer(sessionId, id) {
137
+ const res = (await this.request(Methods.Unsteer, { sessionId, id }));
138
+ return res?.removed === true;
139
+ }
102
140
  /**
103
141
  * Update runtime configuration on the server.
104
142
  */