@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
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Speech-to-text transcription service (voice input / dictation).
3
+ *
4
+ * A NON-tool, pure "creds + audio bytes → text" service: the desktop composer
5
+ * records the user's voice and calls this to fill the input box (Codex-style
6
+ * dictation). It is deliberately NOT an agent tool — the user is speaking their
7
+ * own prompt, not asking the model to transcribe a file.
8
+ *
9
+ * Targets the OpenAI-compatible `/audio/transcriptions` endpoint, which a single
10
+ * adapter covers across OpenAI (whisper-1 / gpt-4o-transcribe), Groq
11
+ * (whisper-large-v3-turbo), and self-hosted whisper.cpp servers — they share
12
+ * the same multipart wire shape; only baseUrl + model differ.
13
+ *
14
+ * `fetch` is injected so this is unit-testable without network (mirrors
15
+ * image-providers.ts). Production callers pass the global `fetch`.
16
+ */
17
+ export interface TranscribeCreds {
18
+ baseUrl: string;
19
+ apiKey: string;
20
+ }
21
+ export interface TranscribeRequest {
22
+ /** Raw audio bytes (NOT base64) — e.g. a webm/opus recording. */
23
+ audio: Uint8Array;
24
+ /** MIME type of the audio, e.g. "audio/webm". */
25
+ mimeType: string;
26
+ /** Multipart part filename hint (extension matters to some servers). */
27
+ filename: string;
28
+ /** Model id, e.g. "gpt-4o-transcribe" | "whisper-1". */
29
+ model: string;
30
+ creds: TranscribeCreds;
31
+ /** Optional ISO-639-1 language hint (improves accuracy / latency). */
32
+ language?: string;
33
+ /** Optional cancellation signal forwarded to fetch. */
34
+ signal?: AbortSignal;
35
+ /** Injected for tests; defaults to global fetch. */
36
+ fetchImpl?: typeof fetch;
37
+ }
38
+ export type TranscribeResult = {
39
+ ok: true;
40
+ text: string;
41
+ } | {
42
+ ok: false;
43
+ error: string;
44
+ };
45
+ /**
46
+ * Transcribe audio via an OpenAI-compatible `/audio/transcriptions` endpoint.
47
+ * Posts multipart/form-data (file + model + response_format[+ language]) with a
48
+ * Bearer key; reads `{ text }` from the JSON response. Do NOT set Content-Type
49
+ * manually — fetch derives the multipart boundary from the FormData body.
50
+ */
51
+ export declare function transcribe(req: TranscribeRequest): Promise<TranscribeResult>;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Speech-to-text transcription service (voice input / dictation).
3
+ *
4
+ * A NON-tool, pure "creds + audio bytes → text" service: the desktop composer
5
+ * records the user's voice and calls this to fill the input box (Codex-style
6
+ * dictation). It is deliberately NOT an agent tool — the user is speaking their
7
+ * own prompt, not asking the model to transcribe a file.
8
+ *
9
+ * Targets the OpenAI-compatible `/audio/transcriptions` endpoint, which a single
10
+ * adapter covers across OpenAI (whisper-1 / gpt-4o-transcribe), Groq
11
+ * (whisper-large-v3-turbo), and self-hosted whisper.cpp servers — they share
12
+ * the same multipart wire shape; only baseUrl + model differ.
13
+ *
14
+ * `fetch` is injected so this is unit-testable without network (mirrors
15
+ * image-providers.ts). Production callers pass the global `fetch`.
16
+ */
17
+ /**
18
+ * Transcribe audio via an OpenAI-compatible `/audio/transcriptions` endpoint.
19
+ * Posts multipart/form-data (file + model + response_format[+ language]) with a
20
+ * Bearer key; reads `{ text }` from the JSON response. Do NOT set Content-Type
21
+ * manually — fetch derives the multipart boundary from the FormData body.
22
+ */
23
+ export async function transcribe(req) {
24
+ const fetchImpl = req.fetchImpl ?? fetch;
25
+ // Trim trailing slashes so `${baseUrl}/audio/...` doesn't double up.
26
+ const baseUrl = req.creds.baseUrl.replace(/\/+$/, "");
27
+ const form = new FormData();
28
+ // Copy into a fresh Uint8Array so the Blob gets a clean ArrayBuffer (avoids
29
+ // SharedArrayBuffer / byteOffset typing issues across runtimes).
30
+ const buf = Uint8Array.from(req.audio);
31
+ form.append("file", new Blob([buf], { type: req.mimeType }), req.filename);
32
+ form.append("model", req.model);
33
+ form.append("response_format", "json");
34
+ if (req.language)
35
+ form.append("language", req.language);
36
+ let resp;
37
+ try {
38
+ resp = await fetchImpl(`${baseUrl}/audio/transcriptions`, {
39
+ method: "POST",
40
+ headers: { Authorization: `Bearer ${req.creds.apiKey}` },
41
+ body: form,
42
+ signal: req.signal,
43
+ });
44
+ }
45
+ catch (err) {
46
+ return { ok: false, error: `request failed: ${err.message}` };
47
+ }
48
+ if (!resp.ok) {
49
+ const body = (await resp.text().catch(() => "")).slice(0, 500);
50
+ return { ok: false, error: `transcription API returned ${resp.status}: ${body}` };
51
+ }
52
+ let json;
53
+ try {
54
+ json = await resp.json();
55
+ }
56
+ catch (err) {
57
+ return { ok: false, error: `could not parse transcription response: ${err.message}` };
58
+ }
59
+ const text = json?.text;
60
+ if (typeof text !== "string") {
61
+ const preview = JSON.stringify(json).slice(0, 500);
62
+ return { ok: false, error: `no text in transcription response: ${preview}` };
63
+ }
64
+ return { ok: true, text };
65
+ }
@@ -0,0 +1,226 @@
1
+ /**
2
+ * BrowserBridge — driver-agnostic contract between the browser tools (core)
3
+ * and whatever drives the actual browser (renderer's webview via CDP).
4
+ *
5
+ * Spec: docs/superpowers/specs/2026-06-16-browser-automation-mvp.md
6
+ *
7
+ * The core tools only know this interface. The renderer implements it on top
8
+ * of the webview's `webContents.debugger` (CDP): observe via
9
+ * Accessibility.getFullAXTree, act via DOM.getBoxModel → Input.dispatchMouseEvent.
10
+ * Keeping it driver-agnostic means a future implementation (a hidden
11
+ * BrowserWindow for unattended runs, or an external engine) can swap in without
12
+ * touching the tools. Undefined on ToolContext → headless / no panel → tools
13
+ * degrade with a clear error.
14
+ */
15
+ /** One interactive element from the page's accessibility tree. */
16
+ export interface BrowserElement {
17
+ /** Per-snapshot reference id (e1, e2, …); the renderer maps it back to a
18
+ * backendDOMNodeId for the action tools. Reassigned each snapshot. */
19
+ ref: string;
20
+ /** ARIA role (button, link, textbox, checkbox, combobox, …). */
21
+ role: string;
22
+ /** Accessible name (visible text / label). May be empty. */
23
+ name: string;
24
+ /** True for password/sensitive inputs — value is never captured (security). */
25
+ sensitive?: boolean;
26
+ /** Optional value for non-sensitive inputs (e.g. current textbox text). */
27
+ value?: string;
28
+ }
29
+ export interface BrowserSnapshot {
30
+ url: string;
31
+ title?: string;
32
+ elements: BrowserElement[];
33
+ /** Set when the page needs the user to act (login wall / 2FA) — agent should
34
+ * hand control back to the user rather than retry. */
35
+ needsHuman?: string;
36
+ }
37
+ export interface BrowserResult {
38
+ ok: boolean;
39
+ /** Human-readable detail (error reason, or short success note). */
40
+ detail?: string;
41
+ /** True when a ref no longer resolves (DOM changed) → agent should re-snapshot. */
42
+ staleRef?: boolean;
43
+ }
44
+ /** Result of reading the page's main textual content (扒内容). */
45
+ export interface BrowserContent {
46
+ ok: boolean;
47
+ url: string;
48
+ title?: string;
49
+ /** Extracted readable text (main content, scripts/styles/nav stripped). */
50
+ text: string;
51
+ /** True if the text was truncated to a cap. */
52
+ truncated?: boolean;
53
+ detail?: string;
54
+ }
55
+ /** One hyperlink extracted from the page (a[href]). */
56
+ export interface BrowserLink {
57
+ /** Visible link text (trimmed, may be empty for icon-only links). */
58
+ text: string;
59
+ /** Absolute URL (href resolved against the page). */
60
+ url: string;
61
+ }
62
+ /** One image extracted from the page (img[src]). */
63
+ export interface BrowserImage {
64
+ /** Absolute image URL (src resolved against the page). */
65
+ url: string;
66
+ /** alt text if present (helps the agent know what the image is). */
67
+ alt?: string;
68
+ /** Per-extract ref (imgN) — pass to browser_observe(image) to see its pixels. */
69
+ ref?: string;
70
+ }
71
+ /** One video extracted from the page (<video src> / <source src>). */
72
+ export interface BrowserVideo {
73
+ /** Absolute video URL (src resolved against the page). */
74
+ url: string;
75
+ }
76
+ /**
77
+ * Result of extracting the page's link/image URLs (扒链接/图片地址).
78
+ * The a11y snapshot deliberately omits href/src (token economy); this is the
79
+ * explicit opt-in for "I need the actual URLs" — e.g. collect article links,
80
+ * find a video/image source to hand to yt-dlp/curl.
81
+ */
82
+ export interface BrowserExtract {
83
+ ok: boolean;
84
+ url: string;
85
+ title?: string;
86
+ links: BrowserLink[];
87
+ images: BrowserImage[];
88
+ /** Video/source URLs found on the page (a downloader like yt-dlp can fetch). */
89
+ videos: BrowserVideo[];
90
+ /** True if any list was capped (page had more) — narrow the page first. */
91
+ truncated?: boolean;
92
+ detail?: string;
93
+ }
94
+ /** A captured image's bytes, ready to become a vision ContentBlock. */
95
+ export interface BrowserImageData {
96
+ ok: boolean;
97
+ /** base64 (no data: prefix). */
98
+ base64?: string;
99
+ /** "image/jpeg" | "image/png" | … */
100
+ mediaType?: string;
101
+ /** ref the image came from (so the tool can label which image is which). */
102
+ ref?: string;
103
+ detail?: string;
104
+ }
105
+ export interface BrowserBridge {
106
+ snapshot(): Promise<BrowserSnapshot>;
107
+ click(ref: string): Promise<BrowserResult>;
108
+ type(ref: string, text: string): Promise<BrowserResult>;
109
+ navigate(url: string): Promise<BrowserResult>;
110
+ scroll(dir: "up" | "down", amount?: number): Promise<BrowserResult>;
111
+ /** Read the page's main readable text content (for summarizing / extraction). */
112
+ readContent(): Promise<BrowserContent>;
113
+ /** Extract the page's hyperlink + image URLs (href/src the a11y tree omits). */
114
+ extractLinks(): Promise<BrowserExtract>;
115
+ /** Wait until the page finishes loading (or a timeout). */
116
+ waitForLoad(timeoutMs?: number): Promise<BrowserResult>;
117
+ /** Hover over an element by ref (reveal hover-dependent menus/tooltips). */
118
+ hover(ref: string): Promise<BrowserResult>;
119
+ /**
120
+ * Select an option in a native <select> by ref. `value` matches an option's
121
+ * value or visible text. Custom <div> dropdowns are NOT this — click to expand
122
+ * them and click the option from the next snapshot.
123
+ */
124
+ selectOption(ref: string, value: string): Promise<BrowserResult>;
125
+ /**
126
+ * Press a key (or combination) on the focused element / a given ref. `key` is
127
+ * a key name ("Enter", "Tab", "Escape", "ArrowDown") or a combination
128
+ * ("Control+a"). Focuses `ref` first if given (so the key lands there).
129
+ */
130
+ pressKey(key: string, ref?: string): Promise<BrowserResult>;
131
+ /**
132
+ * Fetch the real pixels of page images by ref (e.g. 小红书 笔记配图) so a
133
+ * vision model can SEE their content. Fetched in-page (carries the page's
134
+ * cookies → beats hotlink protection). One result per requested ref.
135
+ */
136
+ fetchImages(refs: string[]): Promise<BrowserImageData[]>;
137
+ /**
138
+ * Screenshot the viewport, or a single element's box if `ref` given (a
139
+ * <video> ref → its current frame). For "see the rendered layout / canvas /
140
+ * chart" — when the a11y tree isn't enough.
141
+ */
142
+ screenshot(ref?: string): Promise<BrowserImageData>;
143
+ /** List the open browser tabs (the agent picks one to drive via switchTab). */
144
+ listTabs(): Promise<BrowserTab[]>;
145
+ /** Make a tab the active automation target (subsequent actions drive it). */
146
+ switchTab(tabId: string): Promise<BrowserResult>;
147
+ }
148
+ /** One open browser tab, as the agent sees it. */
149
+ export interface BrowserTab {
150
+ /** Stable id (the desktop webContents id, as a string). */
151
+ tabId: string;
152
+ url: string;
153
+ title: string;
154
+ /** True for the tab automation currently drives. */
155
+ active: boolean;
156
+ }
157
+ /**
158
+ * Minimal shape of a CDP Accessibility.getFullAXTree node we depend on.
159
+ * (The real payload has more fields; we read only these.)
160
+ */
161
+ export interface AXNode {
162
+ nodeId: string;
163
+ ignored?: boolean;
164
+ role?: {
165
+ value?: string;
166
+ };
167
+ name?: {
168
+ value?: string;
169
+ };
170
+ value?: {
171
+ value?: string;
172
+ };
173
+ backendDOMNodeId?: number;
174
+ properties?: Array<{
175
+ name: string;
176
+ value?: {
177
+ value?: unknown;
178
+ };
179
+ }>;
180
+ }
181
+ /**
182
+ * Pure: flatten a CDP accessibility tree into the compact, ref-tagged element
183
+ * list the LLM sees. Token-economical (role + name + key props only, no DOM
184
+ * markup). Returns elements in tree order with refs e1, e2, …, plus a
185
+ * `refToBackendId` map the caller (renderer) keeps so action tools can resolve
186
+ * a ref back to a backendDOMNodeId.
187
+ *
188
+ * Filtering: drop ignored nodes; keep nodes whose role is interactive (or that
189
+ * are explicitly focusable), and that have a name OR are a value input. Password
190
+ * / sensitive inputs are marked `sensitive` and their value is NEVER included.
191
+ */
192
+ export declare function flattenAxTree(nodes: AXNode[]): {
193
+ elements: BrowserElement[];
194
+ refToBackendId: Record<string, number>;
195
+ };
196
+ /** Default cap for extracted page text (chars) — keeps content within a sane
197
+ * token budget; the agent can scroll + re-read for more. */
198
+ export declare const CONTENT_CHAR_CAP = 12000;
199
+ /** Cap for extracted links/images per call — keeps the result token-bounded;
200
+ * a busy page can have thousands of <a>/<img>. The agent narrows the page
201
+ * (navigate/scroll) and re-extracts for more. */
202
+ export declare const EXTRACT_LINK_CAP = 200;
203
+ /**
204
+ * In-page JS (string) that collects deduped, absolute link + image URLs and
205
+ * returns them as a JSON-serializable object. Run via CDP Runtime.evaluate with
206
+ * returnByValue. Kept here (not in the renderer) so the extraction contract is
207
+ * defined alongside its types and is unit-testable. `cap` bounds each list;
208
+ * `truncated` is set when either hit the cap.
209
+ *
210
+ * - Links: <a href> with a real navigable href (skips javascript:/empty/#-only).
211
+ * - Images: <img src> (skips empty/data: noise beyond a length sanity bound is
212
+ * left to the page; data URLs are dropped — they're inline, not fetchable URLs).
213
+ * - URLs are absolute (the DOM's .href/.src already resolve against the base).
214
+ */
215
+ export declare function buildExtractLinksScript(cap?: number): string;
216
+ /**
217
+ * Pure: normalize raw extracted page text — collapse runs of whitespace/blank
218
+ * lines, trim, and cap to `cap` chars (marking truncation). The renderer pulls
219
+ * raw innerText via CDP; this keeps the cleanup logic testable and consistent.
220
+ */
221
+ export declare function cleanPageText(raw: string, cap?: number): {
222
+ text: string;
223
+ truncated: boolean;
224
+ };
225
+ /** Render a snapshot's element list as the compact text block shown to the LLM. */
226
+ export declare function renderElementList(elements: BrowserElement[]): string;
@@ -0,0 +1,163 @@
1
+ /**
2
+ * BrowserBridge — driver-agnostic contract between the browser tools (core)
3
+ * and whatever drives the actual browser (renderer's webview via CDP).
4
+ *
5
+ * Spec: docs/superpowers/specs/2026-06-16-browser-automation-mvp.md
6
+ *
7
+ * The core tools only know this interface. The renderer implements it on top
8
+ * of the webview's `webContents.debugger` (CDP): observe via
9
+ * Accessibility.getFullAXTree, act via DOM.getBoxModel → Input.dispatchMouseEvent.
10
+ * Keeping it driver-agnostic means a future implementation (a hidden
11
+ * BrowserWindow for unattended runs, or an external engine) can swap in without
12
+ * touching the tools. Undefined on ToolContext → headless / no panel → tools
13
+ * degrade with a clear error.
14
+ */
15
+ /** Roles we surface as actionable/meaningful to the agent. */
16
+ const INTERACTIVE_ROLES = new Set([
17
+ "button",
18
+ "link",
19
+ "textbox",
20
+ "searchbox",
21
+ "checkbox",
22
+ "radio",
23
+ "combobox",
24
+ "listbox",
25
+ "menuitem",
26
+ "menuitemcheckbox",
27
+ "menuitemradio",
28
+ "tab",
29
+ "switch",
30
+ "slider",
31
+ "option",
32
+ ]);
33
+ /** Input-ish roles whose value we may show (unless sensitive). */
34
+ const VALUE_ROLES = new Set(["textbox", "searchbox", "combobox", "slider"]);
35
+ function propValue(node, name) {
36
+ return node.properties?.find((p) => p.name === name)?.value?.value;
37
+ }
38
+ /**
39
+ * Pure: flatten a CDP accessibility tree into the compact, ref-tagged element
40
+ * list the LLM sees. Token-economical (role + name + key props only, no DOM
41
+ * markup). Returns elements in tree order with refs e1, e2, …, plus a
42
+ * `refToBackendId` map the caller (renderer) keeps so action tools can resolve
43
+ * a ref back to a backendDOMNodeId.
44
+ *
45
+ * Filtering: drop ignored nodes; keep nodes whose role is interactive (or that
46
+ * are explicitly focusable), and that have a name OR are a value input. Password
47
+ * / sensitive inputs are marked `sensitive` and their value is NEVER included.
48
+ */
49
+ export function flattenAxTree(nodes) {
50
+ const elements = [];
51
+ const refToBackendId = {};
52
+ let counter = 0;
53
+ for (const node of nodes) {
54
+ if (node.ignored)
55
+ continue;
56
+ const role = node.role?.value;
57
+ if (!role)
58
+ continue;
59
+ const focusable = propValue(node, "focusable") === true;
60
+ if (!INTERACTIVE_ROLES.has(role) && !focusable)
61
+ continue;
62
+ const name = (node.name?.value ?? "").trim();
63
+ const isValueRole = VALUE_ROLES.has(role);
64
+ // Skip nameless non-input noise (e.g. a focusable wrapper with no label).
65
+ if (!name && !isValueRole)
66
+ continue;
67
+ // backendDOMNodeId is required to act on the element later; without it the
68
+ // element isn't actionable, so don't surface it.
69
+ if (node.backendDOMNodeId === undefined)
70
+ continue;
71
+ const sensitive = propValue(node, "protected") === true || // ARIA "protected" → password-like
72
+ role === "textbox" && /password|密码/i.test(name);
73
+ counter += 1;
74
+ const ref = `e${counter}`;
75
+ refToBackendId[ref] = node.backendDOMNodeId;
76
+ const el = { ref, role, name };
77
+ if (sensitive) {
78
+ el.sensitive = true; // value intentionally omitted
79
+ }
80
+ else if (isValueRole) {
81
+ const v = node.value?.value?.toString();
82
+ if (v)
83
+ el.value = v;
84
+ }
85
+ elements.push(el);
86
+ }
87
+ return { elements, refToBackendId };
88
+ }
89
+ /** Default cap for extracted page text (chars) — keeps content within a sane
90
+ * token budget; the agent can scroll + re-read for more. */
91
+ export const CONTENT_CHAR_CAP = 12_000;
92
+ /** Cap for extracted links/images per call — keeps the result token-bounded;
93
+ * a busy page can have thousands of <a>/<img>. The agent narrows the page
94
+ * (navigate/scroll) and re-extracts for more. */
95
+ export const EXTRACT_LINK_CAP = 200;
96
+ /**
97
+ * In-page JS (string) that collects deduped, absolute link + image URLs and
98
+ * returns them as a JSON-serializable object. Run via CDP Runtime.evaluate with
99
+ * returnByValue. Kept here (not in the renderer) so the extraction contract is
100
+ * defined alongside its types and is unit-testable. `cap` bounds each list;
101
+ * `truncated` is set when either hit the cap.
102
+ *
103
+ * - Links: <a href> with a real navigable href (skips javascript:/empty/#-only).
104
+ * - Images: <img src> (skips empty/data: noise beyond a length sanity bound is
105
+ * left to the page; data URLs are dropped — they're inline, not fetchable URLs).
106
+ * - URLs are absolute (the DOM's .href/.src already resolve against the base).
107
+ */
108
+ export function buildExtractLinksScript(cap = EXTRACT_LINK_CAP) {
109
+ return `(function(){
110
+ var cap=${cap};
111
+ var links=[],images=[],lt=false,it=false,seenL={},seenI={};
112
+ var as=document.querySelectorAll('a[href]');
113
+ for(var i=0;i<as.length;i++){
114
+ var a=as[i],u=a.href;
115
+ if(!u||u.indexOf('javascript:')===0||u==='#'||u.charAt(u.length-1)==='#'&&u.indexOf('#')===u.length-1)continue;
116
+ if(seenL[u])continue;seenL[u]=1;
117
+ if(links.length>=cap){lt=true;break;}
118
+ links.push({text:(a.textContent||'').trim().slice(0,200),url:u});
119
+ }
120
+ var ims=document.querySelectorAll('img[src]');
121
+ for(var j=0;j<ims.length;j++){
122
+ var im=ims[j],s=im.src;
123
+ if(!s||s.indexOf('data:')===0)continue;
124
+ if(seenI[s])continue;seenI[s]=1;
125
+ if(images.length>=cap){it=true;break;}
126
+ var o={url:s};var alt=(im.getAttribute('alt')||'').trim();if(alt)o.alt=alt.slice(0,200);
127
+ images.push(o);
128
+ }
129
+ return {links:links,images:images,truncated:lt||it};
130
+ })()`;
131
+ }
132
+ /**
133
+ * Pure: normalize raw extracted page text — collapse runs of whitespace/blank
134
+ * lines, trim, and cap to `cap` chars (marking truncation). The renderer pulls
135
+ * raw innerText via CDP; this keeps the cleanup logic testable and consistent.
136
+ */
137
+ export function cleanPageText(raw, cap = CONTENT_CHAR_CAP) {
138
+ const normalized = raw
139
+ .replace(/\r\n?/g, "\n")
140
+ .replace(/[ \t\f\v]+/g, " ")
141
+ .replace(/ *\n */g, "\n")
142
+ .replace(/\n{3,}/g, "\n\n")
143
+ .trim();
144
+ if (normalized.length <= cap)
145
+ return { text: normalized, truncated: false };
146
+ return { text: normalized.slice(0, cap) + "\n…(truncated)", truncated: true };
147
+ }
148
+ /** Render a snapshot's element list as the compact text block shown to the LLM. */
149
+ export function renderElementList(elements) {
150
+ if (elements.length === 0)
151
+ return "(no interactive elements found)";
152
+ return elements
153
+ .map((e) => {
154
+ const namePart = e.name ? ` "${e.name}"` : "";
155
+ const valuePart = e.sensitive
156
+ ? " [sensitive]"
157
+ : e.value
158
+ ? ` =${JSON.stringify(e.value)}`
159
+ : "";
160
+ return `[ref=${e.ref}] ${e.role}${namePart}${valuePart}`;
161
+ })
162
+ .join("\n");
163
+ }
@@ -0,0 +1,49 @@
1
+ /**
2
+ * AgentHeartbeatPinger (B: background-agent visibility) — while background
3
+ * sub-agents are running, emit a periodic `agent_heartbeat` per parent session
4
+ * so the UI knows they're alive even during long LLM-request silence (no
5
+ * tool_use / no text for minutes). Decided over mtime/event-stream liveness
6
+ * because the worker KNOWS an agent is mid-request and can keep reporting it,
7
+ * whereas a quiet event stream looks dead.
8
+ *
9
+ * Liveness model deliberately NOT a separate heartbeat-file here — the file +
10
+ * pid (Heartbeat.ts / isProcessAlive) is for cross-restart interrupted
11
+ * detection (phase C). This pinger is the live "still working" UI signal only.
12
+ *
13
+ * Lifecycle (anti-leak): single timer, stored + cleared; `unref()` so it never
14
+ * pins the process open; `start()` idempotent; self-stops emitting when no
15
+ * agent runs but keeps the (unref'd) tick cheap. Mirrors the proven
16
+ * Heartbeat.ts / chat-session-manager sweeper pattern.
17
+ */
18
+ import type { StreamEvent } from "../../types.js";
19
+ /** Default 30s — user-chosen. Stale threshold downstream is 3× (90s). */
20
+ export declare const DEFAULT_HEARTBEAT_INTERVAL_MS = 30000;
21
+ export interface AgentHeartbeatConfig {
22
+ intervalMs?: number;
23
+ /** Sink for each heartbeat event (server forwards to the client). */
24
+ publish: (sessionId: string, event: StreamEvent) => void;
25
+ /** Injectable clock for tests. */
26
+ now?: () => number;
27
+ }
28
+ export declare class AgentHeartbeatPinger {
29
+ private readonly intervalMs;
30
+ private readonly publish;
31
+ private readonly now;
32
+ private timer;
33
+ constructor(config: AgentHeartbeatConfig);
34
+ /** Begin periodic heartbeats. Idempotent — a second call is a no-op. */
35
+ start(): void;
36
+ stop(): void;
37
+ /** One heartbeat cycle: group running agents by session and publish. */
38
+ private tick;
39
+ }
40
+ /**
41
+ * Process-wide pinger that publishes to the agentNotificationBus (the same
42
+ * channel background-agent completions use → the protocol server forwards each
43
+ * event to the client). `ensureRunning()` is called when an agent backgrounds;
44
+ * the pinger self-stops once no agent is running, so a fresh handoff re-arms it.
45
+ */
46
+ export declare const agentHeartbeatPinger: AgentHeartbeatPinger;
47
+ /** Start the shared pinger if not already ticking (idempotent). Call when an
48
+ * agent enters the background. */
49
+ export declare function ensureAgentHeartbeat(): void;
@@ -0,0 +1,89 @@
1
+ /**
2
+ * AgentHeartbeatPinger (B: background-agent visibility) — while background
3
+ * sub-agents are running, emit a periodic `agent_heartbeat` per parent session
4
+ * so the UI knows they're alive even during long LLM-request silence (no
5
+ * tool_use / no text for minutes). Decided over mtime/event-stream liveness
6
+ * because the worker KNOWS an agent is mid-request and can keep reporting it,
7
+ * whereas a quiet event stream looks dead.
8
+ *
9
+ * Liveness model deliberately NOT a separate heartbeat-file here — the file +
10
+ * pid (Heartbeat.ts / isProcessAlive) is for cross-restart interrupted
11
+ * detection (phase C). This pinger is the live "still working" UI signal only.
12
+ *
13
+ * Lifecycle (anti-leak): single timer, stored + cleared; `unref()` so it never
14
+ * pins the process open; `start()` idempotent; self-stops emitting when no
15
+ * agent runs but keeps the (unref'd) tick cheap. Mirrors the proven
16
+ * Heartbeat.ts / chat-session-manager sweeper pattern.
17
+ */
18
+ import { asyncAgentRegistry } from "./agent-registry.js";
19
+ import { agentNotificationBus } from "./agent-notifications.js";
20
+ /** Default 30s — user-chosen. Stale threshold downstream is 3× (90s). */
21
+ export const DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000;
22
+ export class AgentHeartbeatPinger {
23
+ intervalMs;
24
+ publish;
25
+ now;
26
+ timer = null;
27
+ constructor(config) {
28
+ this.intervalMs = config.intervalMs ?? DEFAULT_HEARTBEAT_INTERVAL_MS;
29
+ this.publish = config.publish;
30
+ this.now = config.now ?? Date.now;
31
+ }
32
+ /** Begin periodic heartbeats. Idempotent — a second call is a no-op. */
33
+ start() {
34
+ if (this.timer)
35
+ return;
36
+ this.timer = setInterval(() => this.tick(), this.intervalMs);
37
+ // Never keep the process alive just for heartbeats.
38
+ if (typeof this.timer === "object" && "unref" in this.timer) {
39
+ this.timer.unref();
40
+ }
41
+ }
42
+ stop() {
43
+ if (this.timer) {
44
+ clearInterval(this.timer);
45
+ this.timer = null;
46
+ }
47
+ }
48
+ /** One heartbeat cycle: group running agents by session and publish. */
49
+ tick() {
50
+ const running = asyncAgentRegistry.getSnapshot().filter((e) => e.status === "running");
51
+ if (running.length === 0) {
52
+ // Nothing left to ping — self-stop so the timer doesn't tick forever
53
+ // after the last background agent finishes. start() re-arms on the next
54
+ // handoff. (Idempotent stop.)
55
+ this.stop();
56
+ return;
57
+ }
58
+ const bySession = new Map();
59
+ for (const e of running) {
60
+ // Background agents always carry their spawning sessionId; skip any
61
+ // legacy/ad-hoc entry without one (can't address a heartbeat to nobody).
62
+ if (!e.sessionId)
63
+ continue;
64
+ const list = bySession.get(e.sessionId);
65
+ if (list)
66
+ list.push(e.agentId);
67
+ else
68
+ bySession.set(e.sessionId, [e.agentId]);
69
+ }
70
+ const ts = this.now();
71
+ for (const [sessionId, agentIds] of bySession) {
72
+ this.publish(sessionId, { type: "agent_heartbeat", agentIds, ts });
73
+ }
74
+ }
75
+ }
76
+ /**
77
+ * Process-wide pinger that publishes to the agentNotificationBus (the same
78
+ * channel background-agent completions use → the protocol server forwards each
79
+ * event to the client). `ensureRunning()` is called when an agent backgrounds;
80
+ * the pinger self-stops once no agent is running, so a fresh handoff re-arms it.
81
+ */
82
+ export const agentHeartbeatPinger = new AgentHeartbeatPinger({
83
+ publish: (sessionId, event) => agentNotificationBus.publish(sessionId, event),
84
+ });
85
+ /** Start the shared pinger if not already ticking (idempotent). Call when an
86
+ * agent enters the background. */
87
+ export function ensureAgentHeartbeat() {
88
+ agentHeartbeatPinger.start();
89
+ }
@@ -1,4 +1,4 @@
1
- import type { BackgroundAgentCompletedEvent } from "../../types.js";
1
+ import type { BackgroundAgentCompletedEvent, StreamEvent } from "../../types.js";
2
2
  /**
3
3
  * Background-agent completion notification queue.
4
4
  *
@@ -30,8 +30,17 @@ export type NotificationItem = {
30
30
  name?: string;
31
31
  description: string;
32
32
  status: "completed" | "failed";
33
+ /** What kind of background work this was (lets UIs localize the toast). */
34
+ workKind?: "agent" | "shell" | "video" | "cc";
35
+ /** For workKind === "shell": the command that ran. */
36
+ command?: string;
33
37
  /** Final assistant text (completed only). */
34
38
  finalText?: string;
39
+ /** For workKind === "cc": the external claude session id this drove, so the
40
+ * result is recoverable from ~/.claude/projects/.../<ccSessionId>.jsonl even
41
+ * if this notification is lost, and the user sees a real session id (not just
42
+ * an opaque background jobId). */
43
+ ccSessionId?: string;
35
44
  /** Error message (failed only). */
36
45
  error?: string;
37
46
  enqueuedAt: number;
@@ -53,10 +62,10 @@ declare class NotificationQueue {
53
62
  private notify;
54
63
  }
55
64
  export declare const notificationQueue: NotificationQueue;
56
- type BusHandler = (sessionId: string, event: BackgroundAgentCompletedEvent) => void;
65
+ type BusHandler = (sessionId: string, event: StreamEvent) => void;
57
66
  declare class AgentNotificationBus {
58
67
  private handlers;
59
- publish(sessionId: string, event: BackgroundAgentCompletedEvent): void;
68
+ publish(sessionId: string, event: StreamEvent): void;
60
69
  subscribe(handler: BusHandler): () => void;
61
70
  }
62
71
  export declare const agentNotificationBus: AgentNotificationBus;