@vellumai/assistant 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (535) hide show
  1. package/ARCHITECTURE.md +32 -49
  2. package/Dockerfile +1 -0
  3. package/README.md +1 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +9 -3
  5. package/bun.lock +26 -26
  6. package/docs/architecture/security.md +20 -0
  7. package/docs/plugins.md +7 -9
  8. package/knip.json +1 -0
  9. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +39 -1
  11. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  12. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  13. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  15. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  16. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  17. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +9 -0
  19. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  20. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  21. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  22. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  23. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  24. package/openapi.yaml +565 -12
  25. package/package.json +6 -3
  26. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  27. package/src/__tests__/app-bundler.test.ts +170 -1
  28. package/src/__tests__/app-control-flow.test.ts +374 -0
  29. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  30. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  31. package/src/__tests__/app-executors.test.ts +30 -43
  32. package/src/__tests__/approval-routes-http.test.ts +23 -6
  33. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  34. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  35. package/src/__tests__/assistant-event-hub.test.ts +109 -2
  36. package/src/__tests__/assistant-event.test.ts +10 -0
  37. package/src/__tests__/assistant-events-sse-hardening.test.ts +7 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +11 -7
  39. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  40. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  41. package/src/__tests__/btw-routes.test.ts +13 -4
  42. package/src/__tests__/call-controller.test.ts +49 -1
  43. package/src/__tests__/call-domain.test.ts +0 -2
  44. package/src/__tests__/call-routes-http.test.ts +0 -2
  45. package/src/__tests__/channel-readiness-service.test.ts +59 -1
  46. package/src/__tests__/checker.test.ts +3 -4
  47. package/src/__tests__/config-loader-backfill.test.ts +90 -155
  48. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  49. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  50. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  51. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +2 -2
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  54. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  55. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  56. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  57. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  58. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  59. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  60. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  61. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  62. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  63. package/src/__tests__/conversation-surfaces-app-control.test.ts +317 -0
  64. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  65. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  66. package/src/__tests__/credentials-cli.test.ts +5 -12
  67. package/src/__tests__/cu-unified-flow.test.ts +185 -23
  68. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  69. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  70. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  71. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  72. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  73. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  74. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  75. package/src/__tests__/heartbeat-service.test.ts +718 -1
  76. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  77. package/src/__tests__/host-app-control-proxy.test.ts +602 -0
  78. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  79. package/src/__tests__/host-bash-proxy.test.ts +246 -47
  80. package/src/__tests__/host-bash-routes.test.ts +294 -0
  81. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  82. package/src/__tests__/host-browser-routes.test.ts +39 -13
  83. package/src/__tests__/host-cu-proxy.test.ts +41 -52
  84. package/src/__tests__/host-cu-routes-targeted.test.ts +300 -0
  85. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  86. package/src/__tests__/host-file-proxy-targeted.test.ts +339 -0
  87. package/src/__tests__/host-file-proxy.test.ts +37 -43
  88. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  89. package/src/__tests__/host-file-routes-targeted.test.ts +262 -0
  90. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  91. package/src/__tests__/host-proxy-base.test.ts +312 -0
  92. package/src/__tests__/host-shell-tool.test.ts +22 -4
  93. package/src/__tests__/host-transfer-proxy-targeted.test.ts +583 -0
  94. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  95. package/src/__tests__/host-transfer-routes-targeted.test.ts +447 -0
  96. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  97. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  98. package/src/__tests__/identity-routes.test.ts +103 -1
  99. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  100. package/src/__tests__/inline-command-runner.test.ts +0 -1
  101. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  102. package/src/__tests__/integration-status.test.ts +85 -5
  103. package/src/__tests__/intent-routing.test.ts +0 -1
  104. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  105. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  106. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  107. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  108. package/src/__tests__/mcp-cli.test.ts +338 -2
  109. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  110. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  111. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  112. package/src/__tests__/oauth-cli.test.ts +0 -2
  113. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  114. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  115. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  116. package/src/__tests__/prechat-onboarding-contract.test.ts +3 -1
  117. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  118. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  119. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  120. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  121. package/src/__tests__/retry-backoff.test.ts +87 -0
  122. package/src/__tests__/runtime-events-sse.test.ts +10 -6
  123. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  124. package/src/__tests__/schedule-retry.test.ts +715 -0
  125. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  126. package/src/__tests__/secret-ingress-http.test.ts +1 -0
  127. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  128. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  129. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  130. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  131. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  132. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  133. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  134. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  135. package/src/__tests__/slack-channel-config.test.ts +9 -14
  136. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  137. package/src/__tests__/system-prompt.test.ts +0 -1
  138. package/src/__tests__/telegram-config.test.ts +0 -1
  139. package/src/__tests__/test-preload.ts +8 -0
  140. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  141. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  142. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  143. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  144. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  145. package/src/__tests__/tool-executor.test.ts +0 -1
  146. package/src/__tests__/twilio-config.test.ts +3 -16
  147. package/src/__tests__/twilio-routes.test.ts +3 -5
  148. package/src/__tests__/twilio-validation.test.ts +93 -0
  149. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  150. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  151. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  152. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  153. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  154. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  155. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  156. package/src/backup/__tests__/paths.test.ts +0 -22
  157. package/src/backup/__tests__/restore.test.ts +51 -151
  158. package/src/backup/paths.ts +2 -18
  159. package/src/backup/restore.ts +107 -231
  160. package/src/bundler/app-bundler.ts +51 -3
  161. package/src/calls/relay-server.ts +4 -44
  162. package/src/calls/twilio-config.ts +2 -17
  163. package/src/calls/twilio-rest.ts +33 -105
  164. package/src/calls/twilio-routes.ts +11 -12
  165. package/src/channels/types.ts +8 -7
  166. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  167. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  168. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  169. package/src/cli/commands/__tests__/webhooks.test.ts +0 -1
  170. package/src/cli/commands/backup.ts +6 -331
  171. package/src/cli/commands/clients.ts +36 -37
  172. package/src/cli/commands/contacts.ts +73 -0
  173. package/src/cli/commands/conversations.ts +2 -5
  174. package/src/cli/commands/credentials.ts +15 -7
  175. package/src/cli/commands/domain.ts +66 -15
  176. package/src/cli/commands/gateway.ts +183 -0
  177. package/src/cli/commands/keys.ts +9 -6
  178. package/src/cli/commands/mcp.ts +116 -156
  179. package/src/cli/commands/memory-v2.ts +296 -1
  180. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  181. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -2
  182. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -2
  183. package/src/cli/commands/platform/__tests__/status.test.ts +13 -15
  184. package/src/cli/commands/platform/disconnect.ts +5 -4
  185. package/src/cli/commands/platform/index.ts +0 -18
  186. package/src/cli/lib/daemon-credential-client.ts +110 -28
  187. package/src/cli/program.ts +2 -0
  188. package/src/config/assistant-feature-flags.ts +67 -10
  189. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  190. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  191. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  192. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  193. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  194. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  195. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  196. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  197. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  198. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  199. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  200. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  201. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  202. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  203. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  204. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  205. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  206. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  207. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  208. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  209. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  210. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  211. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  212. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  213. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  214. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  215. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +19 -4
  216. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  217. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  218. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  219. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  220. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  221. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  222. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  223. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  224. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  225. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  226. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  227. package/src/config/bundled-tool-registry.ts +21 -0
  228. package/src/config/env-registry.ts +0 -2
  229. package/src/config/env.ts +19 -12
  230. package/src/config/feature-flag-registry.json +21 -133
  231. package/src/config/loader.ts +73 -99
  232. package/src/config/sanitize-for-transfer.ts +2 -0
  233. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  234. package/src/config/schemas/__tests__/memory-v2.test.ts +7 -4
  235. package/src/config/schemas/calls.ts +0 -9
  236. package/src/config/schemas/heartbeat.ts +63 -0
  237. package/src/config/schemas/ingress.ts +10 -6
  238. package/src/config/schemas/llm.ts +5 -10
  239. package/src/config/schemas/memory-lifecycle.ts +77 -24
  240. package/src/config/schemas/memory-v2.ts +48 -4
  241. package/src/config/schemas/platform.ts +6 -0
  242. package/src/config/schemas/services.ts +1 -15
  243. package/src/config/schemas/skills.ts +0 -6
  244. package/src/config/seed-inference-profiles.ts +1 -1
  245. package/src/contacts/contact-store.ts +0 -30
  246. package/src/contacts/contacts-write.ts +0 -27
  247. package/src/context/window-manager.ts +1 -2
  248. package/src/credential-execution/feature-gates.ts +10 -10
  249. package/src/credential-execution/process-manager.ts +12 -41
  250. package/src/daemon/__tests__/conversation-tool-setup.test.ts +126 -5
  251. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  252. package/src/daemon/config-watcher.ts +4 -3
  253. package/src/daemon/conversation-agent-loop-handlers.ts +21 -3
  254. package/src/daemon/conversation-agent-loop.ts +32 -28
  255. package/src/daemon/conversation-lifecycle.ts +8 -1
  256. package/src/daemon/conversation-process.ts +16 -11
  257. package/src/daemon/conversation-runtime-assembly.ts +2 -2
  258. package/src/daemon/conversation-surfaces.ts +125 -4
  259. package/src/daemon/conversation-tool-setup.ts +16 -55
  260. package/src/daemon/conversation.ts +21 -2
  261. package/src/daemon/doordash-steps.ts +1 -1
  262. package/src/daemon/handlers/shared.ts +4 -1
  263. package/src/daemon/host-app-control-proxy.ts +293 -0
  264. package/src/daemon/host-bash-proxy.ts +84 -74
  265. package/src/daemon/host-browser-proxy.ts +67 -82
  266. package/src/daemon/host-cu-proxy.ts +81 -86
  267. package/src/daemon/host-file-proxy.ts +93 -69
  268. package/src/daemon/host-proxy-base.ts +294 -0
  269. package/src/daemon/host-proxy-preactivation.ts +82 -0
  270. package/src/daemon/host-transfer-proxy.ts +247 -129
  271. package/src/daemon/lifecycle.ts +115 -117
  272. package/src/daemon/message-protocol.ts +3 -8
  273. package/src/daemon/message-types/contacts.ts +23 -1
  274. package/src/daemon/message-types/conversations.ts +11 -8
  275. package/src/daemon/message-types/host-app-control.ts +150 -0
  276. package/src/daemon/message-types/host-bash.ts +4 -0
  277. package/src/daemon/message-types/host-cu.ts +2 -0
  278. package/src/daemon/message-types/host-file.ts +4 -0
  279. package/src/daemon/message-types/host-transfer.ts +3 -0
  280. package/src/daemon/message-types/schedules.ts +8 -3
  281. package/src/daemon/message-types/skills.ts +2 -2
  282. package/src/daemon/process-message.ts +18 -1
  283. package/src/daemon/shutdown-handlers.ts +0 -3
  284. package/src/daemon/tool-setup-types.ts +51 -0
  285. package/src/daemon/tool-side-effects.ts +1 -1
  286. package/src/events/tool-audit-listener.ts +2 -1
  287. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +15 -7
  288. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +216 -0
  289. package/src/heartbeat/heartbeat-run-store.ts +236 -0
  290. package/src/heartbeat/heartbeat-service.ts +280 -49
  291. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  292. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  293. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  294. package/src/home/post-connect-feed.ts +68 -0
  295. package/src/home/relationship-state-writer.ts +17 -92
  296. package/src/home/suggested-prompts.ts +46 -10
  297. package/src/inbound/public-ingress-urls.ts +32 -34
  298. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  299. package/src/ipc/assistant-server.ts +14 -1
  300. package/src/ipc/cli-client.ts +32 -1
  301. package/src/live-voice/live-voice-metrics.ts +10 -10
  302. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  303. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  304. package/src/mcp/mcp-auth-state.ts +133 -0
  305. package/src/mcp/mcp-oauth-provider.ts +19 -0
  306. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  307. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  308. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  309. package/src/memory/anisotropy.test.ts +247 -0
  310. package/src/memory/anisotropy.ts +443 -0
  311. package/src/memory/auto-analysis-constants.ts +17 -0
  312. package/src/memory/auto-analysis-guard.ts +5 -15
  313. package/src/memory/canonical-guardian-store.ts +7 -7
  314. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  315. package/src/memory/context-search/agent-protocol.ts +6 -6
  316. package/src/memory/context-search/agent-runner.ts +32 -7
  317. package/src/memory/context-search/sources/memory-v2.ts +17 -5
  318. package/src/memory/conversation-crud.ts +1 -1
  319. package/src/memory/conversation-key-store.ts +2 -15
  320. package/src/memory/db-init.ts +4 -0
  321. package/src/memory/embedding-backend.ts +9 -21
  322. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +49 -4
  323. package/src/memory/graph/conversation-graph-memory.ts +1 -24
  324. package/src/memory/graph/graph-search.ts +8 -0
  325. package/src/memory/graph/retriever.ts +28 -0
  326. package/src/memory/graph/tools.ts +1 -1
  327. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  328. package/src/memory/jobs/embed-concept-page.ts +28 -2
  329. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  330. package/src/memory/jobs-store.ts +66 -22
  331. package/src/memory/jobs-worker.ts +112 -63
  332. package/src/memory/memory-v2-activation-log-store.ts +1 -1
  333. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  334. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  335. package/src/memory/migrations/index.ts +5 -0
  336. package/src/memory/migrations/registry.ts +8 -0
  337. package/src/memory/pkb/pkb-search.ts +7 -0
  338. package/src/memory/qdrant-client.ts +50 -20
  339. package/src/memory/schema/infrastructure.ts +15 -0
  340. package/src/memory/search/semantic.ts +7 -0
  341. package/src/memory/sparse-tokenize.ts +49 -0
  342. package/src/memory/v2/__tests__/activation.test.ts +77 -95
  343. package/src/memory/v2/__tests__/injection.test.ts +43 -21
  344. package/src/memory/v2/__tests__/sim.test.ts +166 -6
  345. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  346. package/src/memory/v2/__tests__/static-context.test.ts +0 -1
  347. package/src/memory/v2/activation.ts +69 -88
  348. package/src/memory/v2/consolidation-job.ts +3 -5
  349. package/src/memory/v2/constants.ts +7 -0
  350. package/src/memory/v2/injection.ts +86 -53
  351. package/src/memory/v2/prompts/consolidation.ts +312 -91
  352. package/src/memory/v2/qdrant.ts +99 -1
  353. package/src/memory/v2/sim.ts +126 -16
  354. package/src/memory/v2/skill-qdrant.ts +12 -3
  355. package/src/memory/v2/skill-store.ts +16 -1
  356. package/src/memory/v2/sparse-bm25.ts +245 -0
  357. package/src/memory/v2/static-context.ts +6 -5
  358. package/src/messaging/providers/gmail/types.ts +0 -49
  359. package/src/messaging/providers/slack/adapter.ts +1 -31
  360. package/src/messaging/providers/slack/types.ts +0 -32
  361. package/src/notifications/README.md +10 -10
  362. package/src/notifications/broadcaster.ts +1 -1
  363. package/src/notifications/guardian-question-mode.ts +5 -5
  364. package/src/oauth/connect-orchestrator.ts +4 -0
  365. package/src/oauth/credential-token-resolver.ts +1 -3
  366. package/src/oauth/manual-token-connection.ts +0 -4
  367. package/src/outbound-proxy/index.ts +1 -37
  368. package/src/outbound-proxy/logging.ts +1 -1
  369. package/src/outbound-proxy/policy.ts +6 -5
  370. package/src/outbound-proxy/router.ts +2 -1
  371. package/src/permissions/approval-policy.test.ts +6 -275
  372. package/src/permissions/approval-policy.ts +0 -51
  373. package/src/permissions/checker.test.ts +0 -1
  374. package/src/permissions/checker.ts +3 -17
  375. package/src/permissions/gateway-threshold-reader.ts +2 -0
  376. package/src/permissions/prompter.ts +34 -1
  377. package/src/permissions/secret-prompter.ts +6 -2
  378. package/src/prompts/bootstrap-cleanup.ts +27 -0
  379. package/src/prompts/system-prompt.ts +3 -18
  380. package/src/prompts/templates/SOUL.md +13 -1
  381. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  382. package/src/runtime/assistant-event-hub.ts +118 -96
  383. package/src/runtime/assistant-event.ts +1 -0
  384. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  385. package/src/runtime/auth/middleware.ts +0 -96
  386. package/src/runtime/auth/route-policy.ts +19 -0
  387. package/src/runtime/btw-sidechain.ts +2 -3
  388. package/src/runtime/channel-invite-transport.ts +2 -48
  389. package/src/runtime/channel-invite-transports/email.ts +1 -1
  390. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  391. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  392. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  393. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  394. package/src/runtime/channel-invite-types.ts +54 -0
  395. package/src/runtime/channel-readiness-service.ts +32 -13
  396. package/src/runtime/http-server.ts +3 -329
  397. package/src/runtime/http-types.ts +0 -5
  398. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  399. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  400. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  401. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  402. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  403. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  404. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  405. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  406. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  407. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  408. package/src/runtime/migrations/migration-transport.ts +7 -7
  409. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  410. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  411. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  412. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  413. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  414. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  415. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  416. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  417. package/src/runtime/pending-interactions.ts +35 -9
  418. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  419. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -0
  420. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  421. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  422. package/src/runtime/routes/approval-interception-types.ts +13 -0
  423. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  424. package/src/runtime/routes/backup-routes.ts +15 -38
  425. package/src/runtime/routes/btw-routes.ts +14 -37
  426. package/src/runtime/routes/client-routes.ts +1 -0
  427. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  428. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  429. package/src/runtime/routes/conversation-routes.ts +30 -13
  430. package/src/runtime/routes/document-pdf-renderer.ts +165 -0
  431. package/src/runtime/routes/documents-routes.ts +30 -0
  432. package/src/runtime/routes/errors.ts +19 -4
  433. package/src/runtime/routes/events-routes.ts +12 -6
  434. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  435. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  436. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  437. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  438. package/src/runtime/routes/host-bash-routes.ts +36 -6
  439. package/src/runtime/routes/host-browser-routes.ts +108 -13
  440. package/src/runtime/routes/host-cu-routes.ts +44 -14
  441. package/src/runtime/routes/host-file-routes.ts +33 -10
  442. package/src/runtime/routes/host-transfer-routes.ts +64 -24
  443. package/src/runtime/routes/http-adapter.ts +1 -0
  444. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  445. package/src/runtime/routes/identity-routes.ts +15 -43
  446. package/src/runtime/routes/inbound-message-handler.ts +1 -9
  447. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  448. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  449. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  450. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  451. package/src/runtime/routes/index.ts +8 -0
  452. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  453. package/src/runtime/routes/memory-item-routes.ts +10 -12
  454. package/src/runtime/routes/memory-v2-routes.ts +441 -1
  455. package/src/runtime/routes/migration-routes.ts +96 -0
  456. package/src/runtime/routes/schedule-routes.ts +7 -0
  457. package/src/runtime/verification-templates.ts +4 -7
  458. package/src/schedule/integration-status.ts +66 -2
  459. package/src/schedule/recurrence-engine.ts +4 -1
  460. package/src/schedule/retry-backoff.ts +18 -0
  461. package/src/schedule/retry-policy.ts +82 -0
  462. package/src/schedule/schedule-recovery.ts +64 -0
  463. package/src/schedule/schedule-store.ts +106 -2
  464. package/src/schedule/scheduler-types.ts +25 -0
  465. package/src/schedule/scheduler.ts +63 -38
  466. package/src/security/oauth-callback-registry.ts +8 -0
  467. package/src/sequence/analytics.ts +5 -5
  468. package/src/sequence/engine.ts +1 -1
  469. package/src/skills/catalog-files.ts +2 -8
  470. package/src/skills/include-graph.ts +5 -5
  471. package/src/skills/remote-skill-policy.ts +5 -5
  472. package/src/skills/skill-file-provider.ts +1 -1
  473. package/src/skills/skill-file-types.ts +13 -0
  474. package/src/skills/skillssh-audit-types.ts +28 -0
  475. package/src/skills/skillssh-registry.ts +8 -21
  476. package/src/telemetry/types.ts +2 -0
  477. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  478. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  479. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  480. package/src/tools/apps/executors.ts +56 -69
  481. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  482. package/src/tools/browser/browser-execution.ts +2 -2
  483. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  484. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  485. package/src/tools/browser/cdp-client/factory.ts +23 -24
  486. package/src/tools/browser/cdp-client/index.ts +1 -14
  487. package/src/tools/computer-use/definitions.ts +42 -20
  488. package/src/tools/executor.ts +2 -0
  489. package/src/tools/host-filesystem/edit.ts +26 -0
  490. package/src/tools/host-filesystem/read.ts +26 -0
  491. package/src/tools/host-filesystem/transfer.ts +31 -1
  492. package/src/tools/host-filesystem/write.ts +26 -0
  493. package/src/tools/host-terminal/host-shell.ts +58 -0
  494. package/src/tools/schedule/create.ts +6 -0
  495. package/src/tools/schedule/list.ts +2 -0
  496. package/src/tools/schedule/update.ts +10 -0
  497. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  498. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  499. package/src/tools/skills/load.ts +0 -32
  500. package/src/tools/tool-approval-handler.ts +1 -5
  501. package/src/tools/types.ts +4 -0
  502. package/src/usage/pricing.ts +1 -1
  503. package/src/workspace/hatched-date.ts +86 -0
  504. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  505. package/src/workspace/migrations/006-services-config.ts +8 -5
  506. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  507. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  508. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  509. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  510. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  511. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  512. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  513. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  514. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  515. package/src/workspace/migrations/AGENTS.md +1 -1
  516. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  517. package/src/workspace/migrations/utils.ts +21 -0
  518. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  519. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  520. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  521. package/src/__tests__/twilio-rest.test.ts +0 -34
  522. package/src/backup/__tests__/backup-key.test.ts +0 -152
  523. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  524. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  525. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  526. package/src/backup/backup-key.ts +0 -137
  527. package/src/backup/backup-worker.ts +0 -472
  528. package/src/backup/offsite-writer.ts +0 -222
  529. package/src/backup/stream-crypt.ts +0 -263
  530. package/src/daemon/message-types/pairing.ts +0 -58
  531. package/src/outbound-proxy/config.ts +0 -20
  532. package/src/outbound-proxy/health.ts +0 -18
  533. package/src/outbound-proxy/types.ts +0 -150
  534. package/src/runtime/capability-tokens.ts +0 -190
  535. package/src/signals/mcp-reload.ts +0 -18
