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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (396) hide show
  1. package/README.md +13 -10
  2. package/dist/agent/agent-definition-registry.d.ts +3 -0
  3. package/dist/agent/agent-definition-registry.js +3 -1
  4. package/dist/agent/agent-definition.d.ts +15 -0
  5. package/dist/agent/agent-definition.js +27 -3
  6. package/dist/arena/context/context-tools.js +47 -4
  7. package/dist/arena/ledger.js +9 -1
  8. package/dist/arena/strategies/utils.d.ts +1 -4
  9. package/dist/arena/strategies/utils.js +7 -84
  10. package/dist/automation/cron-expr.d.ts +10 -0
  11. package/dist/automation/cron-expr.js +23 -5
  12. package/dist/automation/runner.d.ts +21 -4
  13. package/dist/automation/runner.js +48 -12
  14. package/dist/automation/scheduler.d.ts +38 -0
  15. package/dist/automation/scheduler.js +89 -12
  16. package/dist/automation/store.js +5 -2
  17. package/dist/capability-control/disabled-lists.d.ts +25 -0
  18. package/dist/capability-control/disabled-lists.js +57 -0
  19. package/dist/capability-control/overlay.d.ts +15 -0
  20. package/dist/capability-control/overlay.js +27 -0
  21. package/dist/cc-orchestrator/agent-adapter.d.ts +50 -0
  22. package/dist/cc-orchestrator/agent-adapter.js +133 -0
  23. package/dist/cc-orchestrator/cc-capability.d.ts +19 -0
  24. package/dist/cc-orchestrator/cc-capability.js +53 -0
  25. package/dist/cc-orchestrator/codex-session-discovery.d.ts +24 -0
  26. package/dist/cc-orchestrator/codex-session-discovery.js +191 -0
  27. package/dist/cc-orchestrator/codex-session-history.d.ts +25 -0
  28. package/dist/cc-orchestrator/codex-session-history.js +187 -0
  29. package/dist/cc-orchestrator/external-agent-changes.d.ts +19 -0
  30. package/dist/cc-orchestrator/external-agent-changes.js +214 -0
  31. package/dist/cc-orchestrator/external-agent-driver.d.ts +18 -0
  32. package/dist/cc-orchestrator/external-agent-driver.js +69 -0
  33. package/dist/cc-orchestrator/index.d.ts +8 -0
  34. package/dist/cc-orchestrator/index.js +8 -0
  35. package/dist/cc-orchestrator/relevance-judge.d.ts +15 -0
  36. package/dist/cc-orchestrator/relevance-judge.js +29 -0
  37. package/dist/cc-orchestrator/session-discovery.d.ts +46 -0
  38. package/dist/cc-orchestrator/session-discovery.js +125 -0
  39. package/dist/cc-orchestrator/session-history.d.ts +19 -0
  40. package/dist/cc-orchestrator/session-history.js +67 -0
  41. package/dist/cli/agent-server-stdio.d.ts +15 -1
  42. package/dist/cli/agent-server-stdio.js +115 -17
  43. package/dist/cli/agent-server-tcp.js +40 -26
  44. package/dist/context/compaction.d.ts +86 -0
  45. package/dist/context/compaction.js +279 -0
  46. package/dist/context/manager.d.ts +18 -0
  47. package/dist/context/manager.js +181 -48
  48. package/dist/context/token-counter.js +13 -0
  49. package/dist/cost-tracker.js +5 -61
  50. package/dist/credentials/cipher.d.ts +49 -0
  51. package/dist/credentials/cipher.js +45 -0
  52. package/dist/credentials/cookie-jar.d.ts +24 -0
  53. package/dist/credentials/cookie-jar.js +40 -0
  54. package/dist/credentials/index.d.ts +7 -0
  55. package/dist/credentials/index.js +5 -0
  56. package/dist/credentials/inject-credential-tool.d.ts +20 -0
  57. package/dist/credentials/inject-credential-tool.js +130 -0
  58. package/dist/credentials/store.d.ts +72 -0
  59. package/dist/credentials/store.js +184 -0
  60. package/dist/credentials/types.d.ts +56 -0
  61. package/dist/credentials/use-credential-tool.d.ts +29 -0
  62. package/dist/credentials/use-credential-tool.js +205 -0
  63. package/dist/credentials/use-gate.d.ts +56 -0
  64. package/dist/credentials/use-gate.js +52 -0
  65. package/dist/data/model-metadata.d.ts +77 -0
  66. package/dist/data/model-metadata.js +56 -0
  67. package/dist/data/model-metadata.json +216 -0
  68. package/dist/data/openrouter-models.d.ts +18 -7
  69. package/dist/data/openrouter-models.js +35 -8
  70. package/dist/engine/aux-key.d.ts +10 -0
  71. package/dist/engine/aux-key.js +11 -0
  72. package/dist/engine/dynamic-tool-defs.d.ts +19 -0
  73. package/dist/engine/dynamic-tool-defs.js +36 -0
  74. package/dist/engine/engine.d.ts +280 -141
  75. package/dist/engine/engine.js +1193 -245
  76. package/dist/engine/friendly-error.d.ts +18 -0
  77. package/dist/engine/friendly-error.js +63 -0
  78. package/dist/engine/goal.d.ts +145 -0
  79. package/dist/engine/goal.js +144 -0
  80. package/dist/engine/image-policy.d.ts +13 -0
  81. package/dist/engine/image-policy.js +24 -0
  82. package/dist/engine/model-connections-pool.d.ts +17 -0
  83. package/dist/engine/model-connections-pool.js +67 -0
  84. package/dist/engine/model-facade.d.ts +10 -0
  85. package/dist/engine/model-facade.js +15 -0
  86. package/dist/engine/patch-orphaned-tools.js +3 -0
  87. package/dist/engine/query.js +2 -0
  88. package/dist/engine/resolve-llm-config.d.ts +16 -0
  89. package/dist/engine/resolve-llm-config.js +44 -0
  90. package/dist/engine/runtime.d.ts +2 -0
  91. package/dist/engine/runtime.js +27 -1
  92. package/dist/engine/sandbox-cache-key.d.ts +10 -0
  93. package/dist/engine/sandbox-cache-key.js +9 -0
  94. package/dist/engine/sandbox-config.d.ts +31 -0
  95. package/dist/engine/sandbox-config.js +38 -0
  96. package/dist/engine/session-usage.d.ts +31 -0
  97. package/dist/engine/session-usage.js +81 -0
  98. package/dist/engine/steer-queue.d.ts +33 -0
  99. package/dist/engine/steer-queue.js +26 -0
  100. package/dist/engine/streaming-tool-queue.d.ts +12 -0
  101. package/dist/engine/streaming-tool-queue.js +50 -10
  102. package/dist/engine/turn-loop.d.ts +94 -4
  103. package/dist/engine/turn-loop.js +432 -54
  104. package/dist/engine/types.d.ts +175 -0
  105. package/dist/engine/types.js +13 -0
  106. package/dist/external-agents/config.d.ts +2 -0
  107. package/dist/external-agents/config.js +15 -0
  108. package/dist/external-agents/types.d.ts +31 -0
  109. package/dist/external-agents/types.js +1 -0
  110. package/dist/git/utils.d.ts +12 -0
  111. package/dist/git/utils.js +38 -6
  112. package/dist/git/worktree.d.ts +48 -0
  113. package/dist/git/worktree.js +86 -10
  114. package/dist/hooks/goal-stop-hook.d.ts +28 -0
  115. package/dist/hooks/goal-stop-hook.js +186 -9
  116. package/dist/hooks/registry.d.ts +8 -0
  117. package/dist/hooks/registry.js +19 -0
  118. package/dist/hooks/shell-runner.js +10 -21
  119. package/dist/index.d.ts +51 -7
  120. package/dist/index.js +62 -5
  121. package/dist/llm/capabilities/param-specs.d.ts +14 -0
  122. package/dist/llm/capabilities/param-specs.js +62 -0
  123. package/dist/llm/capabilities/rules.js +5 -1
  124. package/dist/llm/capabilities/types.d.ts +10 -0
  125. package/dist/llm/client-base.d.ts +28 -1
  126. package/dist/llm/client-base.js +119 -13
  127. package/dist/llm/model-cache.js +4 -2
  128. package/dist/llm/model-pool.d.ts +21 -0
  129. package/dist/llm/model-pool.js +21 -1
  130. package/dist/llm/provider-auth.d.ts +41 -0
  131. package/dist/llm/provider-auth.js +76 -0
  132. package/dist/llm/provider-catalog.d.ts +4 -0
  133. package/dist/llm/providers/anthropic.js +64 -14
  134. package/dist/llm/providers/openai.d.ts +36 -0
  135. package/dist/llm/providers/openai.js +257 -51
  136. package/dist/llm/reasoning-setting.d.ts +3 -3
  137. package/dist/llm/reasoning-setting.js +9 -1
  138. package/dist/llm/stream-watchdog.js +5 -1
  139. package/dist/llm/token-counter.js +9 -2
  140. package/dist/llm/types.d.ts +4 -0
  141. package/dist/logging/sanitize-messages.js +22 -0
  142. package/dist/lsp/manager.d.ts +1 -1
  143. package/dist/lsp/manager.js +40 -10
  144. package/dist/model-catalog/builtin.d.ts +12 -0
  145. package/dist/model-catalog/builtin.js +412 -0
  146. package/dist/model-catalog/gen-connections.d.ts +20 -0
  147. package/dist/model-catalog/gen-connections.js +28 -0
  148. package/dist/model-catalog/index.d.ts +41 -0
  149. package/dist/model-catalog/index.js +90 -0
  150. package/dist/model-catalog/params.d.ts +20 -0
  151. package/dist/model-catalog/params.js +45 -0
  152. package/dist/model-catalog/resolve.d.ts +48 -0
  153. package/dist/model-catalog/resolve.js +33 -0
  154. package/dist/model-catalog/save-entry.d.ts +32 -0
  155. package/dist/model-catalog/save-entry.js +104 -0
  156. package/dist/model-catalog/types.d.ts +561 -0
  157. package/dist/model-catalog/types.js +93 -0
  158. package/dist/model-catalog/upsert.d.ts +9 -0
  159. package/dist/model-catalog/upsert.js +8 -0
  160. package/dist/onboarding.d.ts +12 -82
  161. package/dist/onboarding.js +61 -326
  162. package/dist/plugins/gitOps.d.ts +19 -0
  163. package/dist/plugins/gitOps.js +73 -4
  164. package/dist/plugins/installer/checkUpdate.d.ts +16 -0
  165. package/dist/plugins/installer/checkUpdate.js +32 -0
  166. package/dist/plugins/installer/codex/convertCommands.d.ts +19 -0
  167. package/dist/plugins/installer/codex/convertCommands.js +46 -0
  168. package/dist/plugins/installer/codex/convertMcp.d.ts +5 -2
  169. package/dist/plugins/installer/codex/convertMcp.js +45 -5
  170. package/dist/plugins/installer/install.js +25 -1
  171. package/dist/plugins/installer/installFromArchive.d.ts +43 -0
  172. package/dist/plugins/installer/installFromArchive.js +134 -0
  173. package/dist/plugins/installer/installFromSource.js +8 -2
  174. package/dist/plugins/installer/loadPluginAgents.js +6 -2
  175. package/dist/plugins/installer/loadPluginMcp.d.ts +9 -2
  176. package/dist/plugins/installer/loadPluginMcp.js +35 -2
  177. package/dist/plugins/installer/pruneDisabled.d.ts +24 -0
  178. package/dist/plugins/installer/pruneDisabled.js +73 -0
  179. package/dist/plugins/installer/types.d.ts +5 -2
  180. package/dist/plugins/installer/types.js +1 -0
  181. package/dist/plugins/installer/uninstall.js +4 -0
  182. package/dist/plugins/installer/unzip.d.ts +14 -0
  183. package/dist/plugins/installer/unzip.js +82 -0
  184. package/dist/plugins/installer/update.d.ts +14 -0
  185. package/dist/plugins/installer/update.js +53 -21
  186. package/dist/plugins/loadPluginHooks.d.ts +47 -1
  187. package/dist/plugins/loadPluginHooks.js +73 -1
  188. package/dist/plugins/marketplaceManager.d.ts +7 -0
  189. package/dist/plugins/marketplaceManager.js +20 -0
  190. package/dist/plugins/pluginCommandHook.js +4 -18
  191. package/dist/plugins/pluginContent.d.ts +30 -0
  192. package/dist/plugins/pluginContent.js +83 -0
  193. package/dist/plugins/pluginInstaller.d.ts +13 -0
  194. package/dist/plugins/pluginInstaller.js +42 -8
  195. package/dist/plugins/schemas.js +1 -0
  196. package/dist/plugins/types.d.ts +6 -0
  197. package/dist/preset/index.d.ts +11 -1
  198. package/dist/preset/index.js +115 -6
  199. package/dist/product/types.d.ts +1 -1
  200. package/dist/prompt/composer.d.ts +32 -0
  201. package/dist/prompt/composer.js +75 -21
  202. package/dist/prompt/instruction-scanner.js +5 -3
  203. package/dist/prompt/section-loader.js +1 -0
  204. package/dist/prompt/sections/base.md +2 -0
  205. package/dist/prompt/sections/browser.md +10 -0
  206. package/dist/prompt/sections/coding.md +4 -0
  207. package/dist/protocol/chat-session-manager.d.ts +9 -2
  208. package/dist/protocol/chat-session-manager.js +38 -0
  209. package/dist/protocol/chat-session.d.ts +69 -1
  210. package/dist/protocol/chat-session.js +102 -4
  211. package/dist/protocol/client.d.ts +31 -0
  212. package/dist/protocol/client.js +44 -0
  213. package/dist/protocol/server.d.ts +120 -7
  214. package/dist/protocol/server.js +753 -51
  215. package/dist/protocol/transport.js +3 -2
  216. package/dist/protocol/types.d.ts +60 -0
  217. package/dist/protocol/types.js +16 -0
  218. package/dist/quota/credentials.d.ts +3 -0
  219. package/dist/quota/credentials.js +80 -0
  220. package/dist/quota/index.d.ts +36 -0
  221. package/dist/quota/index.js +155 -0
  222. package/dist/quota/types.d.ts +48 -0
  223. package/dist/quota/types.js +13 -0
  224. package/dist/review/review-prompt.d.ts +28 -0
  225. package/dist/review/review-prompt.js +81 -0
  226. package/dist/run/FileRunStore.js +8 -3
  227. package/dist/run/RunApprovalBackend.js +25 -5
  228. package/dist/run/RunManager.d.ts +12 -0
  229. package/dist/run/RunManager.js +35 -0
  230. package/dist/run/factory.d.ts +1 -1
  231. package/dist/runtime/background-shell.d.ts +139 -0
  232. package/dist/runtime/background-shell.js +509 -0
  233. package/dist/runtime/output-clean.d.ts +24 -0
  234. package/dist/runtime/output-clean.js +41 -0
  235. package/dist/runtime/ring-file.d.ts +64 -0
  236. package/dist/runtime/ring-file.js +174 -0
  237. package/dist/runtime/safe-spawn.js +98 -39
  238. package/dist/runtime/spawn-common.d.ts +159 -0
  239. package/dist/runtime/spawn-common.js +404 -0
  240. package/dist/runtime/truncate-output.d.ts +22 -0
  241. package/dist/runtime/truncate-output.js +49 -0
  242. package/dist/runtime/utf8-cut.d.ts +11 -0
  243. package/dist/runtime/utf8-cut.js +23 -0
  244. package/dist/services/auto-dream.d.ts +4 -0
  245. package/dist/services/auto-dream.js +26 -26
  246. package/dist/services/diagnostics.d.ts +1 -2
  247. package/dist/services/diagnostics.js +12 -7
  248. package/dist/services/extract-memories.d.ts +14 -1
  249. package/dist/services/extract-memories.js +45 -6
  250. package/dist/services/memory-orchestrator.d.ts +21 -0
  251. package/dist/services/memory-orchestrator.js +125 -50
  252. package/dist/services/session-memory.js +24 -12
  253. package/dist/session/file-history.d.ts +124 -1
  254. package/dist/session/file-history.js +222 -6
  255. package/dist/session/memory.d.ts +116 -2
  256. package/dist/session/memory.js +250 -28
  257. package/dist/session/session-manager.d.ts +40 -0
  258. package/dist/session/session-manager.js +119 -3
  259. package/dist/session/simple-diff.d.ts +23 -0
  260. package/dist/session/simple-diff.js +84 -0
  261. package/dist/session/transcript.d.ts +29 -1
  262. package/dist/session/transcript.js +56 -2
  263. package/dist/session/undo-target.d.ts +67 -0
  264. package/dist/session/undo-target.js +144 -0
  265. package/dist/settings/disk-defaults.d.ts +9 -2
  266. package/dist/settings/disk-defaults.js +11 -2
  267. package/dist/settings/feature-flags.d.ts +64 -0
  268. package/dist/settings/feature-flags.js +61 -0
  269. package/dist/settings/manager.d.ts +68 -1
  270. package/dist/settings/manager.js +266 -29
  271. package/dist/settings/migrate-config.d.ts +45 -0
  272. package/dist/settings/migrate-config.js +125 -0
  273. package/dist/settings/schema-export.d.ts +25 -0
  274. package/dist/settings/schema-export.js +38 -0
  275. package/dist/settings/schema.d.ts +1186 -771
  276. package/dist/settings/schema.js +268 -97
  277. package/dist/skills/scanner.d.ts +9 -0
  278. package/dist/skills/scanner.js +30 -2
  279. package/dist/stt/resolve-transcribe.d.ts +31 -0
  280. package/dist/stt/resolve-transcribe.js +108 -0
  281. package/dist/stt/transcribe.d.ts +51 -0
  282. package/dist/stt/transcribe.js +65 -0
  283. package/dist/tool-system/browser-bridge.d.ts +226 -0
  284. package/dist/tool-system/browser-bridge.js +163 -0
  285. package/dist/tool-system/builtin/agent-heartbeat.d.ts +49 -0
  286. package/dist/tool-system/builtin/agent-heartbeat.js +89 -0
  287. package/dist/tool-system/builtin/agent-notifications.d.ts +12 -3
  288. package/dist/tool-system/builtin/agent-notifications.js +9 -3
  289. package/dist/tool-system/builtin/agent-output-file.d.ts +38 -0
  290. package/dist/tool-system/builtin/agent-output-file.js +72 -0
  291. package/dist/tool-system/builtin/agent-registry.d.ts +12 -0
  292. package/dist/tool-system/builtin/agent-registry.js +8 -0
  293. package/dist/tool-system/builtin/agent.d.ts +21 -1
  294. package/dist/tool-system/builtin/agent.js +489 -42
  295. package/dist/tool-system/builtin/apply-patch/applier.js +66 -8
  296. package/dist/tool-system/builtin/apply-patch/backup-targets.d.ts +10 -0
  297. package/dist/tool-system/builtin/apply-patch/backup-targets.js +30 -0
  298. package/dist/tool-system/builtin/apply-patch/index.js +0 -15
  299. package/dist/tool-system/builtin/background-jobs.d.ts +76 -0
  300. package/dist/tool-system/builtin/background-jobs.js +124 -0
  301. package/dist/tool-system/builtin/background-shell-tools.d.ts +20 -0
  302. package/dist/tool-system/builtin/background-shell-tools.js +108 -0
  303. package/dist/tool-system/builtin/background-work.d.ts +67 -0
  304. package/dist/tool-system/builtin/background-work.js +86 -0
  305. package/dist/tool-system/builtin/bash-output-style.d.ts +32 -0
  306. package/dist/tool-system/builtin/bash-output-style.js +40 -0
  307. package/dist/tool-system/builtin/bash.d.ts +5 -2
  308. package/dist/tool-system/builtin/bash.js +101 -64
  309. package/dist/tool-system/builtin/browser-tools.d.ts +33 -0
  310. package/dist/tool-system/builtin/browser-tools.js +312 -0
  311. package/dist/tool-system/builtin/cancel-goal.d.ts +31 -0
  312. package/dist/tool-system/builtin/cancel-goal.js +64 -0
  313. package/dist/tool-system/builtin/check-quota.d.ts +15 -0
  314. package/dist/tool-system/builtin/check-quota.js +34 -0
  315. package/dist/tool-system/builtin/config.js +7 -0
  316. package/dist/tool-system/builtin/cron.d.ts +7 -0
  317. package/dist/tool-system/builtin/cron.js +64 -4
  318. package/dist/tool-system/builtin/drive-claude-code.d.ts +30 -0
  319. package/dist/tool-system/builtin/drive-claude-code.js +157 -0
  320. package/dist/tool-system/builtin/edit-model-catalog.d.ts +3 -0
  321. package/dist/tool-system/builtin/edit-model-catalog.js +104 -0
  322. package/dist/tool-system/builtin/edit.js +20 -16
  323. package/dist/tool-system/builtin/eol.d.ts +29 -0
  324. package/dist/tool-system/builtin/eol.js +37 -0
  325. package/dist/tool-system/builtin/file-cache.d.ts +6 -0
  326. package/dist/tool-system/builtin/file-cache.js +8 -0
  327. package/dist/tool-system/builtin/generate-image.d.ts +35 -0
  328. package/dist/tool-system/builtin/generate-image.js +278 -50
  329. package/dist/tool-system/builtin/generate-video.d.ts +55 -0
  330. package/dist/tool-system/builtin/generate-video.js +364 -0
  331. package/dist/tool-system/builtin/glob.js +0 -7
  332. package/dist/tool-system/builtin/grep.d.ts +9 -0
  333. package/dist/tool-system/builtin/grep.js +106 -11
  334. package/dist/tool-system/builtin/image-providers.d.ts +86 -0
  335. package/dist/tool-system/builtin/image-providers.js +190 -0
  336. package/dist/tool-system/builtin/image-uploader.d.ts +33 -0
  337. package/dist/tool-system/builtin/image-uploader.js +74 -0
  338. package/dist/tool-system/builtin/index.d.ts +10 -2
  339. package/dist/tool-system/builtin/index.js +251 -27
  340. package/dist/tool-system/builtin/mcp-tools.js +23 -3
  341. package/dist/tool-system/builtin/memory.js +45 -7
  342. package/dist/tool-system/builtin/notebook-edit.js +0 -7
  343. package/dist/tool-system/builtin/powershell.js +8 -2
  344. package/dist/tool-system/builtin/read.js +10 -10
  345. package/dist/tool-system/builtin/repl.js +4 -1
  346. package/dist/tool-system/builtin/skill.js +9 -0
  347. package/dist/tool-system/builtin/sleep.js +8 -2
  348. package/dist/tool-system/builtin/tool-search.js +25 -7
  349. package/dist/tool-system/builtin/video-providers.d.ts +154 -0
  350. package/dist/tool-system/builtin/video-providers.js +235 -0
  351. package/dist/tool-system/builtin/web-fetch.js +12 -2
  352. package/dist/tool-system/builtin/web-search.js +21 -7
  353. package/dist/tool-system/builtin/worktree.d.ts +2 -1
  354. package/dist/tool-system/builtin/worktree.js +31 -4
  355. package/dist/tool-system/builtin/write.js +0 -6
  356. package/dist/tool-system/context.d.ts +164 -6
  357. package/dist/tool-system/executor.d.ts +3 -1
  358. package/dist/tool-system/executor.js +197 -90
  359. package/dist/tool-system/investigation-guard.js +1 -1
  360. package/dist/tool-system/mcp-manager.d.ts +42 -4
  361. package/dist/tool-system/mcp-manager.js +203 -20
  362. package/dist/tool-system/mcp-stdio-diagnostics.d.ts +9 -0
  363. package/dist/tool-system/mcp-stdio-diagnostics.js +93 -0
  364. package/dist/tool-system/path-policy.d.ts +5 -0
  365. package/dist/tool-system/path-policy.js +307 -8
  366. package/dist/tool-system/permission.d.ts +39 -2
  367. package/dist/tool-system/permission.js +283 -70
  368. package/dist/tool-system/plan-mode-allowlist.d.ts +13 -2
  369. package/dist/tool-system/plan-mode-allowlist.js +24 -2
  370. package/dist/tool-system/registry.d.ts +1 -0
  371. package/dist/tool-system/registry.js +16 -2
  372. package/dist/tool-system/sandbox/index.d.ts +8 -0
  373. package/dist/tool-system/sandbox/index.js +7 -2
  374. package/dist/tool-system/sandbox/off.js +7 -1
  375. package/dist/tool-system/validate-tool-metadata.d.ts +36 -0
  376. package/dist/tool-system/validate-tool-metadata.js +63 -0
  377. package/dist/types.d.ts +252 -7
  378. package/dist/updater.js +20 -9
  379. package/dist/utils/envUtils.d.ts +0 -9
  380. package/dist/utils/envUtils.js +3 -28
  381. package/dist/utils/exec.d.ts +48 -0
  382. package/dist/utils/exec.js +154 -0
  383. package/dist/utils/json.d.ts +12 -0
  384. package/dist/utils/json.js +92 -0
  385. package/dist/utils/theme.d.ts +1 -1
  386. package/dist/utils/theme.js +1 -1
  387. package/dist/utils/toolDisplay.js +0 -1
  388. package/package.json +13 -7
  389. package/dist/agent/coordinator.d.ts +0 -49
  390. package/dist/agent/coordinator.js +0 -77
  391. package/dist/settings/manager.test.js +0 -73
  392. package/dist/tool-system/builtin/remote-trigger.d.ts +0 -6
  393. package/dist/tool-system/builtin/remote-trigger.js +0 -54
  394. package/dist/tool-system/builtin/send-message.d.ts +0 -6
  395. package/dist/tool-system/builtin/send-message.js +0 -47
  396. /package/dist/{settings/manager.test.d.ts → credentials/types.js} +0 -0
