@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
@@ -8,6 +8,7 @@ export interface HostCuRequest {
8
8
  type: "host_cu_request";
9
9
  requestId: string;
10
10
  conversationId: string;
11
+ targetClientId?: string;
11
12
  toolName: string; // "computer_use_click", "computer_use_type_text", etc.
12
13
  input: Record<string, unknown>;
13
14
  stepNumber: number;
@@ -18,6 +19,7 @@ export interface HostCuCancelRequest {
18
19
  type: "host_cu_cancel";
19
20
  requestId: string;
20
21
  conversationId: string;
22
+ targetClientId?: string;
21
23
  }
22
24
 
23
25
  // --- Domain-level union aliases (consumed by the barrel file) ---
@@ -8,6 +8,7 @@ export interface HostFileReadRequest {
8
8
  type: "host_file_request";
9
9
  requestId: string;
10
10
  conversationId: string;
11
+ targetClientId?: string;
11
12
  operation: "read";
12
13
  path: string;
13
14
  offset?: number;
@@ -18,6 +19,7 @@ export interface HostFileWriteRequest {
18
19
  type: "host_file_request";
19
20
  requestId: string;
20
21
  conversationId: string;
22
+ targetClientId?: string;
21
23
  operation: "write";
22
24
  path: string;
23
25
  content: string;
@@ -27,6 +29,7 @@ export interface HostFileEditRequest {
27
29
  type: "host_file_request";
28
30
  requestId: string;
29
31
  conversationId: string;
32
+ targetClientId?: string;
30
33
  operation: "edit";
31
34
  path: string;
32
35
  old_string: string;
@@ -43,6 +46,7 @@ export interface HostFileCancelRequest {
43
46
  type: "host_file_cancel";
44
47
  requestId: string;
45
48
  conversationId: string;
49
+ targetClientId?: string;
46
50
  }
47
51
 
48
52
  // --- Domain-level union aliases (consumed by the barrel file) ---
@@ -8,6 +8,7 @@ export interface HostTransferToHostRequest {
8
8
  type: "host_transfer_request";
9
9
  requestId: string;
10
10
  conversationId: string;
11
+ targetClientId?: string;
11
12
  direction: "to_host";
12
13
  transferId: string;
13
14
  destPath: string;
@@ -20,6 +21,7 @@ export interface HostTransferToSandboxRequest {
20
21
  type: "host_transfer_request";
21
22
  requestId: string;
22
23
  conversationId: string;
24
+ targetClientId?: string;
23
25
  direction: "to_sandbox";
24
26
  transferId: string;
25
27
  sourcePath: string;
@@ -33,6 +35,7 @@ export interface HostTransferCancelRequest {
33
35
  type: "host_transfer_cancel";
34
36
  requestId: string;
35
37
  conversationId: string;
38
+ targetClientId?: string;
36
39
  }
37
40
 
38
41
  // --- Domain-level union aliases (consumed by the barrel file) ---
@@ -118,10 +118,15 @@ export interface HeartbeatRunsListResponse {
118
118
  type: "heartbeat_runs_list_response";
119
119
  runs: Array<{
120
120
  id: string;
121
- title: string;
121
+ scheduledFor: number;
122
+ startedAt: number | null;
123
+ finishedAt: number | null;
124
+ durationMs: number | null;
125
+ status: string;
126
+ skipReason: string | null;
127
+ error: string | null;
128
+ conversationId: string | null;
122
129
  createdAt: number;
123
- result: string;
124
- summary?: string;
125
130
  }>;
126
131
  }
127
132
 
@@ -1,9 +1,9 @@
1
1
  // Skill management types.
2
2
 
3
- import type { PartnerAudit } from "../../skills/skillssh-registry.js";
3
+ import type { PartnerAudit } from "../../skills/skillssh-audit-types.js";
4
4
 
5
5
  // Re-export so consumers can access the audit types from this module.
6
- export type { PartnerAudit } from "../../skills/skillssh-registry.js";
6
+ export type { PartnerAudit } from "../../skills/skillssh-audit-types.js";
7
7
 
8
8
  // === Client → Server ===
9
9
 
@@ -45,7 +45,9 @@ import {
45
45
  mergeConversationOptions,
46
46
  } from "./conversation-store.js";
47
47
  import type { ConversationCreateOptions } from "./handlers/shared.js";
48
+ import { HostAppControlProxy } from "./host-app-control-proxy.js";
48
49
  import { HostCuProxy } from "./host-cu-proxy.js";
50
+ import { preactivateHostProxySkills } from "./host-proxy-preactivation.js";
49
51
 
50
52
  const log = getLogger("process-message");
51
53
 
@@ -156,10 +158,25 @@ async function prepareConversationForMessage(
156
158
  if (!conversation.isProcessing() || !conversation.hostCuProxy) {
157
159
  conversation.setHostCuProxy(new HostCuProxy());
158
160
  }
159
- conversation.addPreactivatedSkillId("computer-use");
160
161
  } else if (!conversation.isProcessing()) {
161
162
  conversation.setHostCuProxy(undefined);
162
163
  }
164
+ // App-control mirrors CU's per-conversation lifecycle. The proxy attaches
165
+ // unconditionally when the client supports the capability — feature-flag
166
+ // gating is enforced by the skill-projection layer via SKILL.md
167
+ // frontmatter, so an attached proxy is harmless when the flag is off.
168
+ if (supportsHostProxy(resolvedInterface, "host_app_control")) {
169
+ if (!conversation.isProcessing() || !conversation.hostAppControlProxy) {
170
+ conversation.setHostAppControlProxy(
171
+ new HostAppControlProxy(conversationId),
172
+ );
173
+ }
174
+ } else if (!conversation.isProcessing()) {
175
+ conversation.setHostAppControlProxy(undefined);
176
+ }
177
+ // The early `isProcessing()` throw above guarantees the conversation is
178
+ // idle here, so preactivation is unconditional once the proxies are wired.
179
+ preactivateHostProxySkills(conversation, resolvedInterface);
163
180
  conversation.setCommandIntent(options?.commandIntent ?? null);
164
181
  conversation.setTurnChannelContext({
165
182
  userMessageChannel: resolvedChannel,
@@ -1,6 +1,5 @@
1
1
  import * as Sentry from "@sentry/node";
2
2
 
3
- import type { BackupWorkerHandle } from "../backup/backup-worker.js";
4
3
  import type { FilingService } from "../filing/filing-service.js";
5
4
  import type { HeartbeatService } from "../heartbeat/heartbeat-service.js";
6
5
  import type { McpServerManager } from "../mcp/manager.js";
@@ -26,7 +25,6 @@ export interface ShutdownDeps {
26
25
  scheduler: { stop(): void };
27
26
  feedScheduler: { stop(): void } | null;
28
27
  getMemoryWorker: () => { stop(): void } | null;
29
- getBackupWorker: () => BackupWorkerHandle | null;
30
28
  getQdrantManager: () => QdrantManager | null;
31
29
  mcpManager: McpServerManager | null;
32
30
  telemetryReporter: { stop(): Promise<void> } | null;
@@ -123,7 +121,6 @@ export function installShutdownHandlers(deps: ShutdownDeps): void {
123
121
  deps.scheduler.stop();
124
122
  deps.feedScheduler?.stop();
125
123
  deps.getMemoryWorker()?.stop();
126
- deps.getBackupWorker()?.stop();
127
124
 
128
125
  if (deps.mcpManager) {
129
126
  try {
@@ -0,0 +1,51 @@
1
+ /**
2
+ * Types extracted from conversation-tool-setup.ts to break the
3
+ * tool-setup ↔ doordash-steps and tool-setup ↔ tool-side-effects cycles.
4
+ */
5
+
6
+ import type { InterfaceId } from "../channels/types.js";
7
+ import type { CesClient } from "../credential-execution/client.js";
8
+ import type { SurfaceConversationContext } from "./conversation-surfaces.js";
9
+ import type { TrustContext } from "./trust-context.js";
10
+
11
+ /**
12
+ * Subset of Conversation state that the tool executor callback reads at
13
+ * call time (not construction time). These are captured by the
14
+ * returned closure, so they must be live references.
15
+ */
16
+ export interface ToolSetupContext extends SurfaceConversationContext {
17
+ readonly conversationId: string;
18
+ assistantId?: string;
19
+ currentRequestId?: string;
20
+ workingDir: string;
21
+ abortController: AbortController | null;
22
+ /** When set, only tools in this set may execute during the current turn. */
23
+ allowedToolNames?: Set<string>;
24
+ /** Conversation memory policy used to propagate scopeId into ToolContext. */
25
+ memoryPolicy: { scopeId: string };
26
+ /** True when the conversation has no connected client (HTTP-only path). */
27
+ hasNoClient?: boolean;
28
+ /** When true, the conversation is executing a task run and must not become interactive. */
29
+ headlessLock?: boolean;
30
+ /** When set, this conversation is executing a task run. Used to retrieve ephemeral permission rules. */
31
+ taskRunId?: string;
32
+ /** Guardian runtime context for the conversation — trustClass is propagated into ToolContext for control-plane policy enforcement. */
33
+ trustContext?: TrustContext;
34
+ /** Voice/call session ID, if the conversation originates from a call. Propagated into ToolContext for scoped grant consumption. */
35
+ callSessionId?: string;
36
+ /** CES RPC client for credential execution operations. Injected when CES tools are enabled and the CES process is available. */
37
+ cesClient?: CesClient;
38
+ /** The interface ID of the connected client driving the current turn (e.g. "macos", "chrome-extension"). Propagated into ToolContext for browser backend selection. */
39
+ readonly transportInterface?: InterfaceId;
40
+
41
+ /** Turn-scoped flag: true when any tool call in the current turn received explicit user approval via interactive prompt. Cleared at turn end. */
42
+ approvedViaPromptThisTurn?: boolean;
43
+ /**
44
+ * Per-turn snapshot of the resolved inference-profile override, set by
45
+ * `runAgentLoopImpl`. Propagated into `ToolContext.overrideProfile` so
46
+ * tools that spawn nested invocations (e.g. `subagent_spawn`) can forward
47
+ * the override without round-tripping through a row read that would
48
+ * return `undefined` for the in-flight (background) subagent.
49
+ */
50
+ currentTurnOverrideProfile?: string;
51
+ }
@@ -22,9 +22,9 @@ import { getLogger } from "../util/logger.js";
22
22
  import { getWorkspaceDir } from "../util/platform.js";
23
23
  import { ensureAppSourceWatcher } from "./app-source-watcher.js";
24
24
  import { refreshSurfacesForApp } from "./conversation-surfaces.js";
25
- import type { ToolSetupContext } from "./conversation-tool-setup.js";
26
25
  import { isDoordashCommand, updateDoordashProgress } from "./doordash-steps.js";
27
26
  import type { ServerMessage } from "./message-protocol.js";
27
+ import type { ToolSetupContext } from "./tool-setup-types.js";
28
28
 
29
29
  const log = getLogger("tool-side-effects");
30
30
 
@@ -2,6 +2,7 @@ import {
2
2
  recordToolInvocation,
3
3
  type ToolInvocationRecord,
4
4
  } from "../memory/tool-usage-store.js";
5
+ import { redactSecrets } from "../security/secret-scanner.js";
5
6
  import type {
6
7
  ToolLifecycleEvent,
7
8
  ToolLifecycleEventHandler,
@@ -40,7 +41,7 @@ function toInvocationRecord(
40
41
  conversationId: event.conversationId,
41
42
  toolName: event.toolName,
42
43
  input: stringifyInput(event.input),
43
- result: event.result.content.slice(0, RESULT_PREVIEW_LIMIT),
44
+ result: redactSecrets(event.result.content).slice(0, RESULT_PREVIEW_LIMIT),
44
45
  decision: event.decision,
45
46
  riskLevel: event.riskLevel,
46
47
  matchedTrustRuleId: event.matchedTrustRuleId,
@@ -5,6 +5,18 @@ import { afterEach, beforeEach, describe, expect, mock, test } from "bun:test";
5
5
 
6
6
  let workspaceDir: string;
7
7
 
8
+ // Stub the heartbeat run store so HeartbeatService doesn't hit the real DB.
9
+ mock.module("../heartbeat-run-store.js", () => ({
10
+ insertPendingHeartbeatRun: () => "mock-run-id",
11
+ startHeartbeatRun: () => true,
12
+ completeHeartbeatRun: () => true,
13
+ skipHeartbeatRun: () => true,
14
+ supersedePendingRun: () => true,
15
+ markStaleRunsAsMissed: () => 0,
16
+ markStaleRunningAsError: () => 0,
17
+ listHeartbeatRuns: () => [],
18
+ }));
19
+
8
20
  // Stub the in-process SSE hub so the writer's publish path is a
9
21
  // no-op in these tests.
10
22
  const publishSpy = mock<(event: unknown) => Promise<void>>(async () => {});
@@ -60,12 +72,10 @@ mock.module("../../config/loader.js", () => ({
60
72
  getConfig: () => stubConfig,
61
73
  getConfigReadOnly: () => stubConfig,
62
74
  loadConfig: () => stubConfig,
63
- saveConfig: () => {},
64
75
  invalidateConfigCache: () => {},
65
76
  loadRawConfig: () => ({}),
66
77
  saveRawConfig: () => {},
67
78
  applyNestedDefaults: (c: unknown) => c,
68
- deepMergeMissing: (a: unknown) => a,
69
79
  deepMergeOverwrite: (a: unknown) => a,
70
80
  mergeDefaultWorkspaceConfig: () => {},
71
81
  getNestedValue: () => undefined,
@@ -200,13 +210,11 @@ describe("heartbeat feed events", () => {
200
210
  await new Promise((r) => setTimeout(r, 100));
201
211
 
202
212
  const items = readFeedItems();
203
- const heartbeatItem = items.find((i) => i.title === "Heartbeat");
213
+ const heartbeatItem = items.find((i) => i.title === "Heartbeat Failed");
204
214
  expect(heartbeatItem).toBeDefined();
205
- expect(heartbeatItem!.summary).toBe(
206
- "Heartbeat check failed. Check logs for details.",
207
- );
215
+ expect(heartbeatItem!.summary).toContain("LLM call failed");
208
216
  expect(heartbeatItem!.priority).toBe(55);
209
- expect(heartbeatItem!.urgency).toBe("medium");
217
+ expect(heartbeatItem!.urgency).toBe("high");
210
218
  expect(heartbeatItem!.source).toBe("assistant");
211
219
  });
212
220
 
@@ -0,0 +1,216 @@
1
+ import { beforeEach, describe, expect, test } from "bun:test";
2
+ import { mock } from "bun:test";
3
+
4
+ mock.module("../../util/logger.js", () => ({
5
+ getLogger: () =>
6
+ new Proxy({} as Record<string, unknown>, {
7
+ get: () => () => {},
8
+ }),
9
+ truncateForLog: (value: string) => value,
10
+ }));
11
+
12
+ import { sql } from "drizzle-orm";
13
+
14
+ import { getDb } from "../../memory/db-connection.js";
15
+ import { initializeDb } from "../../memory/db-init.js";
16
+ import {
17
+ completeHeartbeatRun,
18
+ insertPendingHeartbeatRun,
19
+ listHeartbeatRuns,
20
+ markStaleRunningAsError,
21
+ markStaleRunsAsMissed,
22
+ skipHeartbeatRun,
23
+ startHeartbeatRun,
24
+ supersedePendingRun,
25
+ } from "../heartbeat-run-store.js";
26
+
27
+ initializeDb();
28
+
29
+ describe("heartbeat-run-store", () => {
30
+ beforeEach(() => {
31
+ const db = getDb();
32
+ db.run("DELETE FROM heartbeat_runs");
33
+ });
34
+
35
+ test("insertPendingHeartbeatRun creates row with status pending and null timing", () => {
36
+ const scheduledFor = Date.now();
37
+ const id = insertPendingHeartbeatRun(scheduledFor);
38
+ expect(id).toBeTruthy();
39
+
40
+ const rows = listHeartbeatRuns();
41
+ expect(rows).toHaveLength(1);
42
+ expect(rows[0].id).toBe(id);
43
+ expect(rows[0].status).toBe("pending");
44
+ expect(rows[0].scheduledFor).toBe(scheduledFor);
45
+ expect(rows[0].startedAt).toBeNull();
46
+ expect(rows[0].finishedAt).toBeNull();
47
+ expect(rows[0].durationMs).toBeNull();
48
+ expect(rows[0].error).toBeNull();
49
+ expect(rows[0].conversationId).toBeNull();
50
+ expect(rows[0].skipReason).toBeNull();
51
+ });
52
+
53
+ test("startHeartbeatRun transitions pending -> running and sets startedAt", () => {
54
+ const id = insertPendingHeartbeatRun(Date.now());
55
+ const ok = startHeartbeatRun(id);
56
+ expect(ok).toBe(true);
57
+
58
+ const rows = listHeartbeatRuns();
59
+ expect(rows[0].status).toBe("running");
60
+ expect(rows[0].startedAt).toBeGreaterThan(0);
61
+ });
62
+
63
+ test("startHeartbeatRun returns false for non-pending row", () => {
64
+ const id = insertPendingHeartbeatRun(Date.now());
65
+
66
+ // Start once — succeeds
67
+ expect(startHeartbeatRun(id)).toBe(true);
68
+ // Start again — fails (already running)
69
+ expect(startHeartbeatRun(id)).toBe(false);
70
+
71
+ // Also: superseded row cannot be started
72
+ const id2 = insertPendingHeartbeatRun(Date.now());
73
+ supersedePendingRun(id2);
74
+ expect(startHeartbeatRun(id2)).toBe(false);
75
+ });
76
+
77
+ test("completeHeartbeatRun transitions running -> ok with conversationId", () => {
78
+ const id = insertPendingHeartbeatRun(Date.now());
79
+ startHeartbeatRun(id);
80
+ const ok = completeHeartbeatRun(id, {
81
+ status: "ok",
82
+ conversationId: "conv-123",
83
+ });
84
+ expect(ok).toBe(true);
85
+
86
+ const rows = listHeartbeatRuns();
87
+ expect(rows[0].status).toBe("ok");
88
+ expect(rows[0].conversationId).toBe("conv-123");
89
+ expect(rows[0].finishedAt).toBeGreaterThan(0);
90
+ expect(rows[0].durationMs).toBeGreaterThanOrEqual(0);
91
+ });
92
+
93
+ test("completeHeartbeatRun transitions running -> error with truncated error", () => {
94
+ const id = insertPendingHeartbeatRun(Date.now());
95
+ startHeartbeatRun(id);
96
+
97
+ // 3KB string — should be truncated to 2000 chars
98
+ const longError = "x".repeat(3000);
99
+ const ok = completeHeartbeatRun(id, {
100
+ status: "error",
101
+ error: longError,
102
+ });
103
+ expect(ok).toBe(true);
104
+
105
+ const rows = listHeartbeatRuns();
106
+ expect(rows[0].status).toBe("error");
107
+ expect(rows[0].error).toHaveLength(2000);
108
+ });
109
+
110
+ test("completeHeartbeatRun returns false when status is not running (CAS)", () => {
111
+ const id = insertPendingHeartbeatRun(Date.now());
112
+ startHeartbeatRun(id);
113
+ // Complete with timeout
114
+ completeHeartbeatRun(id, { status: "timeout" });
115
+ // Try to complete again with ok — should fail (already timeout)
116
+ const ok = completeHeartbeatRun(id, { status: "ok" });
117
+ expect(ok).toBe(false);
118
+
119
+ const rows = listHeartbeatRuns();
120
+ expect(rows[0].status).toBe("timeout");
121
+ });
122
+
123
+ test("skipHeartbeatRun transitions pending -> skipped with reason", () => {
124
+ const id = insertPendingHeartbeatRun(Date.now());
125
+ const ok = skipHeartbeatRun(id, "outside_active_hours");
126
+ expect(ok).toBe(true);
127
+
128
+ const rows = listHeartbeatRuns();
129
+ expect(rows[0].status).toBe("skipped");
130
+ expect(rows[0].skipReason).toBe("outside_active_hours");
131
+ });
132
+
133
+ test("skipHeartbeatRun returns false for non-pending row", () => {
134
+ const id = insertPendingHeartbeatRun(Date.now());
135
+ startHeartbeatRun(id);
136
+ const ok = skipHeartbeatRun(id, "disabled");
137
+ expect(ok).toBe(false);
138
+ });
139
+
140
+ test("supersedePendingRun transitions pending -> superseded", () => {
141
+ const id = insertPendingHeartbeatRun(Date.now());
142
+ const ok = supersedePendingRun(id);
143
+ expect(ok).toBe(true);
144
+
145
+ const rows = listHeartbeatRuns();
146
+ expect(rows[0].status).toBe("superseded");
147
+ });
148
+
149
+ test("supersedePendingRun returns false for non-pending row", () => {
150
+ const id = insertPendingHeartbeatRun(Date.now());
151
+ startHeartbeatRun(id);
152
+ const ok = supersedePendingRun(id);
153
+ expect(ok).toBe(false);
154
+ });
155
+
156
+ test("markStaleRunsAsMissed transitions old pending rows to missed", () => {
157
+ const now = Date.now();
158
+ // Two old pending rows
159
+ const id1 = insertPendingHeartbeatRun(now - 10 * 60 * 1000);
160
+ const id2 = insertPendingHeartbeatRun(now - 8 * 60 * 1000);
161
+ // One recent pending row
162
+ const id3 = insertPendingHeartbeatRun(now);
163
+
164
+ const count = markStaleRunsAsMissed(5 * 60 * 1000);
165
+ expect(count).toBe(2);
166
+
167
+ const rows = listHeartbeatRuns();
168
+ const byId = Object.fromEntries(rows.map((r) => [r.id, r]));
169
+ expect(byId[id1].status).toBe("missed");
170
+ expect(byId[id2].status).toBe("missed");
171
+ expect(byId[id3].status).toBe("pending");
172
+ });
173
+
174
+ test("markStaleRunningAsError transitions old running rows to error", () => {
175
+ const now = Date.now();
176
+ const id = insertPendingHeartbeatRun(now - 60 * 60 * 1000);
177
+ startHeartbeatRun(id);
178
+
179
+ // Backdate started_at to simulate a long-running process
180
+ const db = getDb();
181
+ const backdatedStartedAt = now - 60 * 60 * 1000;
182
+ db.run(
183
+ sql`UPDATE heartbeat_runs SET started_at = ${backdatedStartedAt} WHERE id = ${id}`,
184
+ );
185
+
186
+ const count = markStaleRunningAsError(45 * 60 * 1000);
187
+ expect(count).toBe(1);
188
+
189
+ const rows = listHeartbeatRuns();
190
+ expect(rows[0].status).toBe("error");
191
+ expect(rows[0].error).toBe("Process crashed or restarted during execution");
192
+ });
193
+
194
+ test("listHeartbeatRuns returns rows ordered by scheduledFor desc", () => {
195
+ const now = Date.now();
196
+ insertPendingHeartbeatRun(now - 2000);
197
+ insertPendingHeartbeatRun(now);
198
+ insertPendingHeartbeatRun(now - 1000);
199
+
200
+ const rows = listHeartbeatRuns();
201
+ expect(rows).toHaveLength(3);
202
+ expect(rows[0].scheduledFor).toBe(now);
203
+ expect(rows[1].scheduledFor).toBe(now - 1000);
204
+ expect(rows[2].scheduledFor).toBe(now - 2000);
205
+ });
206
+
207
+ test("listHeartbeatRuns respects limit", () => {
208
+ const now = Date.now();
209
+ for (let i = 0; i < 5; i++) {
210
+ insertPendingHeartbeatRun(now + i);
211
+ }
212
+
213
+ const rows = listHeartbeatRuns(3);
214
+ expect(rows).toHaveLength(3);
215
+ });
216
+ });