@@ -18,17 +18,46 @@
18
18
  * first and is authoritative for structural support, so host_bash and
19
19
  * host_file_* are filtered out for chrome-extension regardless of the
20
20
  * hasNoClient flag.
21
+ *
22
+ * Cross-client exception (Phase 1): host_bash is allowed for non-host-proxy
23
+ * interfaces (e.g. "web") when at least one host_bash-capable client is
24
+ * connected via the event hub. host_file_* and host_browser remain filtered
25
+ * regardless (Phase 2).
21
26
  */
22
27
 
23
- import { describe, expect, test } from "bun:test";
28
+ import { beforeEach, describe, expect, mock, test } from "bun:test";
29
+
30
+ // ── Module-level mocks ─────────────────────────────────────────────
31
+
32
+ // Control how many host_bash-capable clients the hub reports.
33
+ let mockHostBashClientCount = 0;
34
+
35
+ mock.module("../../runtime/assistant-event-hub.js", () => ({
36
+ assistantEventHub: {
37
+ listClientsByCapability: (cap: string) => {
38
+ if (cap === "host_bash") {
39
+ return Array.from({ length: mockHostBashClientCount }, (_, i) => ({
40
+ clientId: `mock-client-${i}`,
41
+ capabilities: ["host_bash"],
42
+ }));
43
+ }
44
+ return [];
45
+ },
46
+ },
47
+ broadcastMessage: () => {},
48
+ }));
24
49
 