@@ -5,7 +5,7 @@
5
5
  * Tier 2: LLM summary (async) — generate summary of older messages via model call
6
6
  * Tier 3: window compact (sync, emergency) — aggressive truncation fallback
7
7
  */
8
- import { estimateTokens, microcompact, snipCompact, windowCompact, truncateToolResult, buildSummarizationPrompt, applySummaryCompaction, applyToolResultBudget, extractAnchoredSummary, } from "./compaction.js";
8
+ import { estimateTokens, microcompact, dedupeFileReads, maskOldObservations, snipCompact, windowCompact, truncateToolResult, buildSummarizationPrompt, applySummaryCompaction, applyToolResultBudget, extractAnchoredSummary, } from "./compaction.js";
9
9
  import { applyToolResultPersistence, createContentReplacementState, reconstructContentReplacementState, resolveToolResultsDir, } from "./tool-result-storage.js";
10
10
  import { logger } from "../logging/logger.js";
11
11
  const DEFAULT_CONFIG = {
@@ -41,6 +41,8 @@ export class ContextManager {
41
41
  config;
42
42
  summarizeFn;
43
43
  consecutiveSummaryFailures = 0;
44
+ /** Prevents repeated spin-band LLM calls after a summary generated no shrink. */
45
+ suppressNoOpMicroSummaryUntilCompact = false;
44
46
  lastSummary;
45
47
  /** Last known actual token count from API usage data. */
46
48
  lastActualTokens;
@@ -91,6 +93,64 @@ export class ContextManager {
91
93
  setSummarizeFn(fn) {
92
94
  this.summarizeFn = fn;
93
95
  }
96
+ async trySummaryCompact(messages, before, logEvent) {
97
+ if (!this.summarizeFn || this.consecutiveSummaryFailures >= 3) {
98
+ return { messages, tokens: before, compacted: false, noProgress: false };
99
+ }
100
+ try {
101
+ const keepRecentN = Math.max(8, Math.floor(messages.length * 0.3));
102
+ const messagesToSummarize = messages.slice(1, -keepRecentN); // skip first (userContext) and recent
103
+ if (messagesToSummarize.length <= 3) {
104
+ return { messages, tokens: before, compacted: false, noProgress: false };
105
+ }
106
+ // Rolling summary: if a prior summary is already anchored in the
107
+ // messages (from an earlier compaction in this session or in a resumed
108
+ // session), feed it back so the LLM merges-updates rather than
109
+ // re-summarizes from scratch.
110
+ const priorSummary = extractAnchoredSummary(messages) ?? this.lastSummary;
111
+ const prompt = buildSummarizationPrompt(messagesToSummarize, priorSummary);
112
+ const summary = await this.summarizeFn(prompt);
113
+ if (!summary || summary.length <= 50) {
114
+ this.consecutiveSummaryFailures++;
115
+ logger.warn("context.summary_failed", {
116
+ failures: this.consecutiveSummaryFailures,
117
+ error: "summary was empty or too short",
118
+ });
119
+ return { messages, tokens: before, compacted: false, noProgress: true };
120
+ }
121
+ const compacted = applySummaryCompaction(messages, summary, keepRecentN, this.transcriptPath);
122
+ const after = estimateTokens(compacted);
123
+ if (after >= before) {
124
+ this.consecutiveSummaryFailures++;
125
+ logger.warn("context.summary_no_progress", {
126
+ failures: this.consecutiveSummaryFailures,
127
+ before,
128
+ after,
129
+ summaryLen: summary.length,
130
+ rolling: priorSummary !== undefined,
131
+ });
132
+ return { messages, tokens: before, compacted: false, noProgress: true };
133
+ }
134
+ this.consecutiveSummaryFailures = 0;
135
+ this.lastSummary = summary;
136
+ logger.info(logEvent, {
137
+ before,
138
+ after,
139
+ summaryLen: summary.length,
140
+ rolling: priorSummary !== undefined,
141
+ });
142
+ this.onCompact?.({ strategy: "summary", before, after });
143
+ return { messages: compacted, tokens: after, compacted: true, noProgress: false };
144
+ }
145
+ catch (err) {
146
+ this.consecutiveSummaryFailures++;
147
+ logger.warn("context.summary_failed", {
148
+ failures: this.consecutiveSummaryFailures,
149
+ error: err.message,
150
+ });
151
+ return { messages, tokens: before, compacted: false, noProgress: false };
152
+ }
153
+ }
94
154
  /**
95
155
  * Set the transcript path so compaction can reference it. The
96
156
  * tool-results directory lives alongside the transcript file:
@@ -127,6 +187,25 @@ export class ContextManager {
127
187
  // Tier 0c: Aggregate tool result budget (per-message) — char-level
128
188
  // backstop for messages still over the limit after persistence.
129
189
  result = applyToolResultBudget(result);
190
+ // Tier 0d: dedup repeated Reads of the same file — keep only the latest
191
+ // copy (older ones are stale). Always-on + zero-cost: it's pure waste
192
+ // removal (the model never needs two snapshots of one file), unlike the
193
+ // pressure-/recency-gated tiers below. Runs before microcompact so an
194
+ // already-deduped result isn't double-counted toward the keep-recent window.
195
+ const dedup = dedupeFileReads(result);
196
+ if (dedup.clearedCount > 0) {
197
+ result = dedup.messages;
198
+ logger.info("context.dedupe_file_reads", { cleared: dedup.clearedCount });
199
+ }
200
+ // Tier 0d': browser observation masking — keep only the latest
201
+ // browser_snapshot, collapse older ones (stale element lists, often large).
202
+ // Same always-on waste-removal class as dedupeFileReads. The research's
203
+ // top browser-token lever (folding old observations beats LLM summarizing).
204
+ const masked = maskOldObservations(result);
205
+ if (masked.maskedCount > 0) {
206
+ result = masked.messages;
207
+ logger.info("context.mask_browser_snapshots", { masked: masked.maskedCount });
208
+ }
130
209
  // Tier 1: microcompact — fingerprint old whitelisted tool_results.
131
210
  // Only runs above the floor ratio: under-pressure context keeps full
132
211
  // detail so the model isn't forced to re-Read files it just looked at.
@@ -221,7 +300,9 @@ export class ContextManager {
221
300
  result = applyToolResultBudget(result);
222
301
  // Tier 1: microcompact — see manage() for the rationale on the floor.
223
302
  const preTier1Tokens = this.estimateTokensHybrid(result);
224
- if (preTier1Tokens > this.config.maxTokens * this.config.microcompactFloorRatio) {
303
+ const microFloorGate = this.config.maxTokens * this.config.microcompactFloorRatio;
304
+ let microNoOpAtFloor = false;
305
+ if (preTier1Tokens > microFloorGate) {
225
306
  const keepRecentN = this.config.microcompactKeepRecent ?? defaultKeepRecent(this.config.maxTokens);
226
307
  // See manage(): onClear fires synchronously before microcompact returns,
227
308
  // so defer the token re-estimate until result is reassigned.
@@ -232,63 +313,58 @@ export class ContextManager {
232
313
  clearedInfo = info;
233
314
  },
234
315
  });
316
+ const postTier1Tokens = this.estimateTokensHybrid(result);
317
+ microNoOpAtFloor = postTier1Tokens === preTier1Tokens;
318
+ if (postTier1Tokens < preTier1Tokens) {
319
+ this.suppressNoOpMicroSummaryUntilCompact = false;
320
+ }
235
321
  if (clearedInfo) {
236
- const after = this.estimateTokensHybrid(result);
237
322
  logger.info("context.microcompact", {
238
323
  before: preTier1Tokens,
239
- after,
324
+ after: postTier1Tokens,
240
325
  keepRecentN,
241
326
  clearedRounds: clearedInfo.clearedRounds,
242
327
  toolNames: clearedInfo.toolNames,
243
328
  });
244
- this.onCompact?.({ strategy: "micro", before: preTier1Tokens, after });
329
+ this.onCompact?.({
330
+ strategy: "micro",
331
+ before: preTier1Tokens,
332
+ after: postTier1Tokens,
333
+ });
245
334
  }
246
335
  }
247
- const tokens = this.estimateTokensHybrid(result);
336
+ let tokens = this.estimateTokensHybrid(result);
248
337
  const ratio = tokens / this.config.maxTokens;
249
- // Tier 2: LLM summary if approaching limit
250
- if (ratio >= this.config.compactAtRatio &&
251
- this.summarizeFn &&
252
- this.consecutiveSummaryFailures < 3) {
253
- try {
254
- const keepRecentN = Math.max(8, Math.floor(result.length * 0.3));
255
- const messagesToSummarize = result.slice(1, -keepRecentN); // skip first (userContext) and recent
256
- if (messagesToSummarize.length > 3) {
257
- // Rolling summary: if a prior summary is already anchored in the
258
- // messages (from an earlier compaction in this session or in a
259
- // resumed session), feed it back so the LLM merges-updates rather
260
- // than re-summarizes from scratch — preserves info that would
261
- // otherwise erode across successive compactions.
262
- const priorSummary = extractAnchoredSummary(result) ?? this.lastSummary;
263
- const prompt = buildSummarizationPrompt(messagesToSummarize, priorSummary);
264
- const summary = await this.summarizeFn(prompt);
265
- if (summary && summary.length > 50) {
266
- result = applySummaryCompaction(result, summary, keepRecentN, this.transcriptPath);
267
- this.consecutiveSummaryFailures = 0;
268
- this.lastSummary = summary;
269
- const after = estimateTokens(result);
270
- logger.info("context.summary_compact", {
271
- before: tokens,
272
- after,
273
- summaryLen: summary.length,
274
- rolling: priorSummary !== undefined,
275
- });
276
- this.onCompact?.({ strategy: "summary", before: tokens, after });
277
- return result;
278
- }
279
- }
338
+ if (ratio < this.config.microcompactFloorRatio) {
339
+ this.suppressNoOpMicroSummaryUntilCompact = false;
340
+ }
341
+ const noOpMicroSpinBand = microNoOpAtFloor &&
342
+ ratio >= this.config.microcompactFloorRatio &&
343
+ ratio < this.config.compactAtRatio;
344
+ const shouldEscalateNoOpMicro = noOpMicroSpinBand && !this.suppressNoOpMicroSummaryUntilCompact;
345
+ // Tier 2: LLM summary if approaching limit, or if micro was the only tier
346
+ // available in the 0.70-0.85 band and it freed nothing.
347
+ if (ratio >= this.config.compactAtRatio || shouldEscalateNoOpMicro) {
348
+ const summarized = await this.trySummaryCompact(result, tokens, "context.summary_compact");
349
+ result = summarized.messages;
350
+ tokens = summarized.tokens;
351
+ if (summarized.compacted) {
352
+ this.suppressNoOpMicroSummaryUntilCompact = false;
353
+ return result;
280
354
  }
281
- catch (err) {
282
- this.consecutiveSummaryFailures++;
283
- logger.warn("context.summary_failed", {
284
- failures: this.consecutiveSummaryFailures,
285
- error: err.message,
355
+ if (shouldEscalateNoOpMicro && summarized.noProgress) {
356
+ this.suppressNoOpMicroSummaryUntilCompact = true;
357
+ logger.info("context.micro_noop_summary_suppressed", {
358
+ tokens,
359
+ ratio,
360
+ compactAtRatio: this.config.compactAtRatio,
361
+ microcompactFloorRatio: this.config.microcompactFloorRatio,
286
362
  });
287
363
  }
288
364
  }
289
- // Reuse the `tokens` we already computed above. We only get here if the
290
- // LLM summary path didn't fire (no summarizeFn, too many failures, or it
291
- // threw) fall back to the same severity ladder as manage().
365
+ // Reuse the `tokens` we already computed above. We only get here if no
366
+ // summary compacted the prompt (no summarizeFn, too many failures, a
367
+ // thrown error, or a generated summary that did not shrink anything).
292
368
  let live = tokens;
293
369
  const snipGate = this.config.maxTokens * this.config.compactAtRatio;
294
370
  const windowGate = this.config.maxTokens * (this.config.compactAtRatio + 0.05);
@@ -317,6 +393,61 @@ export class ContextManager {
317
393
  }
318
394
  return result;
319
395
  }
396
+ /**
397
+ * Force maximum compaction, ignoring the ratio gates. This is what a manual
398
+ * `/compact` invokes: the user explicitly asked to shrink NOW, so we don't
399
+ * wait for the prompt to reach compactAtRatio.
400
+ *
401
+ * Order: tier-0 cleanups (persist/truncate/dedupe/mask) + microcompact, then
402
+ * an unconditional LLM summary of the older messages. If no summarizeFn is
403
+ * wired (or it fails / yields nothing), fall back to snip → window so the
404
+ * call still shrinks the conversation rather than no-opping.
405
+ *
406
+ * Unlike manage()/manageAsync(), there is NO `ratio >= compactAtRatio` gate:
407
+ * a long-but-under-threshold text-only conversation (the /compact bug) still
408
+ * gets summarized here.
409
+ */
410
+ async forceSummarize(messages) {
411
+ let result = messages;
412
+ // Tier 0: same waste-removal + micro as the automatic path.
413
+ result = this.persistLargeToolResults(result);
414
+ result = this.truncateToolResults(result);
415
+ result = applyToolResultBudget(result);
416
+ const dedup = dedupeFileReads(result);
417
+ if (dedup.clearedCount > 0)
418
+ result = dedup.messages;
419
+ const masked = maskOldObservations(result);
420
+ if (masked.maskedCount > 0)
421
+ result = masked.messages;
422
+ const keepRecentN = this.config.microcompactKeepRecent ?? defaultKeepRecent(this.config.maxTokens);
423
+ result = microcompact(result, { keepRecentN });
424
+ let tokens = this.estimateTokensHybrid(result);
425
+ // Unconditional LLM summary (no ratio gate).
426
+ {
427
+ const summarized = await this.trySummaryCompact(result, tokens, "context.force_summary_compact");
428
+ result = summarized.messages;
429
+ tokens = summarized.tokens;
430
+ if (summarized.compacted)
431
+ return result;
432
+ }
433
+ // Fallback: no summary available — snip, then window, so /compact still
434
+ // shrinks the conversation instead of no-opping.
435
+ {
436
+ const before = tokens;
437
+ result = snipCompact(result, 3, 8);
438
+ tokens = this.estimateTokensHybrid(result);
439
+ if (tokens < before)
440
+ this.onCompact?.({ strategy: "snip", before, after: tokens });
441
+ }
442
+ if (this.estimateTokensHybrid(result) >= this.estimateTokensHybrid(messages)) {
443
+ const before = tokens;
444
+ const keepN = Math.max(10, Math.floor(result.length * 0.4));
445
+ result = windowCompact(result, keepN);
446
+ tokens = this.estimateTokensHybrid(result);
447
+ this.onCompact?.({ strategy: "window", before, after: tokens });
448
+ }
449
+ return result;
450
+ }
320
451
  /**
321
452
  * Persist large tool_result blocks to disk and replace them with a
322
453
  * preview + filepath. No-op when transcript path hasn't been set
@@ -341,20 +472,22 @@ export class ContextManager {
341
472
  */
342
473
  truncateToolResults(messages) {
343
474
  const maxChars = this.config.maxToolResultChars;
344
- let modified = false;
345
475
  const result = messages.map((msg) => {
346
476
  if (!Array.isArray(msg.content))
347
477
  return msg;
478
+ // Per-message flag: a truncation in an earlier message must not force
479
+ // later, unchanged messages to be spread-copied.
480
+ let messageModified = false;
348
481
  const newContent = msg.content.map((block) => {
349
482
  if (block.type === "tool_result" && typeof block.content === "string") {
350
483
  if (block.content.length > maxChars) {
351
- modified = true;
484
+ messageModified = true;
352
485
  return { ...block, content: truncateToolResult(block.content, maxChars) };
353
486
  }
354
487
  }
355
488
  return block;
356
489
  });
357
- return modified ? { ...msg, content: newContent } : msg;
490
+ return messageModified ? { ...msg, content: newContent } : msg;
358
491
  });
359
492
  return result;
360
493
  }
@@ -69,11 +69,24 @@ function estimateBlockTokens(block) {
69
69
  if (block.content && typeof block.content === "string") {
70
70
  tokens += estimateStringTokens(block.content);
71
71
  }
72
+ else if (Array.isArray(block.content)) {
73
+ for (const nested of block.content) {
74
+ tokens += estimateBlockTokens(nested);
75
+ }
76
+ }
72
77
  if (block.input) {
73
78
  tokens += estimateStringTokens(JSON.stringify(block.input));
74
79
  }
75
80
  if (block.name)
76
81
  tokens += estimateStringTokens(block.name);
82
+ if (block.source?.data) {
83
+ tokens += estimateStringTokens(block.source.media_type);
84
+ tokens += estimateStringTokens(block.source.data);
85
+ }
86
+ const maybeOpenAI = block;
87
+ if (typeof maybeOpenAI.image_url?.url === "string") {
88
+ tokens += estimateStringTokens(maybeOpenAI.image_url.url);
89
+ }
77
90
  return tokens;
78
91
  }
79
92
  export function calculateContextUsage(messages, systemPrompt, maxTokens) {
@@ -3,67 +3,11 @@
3
3
  */
4
4
  import { NOOP_COLORIZER } from "./colorizer.js";
5
5
  import { findOpenRouterModel } from "./data/openrouter-models.js";
6
- function pricing(input, output) {
7
- // Default cache pricing: read = 10% of input, write = 125% of input
8
- return { input, output, cacheRead: input * 0.1, cacheWrite: input * 1.25 };
9
- }
10
- const MODEL_PRICING = {
11
- // Anthropic (per 1M tokens, USD)
12
- "claude-opus-4.6": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
13
- "claude-opus-4-6": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 }, // alias
14
- "claude-opus-4.5": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
15
- "claude-opus-4.1": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
16
- "claude-opus-4": { input: 15, output: 75, cacheRead: 1.5, cacheWrite: 18.75 },
17
- "claude-sonnet-4.6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
18
- "claude-sonnet-4-6": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 }, // alias
19
- "claude-sonnet-4.5": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
20
- "claude-sonnet-4": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
21
- "claude-3.7-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
22
- "claude-3-7-sonnet": { input: 3, output: 15, cacheRead: 0.3, cacheWrite: 3.75 },
23
- "claude-3.5-haiku": { input: 0.8, output: 4, cacheRead: 0.08, cacheWrite: 1 },
24
- "claude-haiku-4.5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 },
25
- "claude-haiku-4-5": { input: 1, output: 5, cacheRead: 0.1, cacheWrite: 1.25 }, // alias
26
- // OpenAI
27
- "gpt-5.4": pricing(5, 20),
28
- "gpt-5.4-mini": pricing(1.5, 6),
29
- "gpt-5.4-pro": pricing(10, 40),
30
- "gpt-5": pricing(5, 20),
31
- "gpt-4o": pricing(2.5, 10),
32
- "gpt-4o-mini": pricing(0.15, 0.6),
33
- "gpt-4.1": pricing(2, 8),
34
- "gpt-4.1-mini": pricing(0.4, 1.6),
35
- "o4-mini": pricing(1.1, 4.4),
36
- "o3": pricing(10, 40),
37
- "o3-mini": pricing(1.1, 4.4),
38
- // Google
39
- "gemini-2.5-pro": pricing(1.25, 10),
40
- "gemini-2.5-pro-preview": pricing(1.25, 10),
41
- "gemini-2.5-flash": pricing(0.15, 0.6),
42
- "gemini-3.1-pro-preview": pricing(2, 10),
43
- "gemini-3-flash-preview": pricing(0.15, 0.6),
44
- "gemini-2.0-flash": pricing(0.1, 0.4),
45
- // DeepSeek
46
- "deepseek-v4-flash": pricing(0.126, 0.252),
47
- "deepseek-v4-pro": pricing(0.5, 2),
48
- "deepseek-v3.2": pricing(0.14, 0.28),
49
- "deepseek-chat": pricing(0.14, 0.28),
50
- "deepseek-r1": pricing(0.55, 2.19),
51
- "deepseek-reasoner": pricing(0.55, 2.19),
52
- // Qwen
53
- "qwen3-coder": pricing(0.3, 0.6),
54
- "qwen3-235b-a22b": pricing(0.3, 1.2),
55
- "qwen3-30b-a3b": pricing(0.1, 0.3),
56
- "qwen3-max": pricing(0.5, 2),
57
- // Meta
58
- "llama-4-maverick": pricing(0.2, 0.8),
59
- "llama-4-scout": pricing(0.15, 0.4),
60
- // Mistral
61
- "devstral-medium": pricing(0.5, 1.5),
62
- "mistral-large": pricing(2, 6),
63
- "devstral-small": pricing(0.1, 0.3),
64
- };
65
- // Default fallback pricing
66
- const DEFAULT_PRICING = pricing(3, 15);
6
+ import { MODEL_PRICING, DEFAULT_PRICING, } from "./data/model-metadata.js";
7
+ // Pricing per 1M tokens (USD). The MODEL_PRICING table + DEFAULT_PRICING now
8
+ // live in data/model-metadata.json (loaded by data/model-metadata.ts) so a
9
+ // price change is a data edit, not a code change. cacheRead/cacheWrite are
10
+ // derived there: read = 10% of input, write = 125% of input.
67
11
  /** Build a ModelPricing from an OpenRouter snapshot entry. */
68
12
  function openRouterPricing(hit) {
69
13
  const input = hit.inputPricePerMillion;
@@ -0,0 +1,49 @@
1
+ /**
2
+ * Credential encryption boundary.
3
+ *
4
+ * The core has no business owning a platform encryption key — on the desktop
5
+ * the only safe key lives behind Electron `safeStorage`, which is in the main
6
+ * process, not in this worker. So core defines an INTERFACE and the host feeds
7
+ * an implementation: desktop main injects a safeStorage-backed cipher; the
8
+ * headless CLI / SDK inject {@link PlaintextCipher}. This keeps `safeStorage`
9
+ * out of `packages/core` entirely (`grep -R safeStorage packages/core/src`
10
+ * must stay empty) and puts secret crypto where the key actually is.
11
+ *
12
+ * The stored field is a tagged string so a store written by one cipher can be
13
+ * read (or rejected) by another:
14
+ * - `plain:<secret>` — PlaintextCipher, or any pre-cipher legacy value
15
+ * that has no recognized prefix (treated as plain).
16
+ * - `enc:<scheme>:<base64>` — an encrypting cipher; `<scheme>` lets a cipher
17
+ * recognize its own ciphertext via canDecrypt().
18
+ */
19
+ export interface EncryptionCipher {
20
+ /** Encrypt a plaintext secret into its stored (tagged) form. */
21
+ encrypt(plaintext: string): string;
22
+ /** Decrypt a stored value back to plaintext. Must accept this cipher's own
23
+ * output and legacy un-prefixed plaintext; may throw if a value is
24
+ * recognizably foreign and undecryptable. */
25
+ decrypt(stored: string): string;
26
+ /** True when this cipher can decrypt `stored`. Used by the store to decide
27
+ * whether to migrate (re-encrypt on next save) a value written by a
28
+ * different cipher / left as legacy plaintext. */
29
+ canDecrypt?(stored: string): boolean;
30
+ }
31
+ /**
32
+ * The no-encryption strategy — chosen explicitly, not a no-op. Headless and
33
+ * SDK hosts have no safe key store, so they keep credentials as owner-only
34
+ * (0o600) plaintext, exactly as before this boundary existed. Named so the
35
+ * choice reads honestly in host wiring: `new CredentialStore(cwd, new
36
+ * PlaintextCipher())` says "plaintext on purpose", not "forgot to encrypt".
37
+ */
38
+ export declare class PlaintextCipher implements EncryptionCipher {
39
+ encrypt(plaintext: string): string;
40
+ decrypt(stored: string): string;
41
+ canDecrypt(stored: string): boolean;
42
+ }
43
+ /** Reads a value that may be tagged (`plain:`) or legacy bare plaintext. */
44
+ export declare function readPlaintext(stored: string): string;
45
+ /** Host startup hook: install the process-wide credential cipher (desktop main
46
+ * passes a safeStorage-backed implementation). Idempotent; last call wins. */
47
+ export declare function setDefaultCredentialCipher(cipher: EncryptionCipher): void;
48
+ /** The current process-default cipher (PlaintextCipher unless a host set one). */
49
+ export declare function getDefaultCredentialCipher(): EncryptionCipher;
@@ -0,0 +1,45 @@
1
+ const PLAIN_PREFIX = "plain:";
2
+ /**
3
+ * The no-encryption strategy — chosen explicitly, not a no-op. Headless and
4
+ * SDK hosts have no safe key store, so they keep credentials as owner-only
5
+ * (0o600) plaintext, exactly as before this boundary existed. Named so the
6
+ * choice reads honestly in host wiring: `new CredentialStore(cwd, new
7
+ * PlaintextCipher())` says "plaintext on purpose", not "forgot to encrypt".
8
+ */
9
+ export class PlaintextCipher {
10
+ encrypt(plaintext) {
11
+ return `${PLAIN_PREFIX}${plaintext}`;
12
+ }
13
+ decrypt(stored) {
14
+ // Accept our own tag, and treat any un-tagged legacy value as plaintext.
15
+ if (stored.startsWith(PLAIN_PREFIX))
16
+ return stored.slice(PLAIN_PREFIX.length);
17
+ if (stored.startsWith("enc:")) {
18
+ throw new Error("PlaintextCipher cannot decrypt an encrypted credential");
19
+ }
20
+ return stored;
21
+ }
22
+ canDecrypt(stored) {
23
+ return !stored.startsWith("enc:");
24
+ }
25
+ }
26
+ /** Reads a value that may be tagged (`plain:`) or legacy bare plaintext. */
27
+ export function readPlaintext(stored) {
28
+ return stored.startsWith(PLAIN_PREFIX) ? stored.slice(PLAIN_PREFIX.length) : stored;
29
+ }
30
+ // ─── Process-default cipher ──────────────────────────────────────
31
+ // CredentialStore is constructed at ~12 call sites (core + desktop) as
32
+ // `new CredentialStore(cwd)`. Rather than thread a cipher through every one,
33
+ // the host sets the process default ONCE at startup; stores pick it up unless
34
+ // a cipher is passed explicitly. Defaults to PlaintextCipher so any host that
35
+ // never calls the setter behaves exactly as before.
36
+ let defaultCipher = new PlaintextCipher();
37
+ /** Host startup hook: install the process-wide credential cipher (desktop main
38
+ * passes a safeStorage-backed implementation). Idempotent; last call wins. */
39
+ export function setDefaultCredentialCipher(cipher) {
40
+ defaultCipher = cipher;
41
+ }
42
+ /** The current process-default cipher (PlaintextCipher unless a host set one). */
43
+ export function getDefaultCredentialCipher() {
44
+ return defaultCipher;
45
+ }
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Cookie jar 工具(凭证模块第二期):core 侧的纯函数,把存进 CredentialStore 的
3
+ * cookie 凭证(序列化的 jar)转成 yt-dlp/curl/wget/aria2 都吃的 Netscape cookies.txt。
4
+ *
5
+ * 形态与 desktop/src/main/credentials-service.ts 的 `formatNetscapeCookies` 一致
6
+ * (desktop 在拓取那一刻用,core 在取用那一刻用)。core 不能 import desktop,故各持一份
7
+ * 同语义的纯实现 —— 都无 Electron 依赖、可单测。
8
+ */
9
+ /** 与 Electron Cookie 对齐的最小子集(jar 里存的就是这个)。 */
10
+ export interface CookieLike {
11
+ domain?: string;
12
+ hostOnly?: boolean;
13
+ path?: string;
14
+ secure?: boolean;
15
+ expirationDate?: number;
16
+ name: string;
17
+ value: string;
18
+ }
19
+ /** Cookie[] → Netscape cookies.txt 字符串。跳过含 TAB/换行的脏 cookie。 */
20
+ export declare function formatNetscapeCookies(cookies: CookieLike[]): string;
21
+ /**
22
+ * 解析 cookie 凭证的 `secret`(序列化 jar)。容错:非数组/坏 JSON → 空数组。
23
+ */
24
+ export declare function parseCookieJar(secret: string | undefined): CookieLike[];
@@ -0,0 +1,40 @@
1
+ /**
2
+ * Cookie jar 工具(凭证模块第二期):core 侧的纯函数,把存进 CredentialStore 的
3
+ * cookie 凭证(序列化的 jar)转成 yt-dlp/curl/wget/aria2 都吃的 Netscape cookies.txt。
4
+ *
5
+ * 形态与 desktop/src/main/credentials-service.ts 的 `formatNetscapeCookies` 一致
6
+ * (desktop 在拓取那一刻用,core 在取用那一刻用)。core 不能 import desktop,故各持一份
7
+ * 同语义的纯实现 —— 都无 Electron 依赖、可单测。
8
+ */
9
+ function bad(s) {
10
+ return s.includes("\t") || s.includes("\n") || s.includes("\r");
11
+ }
12
+ /** Cookie[] → Netscape cookies.txt 字符串。跳过含 TAB/换行的脏 cookie。 */
13
+ export function formatNetscapeCookies(cookies) {
14
+ const lines = ["# Netscape HTTP Cookie File"];
15
+ for (const c of cookies) {
16
+ if (bad(c.name) || bad(c.value) || (c.domain && bad(c.domain)))
17
+ continue;
18
+ const domain = c.domain ?? "";
19
+ const includeSub = c.hostOnly === true ? "FALSE" : "TRUE";
20
+ const path = c.path ?? "/";
21
+ const secure = c.secure ? "TRUE" : "FALSE";
22
+ const expiry = typeof c.expirationDate === "number" ? String(Math.floor(c.expirationDate)) : "0";
23
+ lines.push([domain, includeSub, path, secure, expiry, c.name, c.value].join("\t"));
24
+ }
25
+ return lines.join("\n") + "\n";
26
+ }
27
+ /**
28
+ * 解析 cookie 凭证的 `secret`(序列化 jar)。容错:非数组/坏 JSON → 空数组。
29
+ */
30
+ export function parseCookieJar(secret) {
31
+ if (!secret)
32
+ return [];
33
+ try {
34
+ const parsed = JSON.parse(secret);
35
+ return Array.isArray(parsed) ? parsed : [];
36
+ }
37
+ catch {
38
+ return [];
39
+ }
40
+ }
@@ -0,0 +1,7 @@
1
+ export { CredentialStore } from "./store.js";
2
+ export type { CredentialScope, MaskedCredential } from "./store.js";
3
+ export { type EncryptionCipher, PlaintextCipher, setDefaultCredentialCipher, getDefaultCredentialCipher, } from "./cipher.js";
4
+ export type { Credential, CredentialType, CredentialStoreFile } from "./types.js";
5
+ export { formatNetscapeCookies, parseCookieJar, type CookieLike } from "./cookie-jar.js";
6
+ export { useCredentialToolDef, useCredentialToolDefFor, useCredentialTool, sweepStaleCredentialCookies, } from "./use-credential-tool.js";
7
+ export { credentialUseGate } from "./use-gate.js";
@@ -0,0 +1,5 @@
1
+ export { CredentialStore } from "./store.js";
2
+ export { PlaintextCipher, setDefaultCredentialCipher, getDefaultCredentialCipher, } from "./cipher.js";
3
+ export { formatNetscapeCookies, parseCookieJar } from "./cookie-jar.js";
4
+ export { useCredentialToolDef, useCredentialToolDefFor, useCredentialTool, sweepStaleCredentialCookies, } from "./use-credential-tool.js";
5
+ export { credentialUseGate } from "./use-gate.js";
@@ -0,0 +1,20 @@
1
+ /**
2
+ * InjectCredential 工具:把一条 cookie 凭证「注入内置浏览器」(恢复登录态),
3
+ * 让 AI 能以该账号身份在内置浏览器面板做 UI 操作(配 browser_* 工具)。
4
+ *
5
+ * 与 UseCredential 的区别:
6
+ * - UseCredential 取 cookie 文件路径走 HTTP 请求(curl/yt-dlp),只读、不改浏览器。
7
+ * - InjectCredential 改的是内置浏览器的登录态(先清再灌),副作用更大 →
8
+ * 独立的逐条门 `autoInjectByAI`(不复用 autoUseByAI)。
9
+ *
10
+ * 跨进程:实际的 restoreCookiesToBrowser 在 desktop main(core 够不到 Electron
11
+ * session),经 `ctx.injectCredentialToBrowser` 回调(宿主注入,镜像 askUser)触发。
12
+ */
13
+ import type { ToolDefinition } from "../types.js";
14
+ import type { ToolContext } from "../tool-system/context.js";
15
+ export declare const injectCredentialToolDef: ToolDefinition;
16
+ /** 该工具仅在有 cookie 凭证 且 宿主接了注入回调时才可见(BUILTIN_TOOL_GUARDS)。 */
17
+ export declare function isInjectCredentialAvailable(cwd: string): boolean;
18
+ export declare function injectCredentialTool(args: Record<string, unknown>, ctx?: ToolContext): Promise<string>;
19
+ /** 测试钩子:清空会话 allow 集。 */
20
+ export declare function __resetInjectCredentialSessionAllowForTests(): void;