25
- import type { SkillProjectionCache } from "../conversation-skill-tools.js";
26
- import {
50
+ // Dynamic imports after mock.module calls so the stubs take effect
51
+ // before the modules under test are loaded.
52
+ const {
27
53
  HOST_TOOL_NAMES,
28
54
  HOST_TOOL_TO_CAPABILITY,
29
55
  isToolActiveForContext,
30
- type SkillProjectionContext,
31
- } from "../conversation-tool-setup.js";
56
+ } = await import("../conversation-tool-setup.js");
57
+ type SkillProjectionContext =
58
+ import("../conversation-tool-setup.js").SkillProjectionContext;
59
+ type SkillProjectionCache =
60
+ import("../conversation-skill-tools.js").SkillProjectionCache;
32
61
 
33
62
  function makeCtx(
34
63
  overrides: Partial<SkillProjectionContext> = {},
@@ -42,6 +71,10 @@ function makeCtx(
42
71
  };
43
72
  }
44
73
 
74
+ beforeEach(() => {
75
+ mockHostBashClientCount = 0;
76
+ });
77
+
45
78
  describe("isToolActiveForContext — host tool capability gating", () => {
46
79
  // macOS transport: SSE-based interactive approval required.
47
80
  test("host_bash is active for macOS with a connected client", () => {
@@ -176,6 +209,94 @@ describe("isToolActiveForContext — host tool capability gating", () => {
176
209
  });
177
210
  });
178
211
 
212
+ describe("isToolActiveForContext — cross-client exception (Phase 1: host_bash)", () => {
213
+ test("host_bash is active for web transport when a host_bash-capable client is connected", () => {
214
+ // Cross-client path: a web turn should see host_bash when a macOS client
215
+ // with host_bash capability is connected via the event hub.
216
+ mockHostBashClientCount = 1;
217
+ expect(
218
+ isToolActiveForContext(
219
+ "host_bash",
220
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
221
+ ),
222
+ ).toBe(true);
223
+ });
224
+
225
+ test("host_bash is NOT active for web transport when no capable client is connected", () => {
226
+ // No cross-client fallback: hub has no host_bash-capable subscribers.
227
+ mockHostBashClientCount = 0;
228
+ expect(
229
+ isToolActiveForContext(
230
+ "host_bash",
231
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
232
+ ),
233
+ ).toBe(false);
234
+ });
235
+
236
+ test("host_file_read is NOT active for web transport even when a capable client is connected (Phase 2 gate)", () => {
237
+ // The cross-client exception is scoped to host_bash only.
238
+ // host_file_* remain filtered for non-host-proxy interfaces regardless
239
+ // of connected clients until Phase 2 lands.
240
+ mockHostBashClientCount = 1;
241
+ expect(
242
+ isToolActiveForContext(
243
+ "host_file_read",
244
+ makeCtx({ hasNoClient: false, transportInterface: "web" }),
245
+ ),
246
+ ).toBe(false);
247
+ });
248
+
249
+ test("host_bash for macos transport is unaffected by the cross-client exception", () => {
250
+ // macos natively supports host_bash via host proxy — the supportsHostProxy
251
+ // check passes, so the cross-client branch is never reached.
252
+ mockHostBashClientCount = 0;
253
+ expect(
254
+ isToolActiveForContext(
255
+ "host_bash",
256
+ makeCtx({ hasNoClient: false, transportInterface: "macos" }),
257
+ ),
258
+ ).toBe(true);
259
+ });
260
+
261
+ test("host_bash for macos with no client is still denied (security invariant unaffected)", () => {
262
+ // Even with a capable client in the hub, the macos SSE path takes
263
+ // precedence — it passes the supportsHostProxy check, bypasses the
264
+ // cross-client branch, and reaches the hasNoClient gate.
265
+ mockHostBashClientCount = 1;
266
+ expect(
267
+ isToolActiveForContext(
268
+ "host_bash",
269
+ makeCtx({ hasNoClient: true, transportInterface: "macos" }),
270
+ ),
271
+ ).toBe(false);
272
+ });
273
+
274
+ test("host_bash is NOT active for chrome-extension even when a capable client is connected", () => {
275
+ // Security boundary: chrome-extension only gets host_browser. The
276
+ // cross-client exception explicitly excludes chrome-extension transport
277
+ // regardless of how many host_bash-capable clients are in the hub.
278
+ mockHostBashClientCount = 1;
279
+ expect(
280
+ isToolActiveForContext(
281
+ "host_bash",
282
+ makeCtx({ hasNoClient: false, transportInterface: "chrome-extension" }),
283
+ ),
284
+ ).toBe(false);
285
+ });
286
+
287
+ test("host_bash is NOT active for web transport when hasNoClient is true (no approval UI)", () => {
288
+ // hasNoClient gate: no interactive approval UI available for this turn.
289
+ // Cross-client exception must not bypass this gate.
290
+ mockHostBashClientCount = 1;
291
+ expect(
292
+ isToolActiveForContext(
293
+ "host_bash",
294
+ makeCtx({ hasNoClient: true, transportInterface: "web" }),
295
+ ),
296
+ ).toBe(false);
297
+ });
298
+ });
299
+
179
300
  describe("HOST_TOOL_NAMES derivation", () => {
180
301
  test("HOST_TOOL_NAMES is derived from HOST_TOOL_TO_CAPABILITY", () => {
181
302
  // Sanity check: every tool in the names set has a capability mapping.
@@ -0,0 +1,45 @@
1
+ import { getMessages, type MessageRow } from "../memory/conversation-crud.js";
2
+ import { cleanupBootstrapFiles } from "../prompts/bootstrap-cleanup.js";
3
+ import { getLogger } from "../util/logger.js";
4
+
5
+ export const BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD = 4;
6
+
7
+ const log = getLogger("bootstrap-turn-cleanup");
8
+
9
+ function isWakeUpGreetingMessage(content: string): boolean {
10
+ return content.toLowerCase().includes("wake up, my friend");
11
+ }
12
+
13
+ export function countBootstrapUserTurns(
14
+ messages: Pick<MessageRow, "role" | "content">[],
15
+ ): number {
16
+ return messages.filter(
17
+ (message) =>
18
+ message.role === "user" && !isWakeUpGreetingMessage(message.content),
19
+ ).length;
20
+ }
21
+
22
+ export function shouldCleanupBootstrapAfterTurn(
23
+ messages: Pick<MessageRow, "role" | "content">[],
24
+ threshold = BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD,
25
+ ): boolean {
26
+ return countBootstrapUserTurns(messages) >= threshold;
27
+ }
28
+
29
+ export function cleanupBootstrapAfterTurnThreshold(
30
+ conversationId: string,
31
+ ): boolean {
32
+ let messages: MessageRow[];
33
+ try {
34
+ messages = getMessages(conversationId);
35
+ } catch (err) {
36
+ log.warn({ err, conversationId }, "Failed to inspect bootstrap turn count");
37
+ return false;
38
+ }
39
+
40
+ if (!shouldCleanupBootstrapAfterTurn(messages)) return false;
41
+
42
+ return cleanupBootstrapFiles(
43
+ `first conversation reached ${BOOTSTRAP_CLEANUP_USER_TURN_THRESHOLD} user turns`,
44
+ );
45
+ }
@@ -21,7 +21,6 @@ import { handleBashSignal } from "../signals/bash.js";
21
21
  import { handleCancelSignal } from "../signals/cancel.js";
22
22
  import { handleConversationUndoSignal } from "../signals/conversation-undo.js";
23
23
  import { handleEmitEventSignal } from "../signals/emit-event.js";
24
- import { handleMcpReloadSignal } from "../signals/mcp-reload.js";
25
24
  import { handleUserMessageSignal } from "../signals/user-message.js";
26
25
  import { DebouncerMap } from "../util/debounce.js";
27
26
  import { getLogger } from "../util/logger.js";
@@ -33,6 +32,7 @@ import {
33
32
  getWorkspaceDir,
34
33
  getWorkspaceSkillsDir,
35
34
  } from "../util/platform.js";
35
+ import { reloadMcpServers } from "./mcp-reload-service.js";
36
36
 
37
37
  const log = getLogger("config-watcher");
38
38
 
@@ -151,7 +151,9 @@ export class ConfigWatcher {
151
151
  const newConfig = getConfig();
152
152
  const newMcpFingerprint = JSON.stringify(newConfig.mcp ?? {});
153
153
  if (newMcpFingerprint !== prevMcpFingerprint) {
154
- handleMcpReloadSignal();
154
+ reloadMcpServers().catch((err: unknown) => {
155
+ log.error({ err }, "MCP reload after config change failed");
156
+ });
155
157
  }
156
158
  }
157
159
  } catch (err) {
@@ -331,7 +333,6 @@ export class ConfigWatcher {
331
333
 
332
334
  const exactSignalHandlers: Record<string, () => void | Promise<void>> = {
333
335
  cancel: handleCancelSignal,
334
- "mcp-reload": handleMcpReloadSignal,
335
336
  "conversation-undo": handleConversationUndoSignal,
336
337
  "emit-event": handleEmitEventSignal,
337
338
  };
@@ -43,6 +43,7 @@ import type {
43
43
  } from "../plugins/types.js";
44
44
  import type { ContentBlock, ImageContent } from "../providers/types.js";
45
45
  import { isContextOverflowError } from "../providers/types.js";
46
+ import { redactSecrets } from "../security/secret-scanner.js";
46
47
  import { ProviderError } from "../util/errors.js";
47
48
  import { getLogger } from "../util/logger.js";
48
49
  import type { DirectiveRequest } from "./assistant-attachments.js";
@@ -804,10 +805,16 @@ export async function handleMessageComplete(
804
805
  ([toolUseId, result]) => ({
805
806
  type: "tool_result",
806
807
  tool_use_id: toolUseId,
807
- content: result.content,
808
+ content: redactSecrets(result.content),
808
809
  is_error: result.isError,
809
810
  ...(result.contentBlocks
810
- ? { contentBlocks: result.contentBlocks }
811
+ ? {
812
+ contentBlocks: result.contentBlocks.map((block) =>
813
+ block.type === "text"
814
+ ? { ...block, text: redactSecrets(block.text) }
815
+ : block,
816
+ ),
817
+ }
811
818
  : {}),
812
819
  }),
813
820
  );
@@ -929,6 +936,17 @@ export async function handleMessageComplete(
929
936
  );
930
937
  }
931
938
  }
939
+ // Redact known-pattern secrets from assistant text blocks before they are
940
+ // written to durable storage. Non-text blocks (images, UI surfaces) pass
941
+ // through unchanged. The live model history retains the original values.
942
+ const contentForPersistence = contentWithSurfaces.map((block) => {
943
+ if (block.type === "text") {
944
+ const tb = block as Extract<ContentBlock, { type: "text" }>;
945
+ return { ...tb, text: redactSecrets(tb.text) };
946
+ }
947
+ return block;
948
+ });
949
+
932
950
  // Route the assistant-message persistence through the `persistence`
933
951
  // pipeline. No `syncToDisk` here — the orchestrator separately invokes
934
952
  // `syncMessageToDisk` on `state.lastAssistantMessageId` after the loop
@@ -941,7 +959,7 @@ export async function handleMessageComplete(
941
959
  op: "add",
942
960
  conversationId: deps.ctx.conversationId,
943
961
  role: "assistant",
944
- content: JSON.stringify(contentWithSurfaces),
962
+ content: JSON.stringify(contentForPersistence),
945
963
  metadata: assistantChannelMetadata,
946
964
  },
947
965
  buildHandlerTurnContext(deps),
@@ -24,7 +24,6 @@ import type {
24
24
  TurnChannelContext,
25
25
  TurnInterfaceContext,
26
26
  } from "../channels/types.js";
27
- import { isAssistantFeatureFlagEnabled } from "../config/assistant-feature-flags.js";
28
27
  import {
29
28
  contextWindowConfigFromEffective,
30
29
  resolveEffectiveContextWindow,
@@ -115,6 +114,7 @@ import type {
115
114
  import type { Provider } from "../providers/types.js";
116
115
  import { resolveActorTrust } from "../runtime/actor-trust-resolver.js";
117
116
  import { DAEMON_INTERNAL_ASSISTANT_ID } from "../runtime/assistant-scope.js";
117
+ import { redactSecrets } from "../security/secret-scanner.js";
118
118
  import { getSubagentManager } from "../subagent/index.js";
119
119
  import type { UsageActor } from "../usage/actors.js";
120
120
  import { getLogger } from "../util/logger.js";
@@ -127,6 +127,7 @@ import {
127
127
  type AssistantAttachmentDraft,
128
128
  cleanAssistantContent,
129
129
  } from "./assistant-attachments.js";
130
+ import { cleanupBootstrapAfterTurnThreshold } from "./bootstrap-turn-cleanup.js";
130
131
  import { resolveOverflowAction } from "./context-overflow-policy.js";
131
132
  import {
132
133
  createInitialReducerState,
@@ -2533,10 +2534,16 @@ export async function runAgentLoopImpl(
2533
2534
  ).map(([toolUseId, result]) => ({
2534
2535
  type: "tool_result",
2535
2536
  tool_use_id: toolUseId,
2536
- content: result.content,
2537
+ content: redactSecrets(result.content),
2537
2538
  is_error: result.isError,
2538
2539
  ...(result.contentBlocks
2539
- ? { contentBlocks: result.contentBlocks }
2540
+ ? {
2541
+ contentBlocks: result.contentBlocks.map((block) =>
2542
+ block.type === "text"
2543
+ ? { ...block, text: redactSecrets(block.text) }
2544
+ : block,
2545
+ ),
2546
+ }
2540
2547
  : {}),
2541
2548
  }));
2542
2549
  const toolResultMetadata = {
@@ -2619,34 +2626,29 @@ export async function runAgentLoopImpl(
2619
2626
 
2620
2627
  // Post-turn tool result truncation: save large results to disk and
2621
2628
  // replace in-context content with a prefix/suffix stub + file pointer.
2622
- if (isAssistantFeatureFlagEnabled("tool-result-truncation", config)) {
2623
- try {
2624
- const conv = getConversation(ctx.conversationId);
2625
- if (conv) {
2626
- const convDir = getResolvedConversationDirPath(
2627
- ctx.conversationId,
2628
- conv.createdAt,
2629
+ try {
2630
+ const conv = getConversation(ctx.conversationId);
2631
+ if (conv) {
2632
+ const convDir = getResolvedConversationDirPath(
2633
+ ctx.conversationId,
2634
+ conv.createdAt,
2635
+ );
2636
+ const { messages: derefMessages, dereferencedCount } =
2637
+ derefToolResultReReads(restoredHistory);
2638
+ const { messages: truncatedMessages, truncatedCount } =
2639
+ postTurnTruncateToolResults(derefMessages, {
2640
+ conversationDir: convDir,
2641
+ });
2642
+ if (truncatedCount > 0 || dereferencedCount > 0) {
2643
+ rlog.info(
2644
+ { truncatedCount, dereferencedCount },
2645
+ "Post-turn tool result truncation applied",
2629
2646
  );
2630
- const { messages: derefMessages, dereferencedCount } =
2631
- derefToolResultReReads(restoredHistory);
2632
- const { messages: truncatedMessages, truncatedCount } =
2633
- postTurnTruncateToolResults(derefMessages, {
2634
- conversationDir: convDir,
2635
- });
2636
- if (truncatedCount > 0 || dereferencedCount > 0) {
2637
- rlog.info(
2638
- { truncatedCount, dereferencedCount },
2639
- "Post-turn tool result truncation applied",
2640
- );
2641
- }
2642
- restoredHistory = truncatedMessages;
2643
2647
  }
2644
- } catch (err) {
2645
- rlog.warn(
2646
- { err },
2647
- "Post-turn tool result truncation failed (non-fatal)",
2648
- );
2648
+ restoredHistory = truncatedMessages;
2649
2649
  }
2650
+ } catch (err) {
2651
+ rlog.warn({ err }, "Post-turn tool result truncation failed (non-fatal)");
2650
2652
  }
2651
2653
 
2652
2654
  // Persist injections in history: runtime-injected context stays on
@@ -2940,6 +2942,8 @@ export async function runAgentLoopImpl(
2940
2942
  }
2941
2943
  } finally {
2942
2944
  if (turnStarted) {
2945
+ cleanupBootstrapAfterTurnThreshold(ctx.conversationId);
2946
+
2943
2947
  ctx.turnCount++;
2944
2948
  const config = getConfig();
2945
2949
  const maxWait = config.workspaceGit?.turnCommitMaxWaitMs ?? 4000;
@@ -240,11 +240,18 @@ export async function loadFromDb(ctx: LoadFromDbContext): Promise<void> {
240
240
  }
241
241
 
242
242
  // Memory remains rehydrated on all rows (existing behavior).
243
+ // Strip any pre-existing wrapper before re-wrapping so historical
244
+ // rows persisted with the wrapper (v2 path before the
245
+ // injectedBlockText contract was unified with v1's unwrapped form)
246
+ // don't render double-wrapped after rehydrate.
243
247
  if (typeof meta.memoryInjectedBlock === "string") {
248
+ const inner = meta.memoryInjectedBlock
249
+ .replace(/^<memory>\n/, "")
250
+ .replace(/\n<\/memory>$/, "");
244
251
  content = [
245
252
  {
246
253
  type: "text" as const,
247
- text: `<memory>\n${meta.memoryInjectedBlock}\n</memory>`,
254
+ text: `<memory>\n${inner}\n</memory>`,
248
255
  },
249
256
  ...content,
250
257
  ];
@@ -14,7 +14,6 @@ import {
14
14
  import {
15
15
  parseChannelId,
16
16
  parseInterfaceId,
17
- supportsHostProxy,
18
17
  type TurnChannelContext,
19
18
  type TurnInterfaceContext,
20
19
  } from "../channels/types.js";
@@ -46,6 +45,7 @@ import {
46
45
  type SlashContext,
47
46
  } from "./conversation-slash.js";
48
47
  import { getModelInfo } from "./handlers/config-model.js";
48
+ import { preactivateHostProxySkills } from "./host-proxy-preactivation.js";
49
49
  import type {
50
50
  ServerMessage,
51
51
  UsageStats,
@@ -425,14 +425,19 @@ async function drainSingleMessage(
425
425
  conversation.applyHostEnvFromTransport(next.transport);
426
426
  }
427
427
 
428
- // Preactivate computer-use skill for interactive desktop turns.
428
+ // Re-preactivate host-proxy skills for interactive desktop turns. The
429
+ // dequeue path reset `preactivatedSkillIds` above, so without these
430
+ // re-adds the relevant skill tools wouldn't be projected to the LLM
431
+ // for queued messages 2+ even though the underlying proxies (HostCuProxy,
432
+ // HostAppControlProxy) are still attached. Mirrors the per-message
433
+ // instantiation block in `conversation-routes.ts` / `process-message.ts`.
429
434
  if (next.isInteractive !== false) {
430
435
  const interfaceCtx =
431
436
  queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
432
- const sourceInterface = interfaceCtx?.userMessageInterface;
433
- if (sourceInterface && supportsHostProxy(sourceInterface)) {
434
- conversation.addPreactivatedSkillId("computer-use");
435
- }
437
+ preactivateHostProxySkills(
438
+ conversation,
439
+ interfaceCtx?.userMessageInterface,
440
+ );
436
441
  }
437
442
 
438
443
  // Snapshot persona context at turn start so later tool turns can't pick up
@@ -862,15 +867,15 @@ async function drainBatch(
862
867
  conversation.applyHostEnvFromTransport(head.transport);
863
868
  }
864
869
 
865
- // Preactivate computer-use skill for interactive desktop turns.
870
+ // Re-preactivate host-proxy skills for interactive desktop turns.
866
871
  // Mirrors the single-message path exactly — sourced from `head`.
867
872
  if (head.isInteractive !== false) {
868
873
  const interfaceCtx =
869
874
  queuedInterfaceCtx ?? conversation.getTurnInterfaceContext();
870
- const sourceInterface = interfaceCtx?.userMessageInterface;
871
- if (sourceInterface && supportsHostProxy(sourceInterface)) {
872
- conversation.addPreactivatedSkillId("computer-use");
873
- }
875
+ preactivateHostProxySkills(
876
+ conversation,
877
+ interfaceCtx?.userMessageInterface,
878
+ );
874
879
  }
875
880
 
876
881
  // Snapshot persona context at turn start so later tool turns can't pick up
@@ -1317,7 +1317,7 @@ export function getSlackCompactionWatermarkForPrefix(
1317
1317
  );
1318
1318
  }
1319
1319
 
1320
- export function assembleSlackChronologicalContext(
1320
+ function assembleSlackChronologicalContext(
1321
1321
  rows: SlackTranscriptInputRow[],
1322
1322
  capabilities: ChannelCapabilities,
1323
1323
  options: {
@@ -1618,7 +1618,7 @@ const RUNTIME_INJECTION_PREFIXES = [
1618
1618
  "<memory_context __injected>",
1619
1619
  "<memory_context>", // backward-compat: strip legacy blocks from pre-__injected history
1620
1620
  // NOTE: `<memory>` blocks (both the dynamic activation block from
1621
- // `prependMemoryV2Block` and the static `memory-v2-static` injector) are
1621
+ // `injectTextBlock` and the static `memory-v2-static` injector) are
1622
1622
  // intentionally NOT stripped — memory injections persist in history so
1623
1623
  // the assistant retains intra-turn memory state. The activation pipeline
1624
1624
  // dedupes via `everInjected`, and compaction handles aggregate growth, so