@vellumai/assistant 0.7.0 → 0.7.1

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 (666) hide show
  1. package/ARCHITECTURE.md +6 -7
  2. package/Dockerfile +1 -0
  3. package/README.md +2 -2
  4. package/__tests__/permissions/gateway-threshold-reader.test.ts +79 -139
  5. package/bun.lock +3 -0
  6. package/docs/architecture/security.md +18 -16
  7. package/knip.json +1 -0
  8. package/node_modules/@vellumai/skill-host-contracts/__tests__/client.test.ts +1 -5
  9. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -5
  10. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -16
  11. package/node_modules/@vellumai/skill-host-contracts/src/skill-host.ts +1 -9
  12. package/node_modules/@vellumai/skill-host-contracts/src/tool-types.ts +12 -12
  13. package/node_modules/@vellumai/slack-text/bun.lock +24 -0
  14. package/node_modules/@vellumai/slack-text/package.json +18 -0
  15. package/node_modules/@vellumai/slack-text/src/index.test.ts +153 -0
  16. package/node_modules/@vellumai/slack-text/src/index.ts +235 -0
  17. package/node_modules/@vellumai/slack-text/tsconfig.json +20 -0
  18. package/openapi.yaml +294 -107
  19. package/package.json +4 -2
  20. package/scripts/generate-openapi.ts +16 -111
  21. package/src/__tests__/agent-wake-override-profile.test.ts +23 -1
  22. package/src/__tests__/anthropic-provider.test.ts +56 -13
  23. package/src/__tests__/app-conversation-ids-backfill.test.ts +278 -0
  24. package/src/__tests__/app-conversation-ids.test.ts +151 -0
  25. package/src/__tests__/approval-cascade.test.ts +0 -15
  26. package/src/__tests__/approval-routes-http.test.ts +6 -17
  27. package/src/__tests__/assistant-event-hub.test.ts +126 -77
  28. package/src/__tests__/assistant-event.test.ts +0 -5
  29. package/src/__tests__/assistant-events-sse-hardening.test.ts +37 -15
  30. package/src/__tests__/assistant-feature-flags-integration.test.ts +0 -29
  31. package/src/__tests__/background-shell-host-bash.test.ts +34 -43
  32. package/src/__tests__/call-controller.test.ts +1 -1
  33. package/src/__tests__/call-site-routing-provider.test.ts +193 -0
  34. package/src/__tests__/channel-approval-routes.test.ts +10 -296
  35. package/src/__tests__/channel-approvals.test.ts +25 -17
  36. package/src/__tests__/channel-guardian.test.ts +100 -146
  37. package/src/__tests__/checker.test.ts +20 -34
  38. package/src/__tests__/compact-event-conversation-id-guard.test.ts +50 -0
  39. package/src/__tests__/compaction-events.test.ts +2 -0
  40. package/src/__tests__/config-schema.test.ts +6 -48
  41. package/src/__tests__/config-watcher.test.ts +12 -0
  42. package/src/__tests__/connection-policy.test.ts +1 -52
  43. package/src/__tests__/contacts-write.test.ts +2 -64
  44. package/src/__tests__/context-image-dimensions.test.ts +1 -1
  45. package/src/__tests__/context-search-memory-source.test.ts +120 -1
  46. package/src/__tests__/context-search-memory-v2-source.test.ts +383 -0
  47. package/src/__tests__/context-search-pkb-source.test.ts +49 -0
  48. package/src/__tests__/context-search-workspace-source.test.ts +9 -22
  49. package/src/__tests__/context-window-manager.test.ts +46 -0
  50. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +2 -0
  51. package/src/__tests__/conversation-agent-loop-overflow.test.ts +102 -29
  52. package/src/__tests__/conversation-agent-loop.test.ts +980 -13
  53. package/src/__tests__/conversation-analysis-routes.test.ts +12 -10
  54. package/src/__tests__/conversation-attention-telegram.test.ts +11 -3
  55. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -291
  56. package/src/__tests__/conversation-history-web-search.test.ts +4 -3
  57. package/src/__tests__/conversation-inference-profile-route.test.ts +12 -23
  58. package/src/__tests__/conversation-lifecycle.test.ts +4 -4
  59. package/src/__tests__/conversation-process-callsite.test.ts +79 -2
  60. package/src/__tests__/conversation-queue.test.ts +3 -8
  61. package/src/__tests__/conversation-routes-disk-view.test.ts +1 -161
  62. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -32
  63. package/src/__tests__/conversation-routes-slash-commands.test.ts +75 -66
  64. package/src/__tests__/conversation-runtime-assembly.test.ts +257 -3
  65. package/src/__tests__/conversation-slash-commands.test.ts +24 -4
  66. package/src/__tests__/conversation-slash-queue.test.ts +2 -0
  67. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  68. package/src/__tests__/conversation-starter-routes.test.ts +79 -2
  69. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +12 -5
  70. package/src/__tests__/conversation-surfaces-standalone.test.ts +18 -14
  71. package/src/__tests__/conversation-surfaces-state-update.test.ts +3 -2
  72. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +8 -46
  73. package/src/__tests__/conversation-usage.test.ts +253 -3
  74. package/src/__tests__/credential-execution-shell-lockdown.test.ts +0 -39
  75. package/src/__tests__/credential-health-service.test.ts +68 -0
  76. package/src/__tests__/credential-security-e2e.test.ts +4 -3
  77. package/src/__tests__/credential-security-invariants.test.ts +1 -5
  78. package/src/__tests__/credential-token-resolver.test.ts +180 -0
  79. package/src/__tests__/cu-unified-flow.test.ts +33 -16
  80. package/src/__tests__/daemon-assistant-events.test.ts +34 -21
  81. package/src/__tests__/daemon-credential-client.test.ts +4 -1
  82. package/src/__tests__/db-connection-isolation.test.ts +125 -0
  83. package/src/__tests__/db-migration-rollback.test.ts +101 -0
  84. package/src/__tests__/db-slack-compaction-watermark-migration.test.ts +169 -0
  85. package/src/__tests__/deterministic-verification-control-plane.test.ts +7 -80
  86. package/src/__tests__/document-conversations.test.ts +332 -0
  87. package/src/__tests__/embedding-managed-proxy-selection.test.ts +2 -2
  88. package/src/__tests__/emit-event-signal.test.ts +4 -6
  89. package/src/__tests__/events-client-registration.test.ts +193 -49
  90. package/src/__tests__/filing-service.test.ts +58 -7
  91. package/src/__tests__/first-greeting.test.ts +156 -150
  92. package/src/__tests__/fixtures/mock-chrome-extension.ts +108 -66
  93. package/src/__tests__/get-skill-detail-audit.test.ts +3 -8
  94. package/src/__tests__/guardian-binding-drift-heal.test.ts +1 -1
  95. package/src/__tests__/guardian-dispatch.test.ts +1 -1
  96. package/src/__tests__/guardian-grant-minting.test.ts +7 -2
  97. package/src/__tests__/guardian-routing-invariants.test.ts +7 -2
  98. package/src/__tests__/guardian-routing-state.test.ts +1 -1
  99. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +32 -11
  100. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +2 -83
  101. package/src/__tests__/headless-browser-mode.test.ts +4 -9
  102. package/src/__tests__/headless-browser-navigate.test.ts +21 -20
  103. package/src/__tests__/heartbeat-service.test.ts +289 -7
  104. package/src/__tests__/helpers/channel-test-adapter.ts +2 -2
  105. package/src/__tests__/helpers/create-guardian-binding.ts +91 -0
  106. package/src/__tests__/host-bash-proxy.test.ts +46 -122
  107. package/src/__tests__/host-browser-e2e-cloud.test.ts +36 -497
  108. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +26 -96
  109. package/src/__tests__/host-browser-proxy.test.ts +111 -185
  110. package/src/__tests__/host-browser-routes.test.ts +45 -75
  111. package/src/__tests__/host-browser-ws-events-e2e.test.ts +26 -30
  112. package/src/__tests__/host-cu-proxy.test.ts +56 -111
  113. package/src/__tests__/host-file-proxy.test.ts +44 -98
  114. package/src/__tests__/host-file-read-tool.test.ts +42 -21
  115. package/src/__tests__/host-shell-tool.test.ts +33 -68
  116. package/src/__tests__/host-transfer-pending-interactions.test.ts +2 -18
  117. package/src/__tests__/host-transfer-proxy.test.ts +43 -53
  118. package/src/__tests__/http-user-message-parity.test.ts +0 -6
  119. package/src/__tests__/inbound-slack-persistence.test.ts +31 -0
  120. package/src/__tests__/injector-chain.test.ts +10 -5
  121. package/src/__tests__/injector-pkb-v2-silenced.test.ts +124 -0
  122. package/src/__tests__/inline-command-runner.test.ts +0 -66
  123. package/src/__tests__/inline-skill-load-permissions.test.ts +0 -2
  124. package/src/__tests__/install-skill-routing.test.ts +1 -13
  125. package/src/__tests__/llm-callsite-catalog.test.ts +34 -0
  126. package/src/__tests__/llm-catalog-parity.test.ts +90 -0
  127. package/src/__tests__/llm-context-resolution.test.ts +180 -0
  128. package/src/__tests__/llm-resolver.test.ts +80 -12
  129. package/src/__tests__/llm-usage-store.test.ts +269 -4
  130. package/src/__tests__/log-export-routes.test.ts +89 -0
  131. package/src/__tests__/managed-profile-guard.test.ts +225 -0
  132. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -10
  133. package/src/__tests__/manual-token-reconciliation.test.ts +334 -0
  134. package/src/__tests__/memory-v2-static-injector.test.ts +95 -0
  135. package/src/__tests__/migration-cross-version-compatibility.test.ts +197 -291
  136. package/src/__tests__/migration-export-http.test.ts +33 -26
  137. package/src/__tests__/migration-export-streaming.test.ts +18 -10
  138. package/src/__tests__/migration-export-to-gcs.test.ts +49 -9
  139. package/src/__tests__/migration-import-commit-http.test.ts +66 -21
  140. package/src/__tests__/migration-import-from-gcs.test.ts +50 -9
  141. package/src/__tests__/migration-import-from-url.test.ts +20 -6
  142. package/src/__tests__/migration-import-preflight-http.test.ts +95 -95
  143. package/src/__tests__/migration-parity-persistence.test.ts +62 -25
  144. package/src/__tests__/migration-transport.test.ts +115 -23
  145. package/src/__tests__/migration-validate-http.test.ts +105 -80
  146. package/src/__tests__/migration-wizard.test.ts +133 -27
  147. package/src/__tests__/non-member-access-request.test.ts +1 -1
  148. package/src/__tests__/notification-guardian-path.test.ts +1 -1
  149. package/src/__tests__/oauth-store.test.ts +19 -0
  150. package/src/__tests__/platform-bash-auto-approve.test.ts +21 -12
  151. package/src/__tests__/prechat-onboarding-contract.test.ts +31 -7
  152. package/src/__tests__/pricing.test.ts +68 -4
  153. package/src/__tests__/process-message-background-slack.test.ts +331 -0
  154. package/src/__tests__/provider-managed-proxy-integration.test.ts +153 -17
  155. package/src/__tests__/provider-send-message-override-profile.test.ts +50 -0
  156. package/src/__tests__/provider-usage-tracking.test.ts +208 -0
  157. package/src/__tests__/reaction-persistence.test.ts +9 -6
  158. package/src/__tests__/rebind-secrets-screen.test.ts +53 -16
  159. package/src/__tests__/recording-handler.test.ts +64 -81
  160. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +4 -3
  161. package/src/__tests__/relay-server.test.ts +18 -13
  162. package/src/__tests__/require-fresh-approval.test.ts +13 -22
  163. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -1
  164. package/src/__tests__/runtime-events-sse-parity.test.ts +3 -4
  165. package/src/__tests__/runtime-events-sse.test.ts +3 -12
  166. package/src/__tests__/search-skills-unified.test.ts +9 -15
  167. package/src/__tests__/secret-ingress-cli.test.ts +2 -5
  168. package/src/__tests__/secret-ingress-http.test.ts +0 -4
  169. package/src/__tests__/secret-onetime-send.test.ts +4 -2
  170. package/src/__tests__/secret-prompt-log-hygiene.test.ts +24 -7
  171. package/src/__tests__/secret-prompter-channel-fallback.test.ts +42 -47
  172. package/src/__tests__/secret-response-routing.test.ts +29 -15
  173. package/src/__tests__/secret-routes-managed-proxy.test.ts +5 -1
  174. package/src/__tests__/secret-scanner.test.ts +2 -545
  175. package/src/__tests__/send-endpoint-busy.test.ts +9 -24
  176. package/src/__tests__/settings-routes.test.ts +1 -1
  177. package/src/__tests__/shell-credential-ref.test.ts +0 -8
  178. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -56
  179. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -11
  180. package/src/__tests__/skill-tool-factory.test.ts +97 -0
  181. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -30
  182. package/src/__tests__/skills-files-catalog-fallback.test.ts +11 -17
  183. package/src/__tests__/slack-inbound-verification.test.ts +1 -62
  184. package/src/__tests__/subagent-fork-notifications.test.ts +57 -47
  185. package/src/__tests__/subagent-manager-notify.test.ts +70 -70
  186. package/src/__tests__/subagent-notify-parent.test.ts +80 -83
  187. package/src/__tests__/system-prompt.test.ts +115 -13
  188. package/src/__tests__/terminal-tools.test.ts +0 -89
  189. package/src/__tests__/thread-backfill.test.ts +945 -31
  190. package/src/__tests__/tool-domain-event-publisher.test.ts +0 -36
  191. package/src/__tests__/tool-execute-pipeline.test.ts +0 -6
  192. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -16
  193. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +9 -19
  194. package/src/__tests__/tool-executor-lifecycle-events.test.ts +4 -7
  195. package/src/__tests__/tool-executor.test.ts +12 -19
  196. package/src/__tests__/tool-metrics-listener.test.ts +0 -35
  197. package/src/__tests__/tool-side-effects-slack-dm.test.ts +1 -0
  198. package/src/__tests__/tool-trace-listener.test.ts +0 -17
  199. package/src/__tests__/transfer-progress-screen.test.ts +63 -26
  200. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +2 -149
  201. package/src/__tests__/trusted-contact-multichannel.test.ts +2 -4
  202. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  203. package/src/__tests__/tts-catalog-parity.test.ts +16 -5
  204. package/src/__tests__/usage-attribution.test.ts +247 -0
  205. package/src/__tests__/usage-cli.test.ts +143 -0
  206. package/src/__tests__/usage-grouped-buckets.test.ts +155 -0
  207. package/src/__tests__/usage-routes.test.ts +150 -0
  208. package/src/__tests__/validation-results-screen.test.ts +39 -16
  209. package/src/__tests__/vbundle-pax-and-symlink.test.ts +12 -3
  210. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +49 -137
  211. package/src/__tests__/verification-control-plane-policy.test.ts +4 -7
  212. package/src/__tests__/voice-session-bridge.test.ts +5 -5
  213. package/src/__tests__/workspace-migration-062-drop-memory-v2-edges-json.test.ts +103 -0
  214. package/src/__tests__/workspace-migration-063-release-notes-dynamic-model-context.test.ts +77 -0
  215. package/src/__tests__/workspace-migration-064-unwind-main-agent-opus-seed.test.ts +225 -0
  216. package/src/__tests__/workspace-migration-memory-v2-init.test.ts +8 -30
  217. package/src/acp/index.ts +0 -15
  218. package/src/acp/session-manager.ts +37 -34
  219. package/src/agent/loop.ts +16 -1
  220. package/src/approvals/AGENTS.md +4 -0
  221. package/src/approvals/__tests__/guardian-feed-event.test.ts +10 -3
  222. package/src/approvals/guardian-request-resolvers.ts +10 -2
  223. package/src/backup/__tests__/backup-worker.test.ts +36 -8
  224. package/src/backup/__tests__/paths.test.ts +2 -2
  225. package/src/backup/__tests__/restore.test.ts +45 -28
  226. package/src/backup/backup-worker.ts +36 -2
  227. package/src/backup/paths.ts +9 -6
  228. package/src/browser-session/events.ts +0 -9
  229. package/src/calls/call-store.ts +1 -34
  230. package/src/calls/guardian-question-copy.ts +0 -108
  231. package/src/calls/relay-server.ts +0 -24
  232. package/src/calls/twilio-rest.ts +0 -38
  233. package/src/calls/twilio-routes.ts +1 -1
  234. package/src/calls/voice-session-bridge.ts +7 -38
  235. package/src/channels/types.ts +1 -36
  236. package/src/cli/commands/__tests__/cache.test.ts +152 -5
  237. package/src/cli/commands/__tests__/memory-v2.test.ts +14 -28
  238. package/src/cli/commands/__tests__/trust.test.ts +21 -387
  239. package/src/cli/commands/backup.ts +4 -4
  240. package/src/cli/commands/cache-fs.ts +8 -0
  241. package/src/cli/commands/cache.ts +153 -82
  242. package/src/cli/commands/clients.ts +63 -5
  243. package/src/cli/commands/completions.ts +3 -3
  244. package/src/cli/commands/contacts.ts +231 -76
  245. package/src/cli/commands/keys.ts +4 -1
  246. package/src/cli/commands/memory-v2.ts +24 -52
  247. package/src/cli/commands/oauth/shared.ts +2 -29
  248. package/src/cli/commands/pending.ts +102 -0
  249. package/src/cli/commands/skills.ts +77 -35
  250. package/src/cli/commands/trust.ts +70 -430
  251. package/src/cli/commands/usage.ts +25 -16
  252. package/src/cli/lib/daemon-credential-client.ts +14 -0
  253. package/src/cli/program.ts +2 -0
  254. package/src/cli.ts +0 -21
  255. package/src/config/__tests__/feature-flag-registry-guard.test.ts +2 -2
  256. package/src/config/bundled-skills/messaging/TOOLS.json +14 -4
  257. package/src/config/env-registry.ts +12 -2
  258. package/src/config/env.ts +3 -14
  259. package/src/config/feature-flag-registry.json +30 -30
  260. package/src/config/llm-callsite-catalog.ts +12 -0
  261. package/src/config/llm-context-resolution.ts +80 -0
  262. package/src/config/llm-resolver.ts +58 -22
  263. package/src/config/loader.ts +3 -3
  264. package/src/config/schema.ts +2 -158
  265. package/src/config/schemas/__tests__/memory-v2.test.ts +1 -0
  266. package/src/config/schemas/call-site-catalog.ts +271 -0
  267. package/src/config/schemas/calls.ts +5 -5
  268. package/src/config/schemas/inference.ts +1 -1
  269. package/src/config/schemas/ingress.ts +1 -1
  270. package/src/config/schemas/llm.ts +31 -3
  271. package/src/config/schemas/memory-retrieval.ts +2 -2
  272. package/src/config/schemas/memory-v2.ts +9 -0
  273. package/src/config/schemas/security.ts +1 -42
  274. package/src/config/schemas/services.ts +6 -6
  275. package/src/config/schemas/skills.ts +5 -5
  276. package/src/config/schemas/tts.ts +1 -1
  277. package/src/config/seed-inference-profiles.ts +117 -0
  278. package/src/config/skills.ts +0 -90
  279. package/src/config/types.ts +3 -6
  280. package/src/contacts/contact-store.ts +0 -17
  281. package/src/contacts/contacts-write.ts +1 -105
  282. package/src/context/window-manager.ts +44 -5
  283. package/src/credential-execution/process-manager.ts +34 -10
  284. package/src/credential-health/credential-health-service.ts +21 -16
  285. package/src/daemon/__tests__/conversation-surfaces-launch.test.ts +75 -82
  286. package/src/daemon/__tests__/daemon-skill-host.test.ts +2 -9
  287. package/src/daemon/connection-policy.ts +1 -26
  288. package/src/daemon/conversation-agent-loop-handlers.ts +53 -4
  289. package/src/daemon/conversation-agent-loop.ts +277 -36
  290. package/src/daemon/conversation-history.ts +8 -8
  291. package/src/daemon/conversation-launch.ts +20 -135
  292. package/src/daemon/conversation-lifecycle.ts +1 -1
  293. package/src/daemon/conversation-messaging.ts +1 -0
  294. package/src/daemon/conversation-process.ts +83 -163
  295. package/src/daemon/conversation-runtime-assembly.ts +219 -76
  296. package/src/daemon/conversation-slash.ts +47 -5
  297. package/src/daemon/conversation-store.ts +7 -31
  298. package/src/daemon/conversation-surfaces.ts +22 -28
  299. package/src/daemon/conversation-tool-setup.ts +3 -33
  300. package/src/daemon/conversation-usage.ts +36 -0
  301. package/src/daemon/conversation.ts +117 -233
  302. package/src/daemon/daemon-control.ts +3 -71
  303. package/src/daemon/daemon-skill-host.ts +8 -11
  304. package/src/daemon/dictation-profile-store.ts +2 -26
  305. package/src/daemon/first-greeting.ts +44 -156
  306. package/src/daemon/handlers/config-channels.ts +12 -12
  307. package/src/daemon/handlers/config-ingress.ts +4 -165
  308. package/src/daemon/handlers/config-model.ts +1 -1
  309. package/src/daemon/handlers/config-voice.ts +0 -42
  310. package/src/daemon/handlers/conversations.ts +11 -190
  311. package/src/daemon/handlers/recording.ts +26 -158
  312. package/src/daemon/handlers/shared.ts +23 -71
  313. package/src/daemon/handlers/skills.ts +42 -93
  314. package/src/daemon/host-bash-proxy.ts +67 -45
  315. package/src/daemon/host-browser-proxy.ts +65 -27
  316. package/src/daemon/host-cu-proxy.ts +40 -39
  317. package/src/daemon/host-file-proxy.ts +58 -37
  318. package/src/daemon/host-transfer-proxy.ts +84 -46
  319. package/src/daemon/lifecycle.ts +49 -15
  320. package/src/daemon/message-types/conversations.ts +7 -0
  321. package/src/daemon/message-types/host-bash.ts +1 -0
  322. package/src/daemon/message-types/host-cu.ts +1 -0
  323. package/src/daemon/message-types/host-file.ts +1 -0
  324. package/src/daemon/message-types/host-transfer.ts +1 -0
  325. package/src/daemon/message-types/messages.ts +10 -9
  326. package/src/daemon/message-types/workspace.ts +1 -1
  327. package/src/daemon/process-message.ts +102 -239
  328. package/src/daemon/server.ts +13 -462
  329. package/src/daemon/shutdown-handlers.ts +2 -2
  330. package/src/daemon/tool-side-effects.ts +125 -107
  331. package/src/daemon/trust-context.ts +13 -0
  332. package/src/daemon/wake-target-adapter.ts +4 -9
  333. package/src/events/domain-events.ts +0 -8
  334. package/src/events/tool-audit-listener.ts +3 -1
  335. package/src/events/tool-domain-event-publisher.ts +0 -10
  336. package/src/events/tool-metrics-listener.ts +0 -17
  337. package/src/events/tool-trace-listener.ts +0 -14
  338. package/src/filing/filing-service.ts +13 -1
  339. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +6 -2
  340. package/src/heartbeat/heartbeat-service.ts +23 -5
  341. package/src/home/__tests__/feed-writer.test.ts +0 -4
  342. package/src/home/__tests__/relationship-state-writer.test.ts +30 -0
  343. package/src/home/feed-writer.ts +1 -2
  344. package/src/home/relationship-state-writer.ts +16 -3
  345. package/src/ipc/__tests__/browser-ipc.test.ts +2 -12
  346. package/src/ipc/__tests__/skill-server-bidirectional.test.ts +0 -1
  347. package/src/ipc/assistant-server.ts +3 -10
  348. package/src/ipc/routes/__tests__/memory-v2-backfill.test.ts +39 -20
  349. package/src/ipc/routes/route-adapter.ts +1 -1
  350. package/src/ipc/routes/trust-rules.test.ts +0 -95
  351. package/src/ipc/skill-ipc-types.ts +41 -0
  352. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +13 -27
  353. package/src/ipc/skill-routes/__tests__/identity.test.ts +4 -23
  354. package/src/ipc/skill-routes/events.ts +12 -23
  355. package/src/ipc/skill-routes/identity.ts +4 -17
  356. package/src/ipc/skill-routes/index.ts +1 -1
  357. package/src/ipc/skill-server.ts +6 -39
  358. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +0 -8
  359. package/src/live-voice/protocol.ts +4 -13
  360. package/src/mcp/manager.ts +0 -5
  361. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +55 -0
  362. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +127 -0
  363. package/src/memory/app-git-service.ts +0 -32
  364. package/src/memory/app-store.ts +154 -0
  365. package/src/memory/attachments-store.ts +6 -0
  366. package/src/memory/context-search/sources/memory-v2.ts +578 -0
  367. package/src/memory/context-search/sources/memory.ts +5 -0
  368. package/src/memory/context-search/sources/pkb.ts +10 -1
  369. package/src/memory/context-search/sources/workspace.ts +3 -2
  370. package/src/memory/conversation-crud.ts +29 -4
  371. package/src/memory/conversation-disk-view.ts +1 -5
  372. package/src/memory/conversation-starter-checkpoints.ts +63 -0
  373. package/src/memory/db-connection.ts +62 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +3 -21
  376. package/src/memory/embedding-gemini.ts +0 -2
  377. package/src/memory/embedding-local.ts +6 -6
  378. package/src/memory/embedding-ollama.ts +6 -6
  379. package/src/memory/embedding-openai.ts +6 -6
  380. package/src/memory/embedding-types.ts +21 -0
  381. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +3 -7
  382. package/src/memory/graph/conversation-graph-memory.ts +35 -13
  383. package/src/memory/graph/injection.test.ts +2 -2
  384. package/src/memory/graph/injection.ts +1 -1
  385. package/src/memory/guardian-action-store.ts +0 -83
  386. package/src/memory/guardian-approvals.ts +0 -48
  387. package/src/memory/indexer.ts +1 -15
  388. package/src/memory/job-handlers/conversation-starters.ts +36 -53
  389. package/src/memory/job-utils.ts +0 -6
  390. package/src/memory/jobs-store.ts +0 -1
  391. package/src/memory/jobs-worker.ts +2 -16
  392. package/src/memory/llm-request-log-store.ts +0 -41
  393. package/src/memory/llm-usage-store.ts +129 -43
  394. package/src/memory/memory-v2-activation-log-store.ts +115 -0
  395. package/src/memory/migrations/233-document-conversations.ts +54 -0
  396. package/src/memory/migrations/234-memory-v2-activation-logs.ts +55 -0
  397. package/src/memory/migrations/235-llm-usage-attribution.ts +31 -0
  398. package/src/memory/migrations/235-slack-compaction-watermark.ts +44 -0
  399. package/src/memory/migrations/236-tool-invocations-matched-rule-id.ts +26 -0
  400. package/src/memory/migrations/__tests__/234-memory-v2-activation-logs.test.ts +182 -0
  401. package/src/memory/migrations/index.ts +14 -0
  402. package/src/memory/migrations/registry.ts +24 -0
  403. package/src/memory/raw-query.ts +2 -68
  404. package/src/memory/schema/conversations.ts +7 -0
  405. package/src/memory/schema/infrastructure.ts +25 -0
  406. package/src/memory/search/semantic.ts +5 -16
  407. package/src/memory/tool-usage-store.ts +2 -0
  408. package/src/memory/usage-buckets.ts +40 -1
  409. package/src/memory/usage-grouped-buckets.ts +127 -0
  410. package/src/memory/v2/__tests__/activation.test.ts +289 -90
  411. package/src/memory/v2/__tests__/backfill-jobs.test.ts +2 -129
  412. package/src/memory/v2/__tests__/consolidation-job.test.ts +28 -11
  413. package/src/memory/v2/__tests__/edge-index.test.ts +278 -0
  414. package/src/memory/v2/__tests__/injection.test.ts +384 -15
  415. package/src/memory/v2/__tests__/migration.test.ts +64 -36
  416. package/src/memory/v2/__tests__/page-store.test.ts +191 -8
  417. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +181 -0
  418. package/src/memory/v2/__tests__/skill-store.test.ts +115 -3
  419. package/src/memory/v2/__tests__/static-context.test.ts +153 -0
  420. package/src/memory/v2/activation.ts +168 -97
  421. package/src/memory/v2/backfill-jobs.ts +15 -100
  422. package/src/memory/v2/consolidation-job.ts +14 -12
  423. package/src/memory/v2/edge-index.ts +191 -0
  424. package/src/memory/v2/injection.ts +182 -58
  425. package/src/memory/v2/migration.ts +57 -64
  426. package/src/memory/v2/now-text.ts +2 -3
  427. package/src/memory/v2/page-store.ts +168 -31
  428. package/src/memory/v2/prompts/consolidation.ts +118 -42
  429. package/src/memory/v2/prompts/sweep.ts +3 -3
  430. package/src/memory/v2/skill-store.ts +55 -7
  431. package/src/memory/v2/static-context.ts +62 -0
  432. package/src/memory/v2/types.ts +10 -20
  433. package/src/memory/validation.ts +0 -11
  434. package/src/messaging/draft-store.ts +0 -6
  435. package/src/messaging/provider-types.ts +8 -0
  436. package/src/messaging/provider.ts +7 -0
  437. package/src/messaging/providers/gmail/client.ts +1 -121
  438. package/src/messaging/providers/outlook/client.ts +0 -73
  439. package/src/messaging/providers/slack/__tests__/adapter-mention-rendering.test.ts +226 -0
  440. package/src/messaging/providers/slack/adapter.ts +122 -21
  441. package/src/messaging/providers/slack/backfill.test.ts +95 -6
  442. package/src/messaging/providers/slack/backfill.ts +89 -11
  443. package/src/messaging/providers/slack/client.ts +10 -124
  444. package/src/messaging/providers/slack/message-metadata.ts +12 -2
  445. package/src/messaging/providers/slack/render-transcript.test.ts +56 -0
  446. package/src/messaging/providers/slack/render-transcript.ts +126 -25
  447. package/src/messaging/providers/slack/types.ts +1 -0
  448. package/src/oauth/connection-resolver.test.ts +8 -0
  449. package/src/oauth/connection-resolver.ts +8 -16
  450. package/src/oauth/credential-token-resolver.ts +97 -0
  451. package/src/oauth/manual-token-connection.ts +30 -34
  452. package/src/oauth/oauth-store.ts +6 -4
  453. package/src/outbound-proxy/certs.ts +0 -7
  454. package/src/outbound-proxy/config.ts +0 -74
  455. package/src/outbound-proxy/health.ts +0 -44
  456. package/src/outbound-proxy/index.ts +0 -22
  457. package/src/permissions/approval-provenance.test.ts +184 -0
  458. package/src/permissions/approval-provenance.ts +70 -0
  459. package/src/permissions/checker.ts +4 -1
  460. package/src/permissions/gateway-threshold-reader.ts +4 -1
  461. package/src/permissions/prompter.ts +9 -2
  462. package/src/permissions/secret-prompter.ts +21 -48
  463. package/src/permissions/types.ts +33 -0
  464. package/src/permissions/workspace-policy.ts +0 -5
  465. package/src/platform/sync-identity.ts +0 -8
  466. package/src/plugins/defaults/injectors.ts +69 -2
  467. package/src/plugins/defaults/overflow-reduce.ts +3 -2
  468. package/src/plugins/types.ts +8 -0
  469. package/src/prompts/system-prompt.ts +34 -70
  470. package/src/prompts/templates/BOOTSTRAP.md +52 -6
  471. package/src/prompts/update-bulletin-job.ts +2 -0
  472. package/src/providers/__tests__/retry-callsite.test.ts +138 -1
  473. package/src/providers/anthropic/client.ts +72 -33
  474. package/src/providers/call-site-routing.ts +42 -3
  475. package/src/providers/gemini/client.ts +18 -2
  476. package/src/providers/managed-proxy/context.ts +0 -5
  477. package/src/providers/model-catalog.ts +105 -19
  478. package/src/providers/openai/chat-completions-provider.ts +6 -0
  479. package/src/providers/openai/responses-provider.ts +7 -1
  480. package/src/providers/provider-send-message.ts +45 -2
  481. package/src/providers/ratelimit.ts +7 -2
  482. package/src/providers/registry.ts +14 -9
  483. package/src/providers/retry.ts +96 -8
  484. package/src/providers/types.ts +13 -0
  485. package/src/providers/usage-tracking.ts +96 -0
  486. package/src/runtime/AGENTS.md +10 -6
  487. package/src/runtime/__tests__/agent-wake.test.ts +89 -0
  488. package/src/runtime/agent-wake.ts +39 -2
  489. package/src/runtime/assistant-event-hub.ts +541 -45
  490. package/src/runtime/assistant-event.ts +1 -6
  491. package/src/runtime/auth/context.ts +0 -9
  492. package/src/runtime/auth/middleware.ts +1 -1
  493. package/src/runtime/auth/route-policy.ts +11 -9
  494. package/src/runtime/auth/token-service.ts +0 -11
  495. package/src/runtime/channel-approvals.ts +6 -2
  496. package/src/runtime/channel-verification-service.ts +3 -5
  497. package/src/runtime/http-errors.ts +0 -34
  498. package/src/runtime/http-router.ts +6 -3
  499. package/src/runtime/http-server.ts +22 -82
  500. package/src/runtime/http-types.ts +5 -0
  501. package/src/runtime/interactive-ui.ts +0 -1
  502. package/src/runtime/middleware/auth.ts +0 -20
  503. package/src/runtime/migrations/__tests__/v1-test-helpers.ts +112 -0
  504. package/src/runtime/migrations/__tests__/vbundle-builder-credentials.test.ts +11 -4
  505. package/src/runtime/migrations/__tests__/vbundle-builder-v1-shape.test.ts +253 -0
  506. package/src/runtime/migrations/__tests__/vbundle-import-credentials.test.ts +19 -6
  507. package/src/runtime/migrations/__tests__/vbundle-legacy-user-md.test.ts +71 -27
  508. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +41 -2
  509. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +143 -79
  510. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +143 -23
  511. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +2 -2
  512. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +371 -0
  513. package/src/runtime/migrations/migration-transport.ts +46 -13
  514. package/src/runtime/migrations/migration-wizard.ts +2 -2
  515. package/src/runtime/migrations/origin-mode.ts +40 -0
  516. package/src/runtime/migrations/vbundle-builder.ts +133 -79
  517. package/src/runtime/migrations/vbundle-import-analyzer.ts +9 -7
  518. package/src/runtime/migrations/vbundle-importer.ts +7 -7
  519. package/src/runtime/migrations/vbundle-metadata-merge.ts +1 -1
  520. package/src/runtime/migrations/vbundle-streaming-importer.ts +3 -3
  521. package/src/runtime/migrations/vbundle-streaming-validator.ts +48 -26
  522. package/src/runtime/migrations/vbundle-validator.ts +214 -41
  523. package/src/runtime/pending-interactions.ts +13 -4
  524. package/src/runtime/routes/__tests__/acp-routes.test.ts +0 -1
  525. package/src/runtime/routes/__tests__/backup-routes.test.ts +28 -19
  526. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +235 -0
  527. package/src/runtime/routes/__tests__/llm-call-sites-routes.test.ts +58 -0
  528. package/src/runtime/routes/__tests__/migration-export-secrets-redacted.test.ts +54 -0
  529. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +19 -6
  530. package/src/runtime/routes/__tests__/user-route-dispatcher.test.ts +7 -7
  531. package/src/runtime/routes/acp-routes.test.ts +0 -3
  532. package/src/runtime/routes/acp-routes.ts +3 -7
  533. package/src/runtime/routes/app-management-routes.ts +18 -9
  534. package/src/runtime/routes/approval-routes.ts +55 -14
  535. package/src/runtime/routes/avatar-routes.ts +3 -5
  536. package/src/runtime/routes/browser-routes.ts +1 -15
  537. package/src/runtime/routes/channel-guardian-routes.ts +1 -5
  538. package/src/runtime/routes/channel-readiness-routes.ts +3 -7
  539. package/src/runtime/routes/channel-route-shared.ts +2 -28
  540. package/src/runtime/routes/client-routes.ts +45 -12
  541. package/src/runtime/routes/consolidation-routes.ts +115 -0
  542. package/src/runtime/routes/conversation-list-routes.ts +12 -29
  543. package/src/runtime/routes/conversation-management-routes.ts +14 -51
  544. package/src/runtime/routes/conversation-query-routes.ts +120 -8
  545. package/src/runtime/routes/conversation-routes.ts +44 -528
  546. package/src/runtime/routes/conversation-starter-routes.ts +19 -40
  547. package/src/runtime/routes/documents-routes.ts +53 -18
  548. package/src/runtime/routes/events-routes.ts +59 -91
  549. package/src/runtime/routes/filing-routes.ts +18 -1
  550. package/src/runtime/routes/guardian-action-routes.ts +4 -9
  551. package/src/runtime/routes/host-bash-routes.ts +3 -2
  552. package/src/runtime/routes/host-browser-routes.ts +9 -33
  553. package/src/runtime/routes/host-cu-routes.ts +6 -1
  554. package/src/runtime/routes/host-file-routes.ts +3 -2
  555. package/src/runtime/routes/host-transfer-routes.ts +11 -15
  556. package/src/runtime/routes/identity-routes.ts +78 -6
  557. package/src/runtime/routes/inbound-message-handler.ts +580 -137
  558. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +2 -88
  559. package/src/runtime/routes/inbound-stages/background-dispatch.ts +3 -0
  560. package/src/runtime/routes/index.ts +4 -0
  561. package/src/runtime/routes/integrations/slack/channel.ts +0 -24
  562. package/src/runtime/routes/llm-call-sites-routes.ts +22 -0
  563. package/src/runtime/routes/memory-v2-routes.ts +10 -15
  564. package/src/runtime/routes/migration-routes.ts +188 -31
  565. package/src/runtime/routes/playground/guard.ts +1 -1
  566. package/src/runtime/routes/playground/index.ts +0 -2
  567. package/src/runtime/routes/recording-routes.ts +4 -24
  568. package/src/runtime/routes/rename-conversation-routes.ts +2 -6
  569. package/src/runtime/routes/schedule-routes.ts +3 -6
  570. package/src/runtime/routes/secret-routes.ts +87 -18
  571. package/src/runtime/routes/settings-routes.ts +29 -28
  572. package/src/runtime/routes/skills-routes.ts +12 -31
  573. package/src/runtime/routes/suggest-trust-rule-routes.ts +32 -1
  574. package/src/runtime/routes/task-routes.ts +6 -6
  575. package/src/runtime/routes/trust-rules-routes.ts +3 -94
  576. package/src/runtime/routes/types.ts +4 -4
  577. package/src/runtime/routes/upgrade-broadcast-routes.ts +3 -10
  578. package/src/runtime/routes/usage-routes.ts +87 -10
  579. package/src/runtime/routes/user-routes.ts +17 -31
  580. package/src/runtime/routes/work-items-routes.ts +1 -4
  581. package/src/runtime/services/__tests__/analyze-conversation.test.ts +2 -2
  582. package/src/runtime/services/analyze-conversation.ts +7 -17
  583. package/src/runtime/services/conversation-serializer.ts +2 -4
  584. package/src/runtime/verification-outbound-actions.ts +1 -1
  585. package/src/runtime/verification-rate-limiter.ts +1 -1
  586. package/src/schedule/schedule-store.ts +0 -16
  587. package/src/security/secret-scanner.ts +14 -547
  588. package/src/security/secure-keys.ts +31 -11
  589. package/src/security/token-manager.ts +7 -3
  590. package/src/signals/cancel.ts +16 -25
  591. package/src/signals/conversation-undo.ts +2 -27
  592. package/src/signals/emit-event.ts +1 -2
  593. package/src/signals/user-message.ts +108 -22
  594. package/src/skills/catalog-install.ts +1 -0
  595. package/src/skills/clawhub.ts +2 -2
  596. package/src/skills/inline-command-runner.ts +1 -7
  597. package/src/subagent/manager.ts +67 -84
  598. package/src/tasks/task-store.ts +1 -28
  599. package/src/telemetry/types.ts +6 -0
  600. package/src/telemetry/usage-telemetry-reporter.test.ts +38 -15
  601. package/src/telemetry/usage-telemetry-reporter.ts +3 -5
  602. package/src/tools/acp/spawn.test.ts +1 -2
  603. package/src/tools/acp/steer.test.ts +1 -2
  604. package/src/tools/browser/__tests__/browser-status.test.ts +44 -127
  605. package/src/tools/browser/browser-execution.ts +31 -147
  606. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +92 -68
  607. package/src/tools/browser/cdp-client/factory.ts +48 -76
  608. package/src/tools/browser/cdp-client/index.ts +1 -14
  609. package/src/tools/executor.ts +44 -31
  610. package/src/tools/host-filesystem/edit.ts +3 -2
  611. package/src/tools/host-filesystem/read.ts +3 -2
  612. package/src/tools/host-filesystem/transfer.test.ts +45 -42
  613. package/src/tools/host-filesystem/transfer.ts +4 -3
  614. package/src/tools/host-filesystem/write.ts +3 -2
  615. package/src/tools/host-terminal/host-shell.ts +4 -3
  616. package/src/tools/network/script-proxy/index.ts +1 -10
  617. package/src/tools/permission-checker.ts +66 -1
  618. package/src/tools/skills/sandbox-runner.ts +1 -6
  619. package/src/tools/skills/skill-tool-factory.ts +32 -0
  620. package/src/tools/terminal/safe-env.ts +1 -0
  621. package/src/tools/terminal/shell.ts +2 -78
  622. package/src/tools/types.ts +12 -39
  623. package/src/tts/__tests__/provider-catalog.test.ts +2 -2
  624. package/src/tts/provider-catalog.ts +1 -1
  625. package/src/usage/actors.ts +2 -1
  626. package/src/usage/attribution.ts +185 -0
  627. package/src/usage/pricing.ts +166 -0
  628. package/src/usage/types.ts +14 -0
  629. package/src/util/json.ts +13 -0
  630. package/src/util/logger.ts +3 -3
  631. package/src/util/pricing.ts +50 -3
  632. package/src/work-items/work-item-runner.ts +15 -42
  633. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +4 -3
  634. package/src/workspace/migrations/052-seed-default-inference-profiles.ts +3 -3
  635. package/src/workspace/migrations/060-memory-v2-init.ts +2 -18
  636. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +59 -0
  637. package/src/workspace/migrations/062-drop-memory-v2-edges-json.ts +27 -0
  638. package/src/workspace/migrations/063-release-notes-dynamic-model-context.ts +70 -0
  639. package/src/workspace/migrations/064-unwind-main-agent-opus-seed.ts +64 -0
  640. package/src/workspace/migrations/registry.ts +8 -0
  641. package/src/workspace/provider-commit-message-generator.ts +3 -3
  642. package/src/__tests__/sandbox-diagnostics.test.ts +0 -138
  643. package/src/__tests__/sandbox-host-parity.test.ts +0 -1024
  644. package/src/__tests__/secret-detection-handler.test.ts +0 -67
  645. package/src/__tests__/secret-scanner-executor.test.ts +0 -450
  646. package/src/__tests__/tcc-sandbox-deny.test.ts +0 -198
  647. package/src/__tests__/terminal-sandbox.test.ts +0 -374
  648. package/src/__tests__/tool-notification-listener.test.ts +0 -65
  649. package/src/context/__tests__/microcompact.test.ts +0 -805
  650. package/src/context/microcompact.ts +0 -443
  651. package/src/daemon/handlers/slack-channel-oauth-install.ts +0 -197
  652. package/src/events/tool-notification-listener.ts +0 -17
  653. package/src/ipc/routes/__tests__/memory-v2-validate.test.ts +0 -219
  654. package/src/memory/v2/__tests__/edges.test.ts +0 -435
  655. package/src/memory/v2/edges.ts +0 -217
  656. package/src/prompts/__tests__/system-prompt-memory-v2.test.ts +0 -197
  657. package/src/runtime/__tests__/chrome-extension-registry.test.ts +0 -518
  658. package/src/runtime/__tests__/client-registry.test.ts +0 -271
  659. package/src/runtime/chrome-extension-registry.ts +0 -368
  660. package/src/runtime/client-registry.ts +0 -254
  661. package/src/runtime/routes/inbound-stages/verification-intercept.ts +0 -329
  662. package/src/tools/secret-detection-handler.ts +0 -269
  663. package/src/tools/terminal/backends/native.ts +0 -327
  664. package/src/tools/terminal/backends/types.ts +0 -37
  665. package/src/tools/terminal/sandbox-diagnostics.ts +0 -87
  666. package/src/tools/terminal/sandbox.ts +0 -40
@@ -55,11 +55,11 @@ mock.module("../runtime/gateway-client.js", () => ({
55
55
  },
56
56
  }));
57
57
 
58
- import { createGuardianBinding } from "../contacts/contacts-write.js";
59
58
  import { getDb } from "../memory/db-connection.js";
60
59
  import { initializeDb } from "../memory/db-init.js";
61
60
  import { findActiveSession } from "../runtime/channel-verification-service.js";
62
61
  import { handleChannelInbound } from "./helpers/channel-test-adapter.js";
62
+ import { createGuardianBinding } from "./helpers/create-guardian-binding.js";
63
63
 
64
64
  initializeDb();
65
65
 
@@ -257,65 +257,4 @@ describe("Slack inbound trusted contact verification", () => {
257
257
  // No Slack DM was sent
258
258
  });
259
259
 
260
- test("user can verify by replying with the code in the DM", async () => {
261
- // Step 1: Unknown user sends a message, gets verification challenge
262
- const req = buildSlackInboundRequest();
263
- await handleChannelInbound(req, undefined, TEST_BEARER_TOKEN);
264
-
265
- const session = findActiveSession("slack");
266
- expect(session).not.toBeNull();
267
-
268
- // The challenge hash is stored in the session — extract the secret
269
- // from the DM text sent to the user. The code is embedded in the
270
- // template text. Since we're using a 6-digit code for identity-bound
271
- // sessions, extract it from the session's challengeHash by consuming
272
- // the challenge directly.
273
- // The session was created with createOutboundSession which generates
274
- // a 6-digit code. We can validate by calling validateAndConsumeVerification
275
- // with the correct secret. Since the mock captures the DM text, we
276
- // can extract the code indirectly. But for testing, we just verify
277
- // the session properties and that validateAndConsumeVerification works
278
- // with the correct identity.
279
-
280
- // The actual secret was sent in the DM. For this test, let's use the
281
- // session directly via the channel-verification-service to verify the
282
- // consume path works.
283
- // The DM text contains the verification code implicitly (it's in the
284
- // template message). Since we need to test the full round-trip, let's
285
- // verify via the inbound handler by sending the code as a message.
286
-
287
- // Extract the session's challenge hash and verify that submitting the
288
- // correct code works. We create a fresh session with a known secret for
289
- // this part of the test.
290
- resetState();
291
-
292
- // Create a verification session manually to test the consume path
293
- const { createOutboundSession } =
294
- await import("../runtime/channel-verification-service.js");
295
-
296
- const outboundSession = createOutboundSession({
297
- channel: "slack",
298
- expectedExternalUserId: "U0123UNKNOWN",
299
- expectedChatId: "U0123UNKNOWN",
300
- identityBindingStatus: "bound",
301
- destinationAddress: "U0123UNKNOWN",
302
- verificationPurpose: "trusted_contact",
303
- });
304
-
305
- // User replies with the code in the DM
306
- const verifyReq = buildSlackInboundRequest({
307
- conversationExternalId: "U0123UNKNOWN",
308
- content: outboundSession.secret,
309
- externalMessageId: `msg-verify-${Date.now()}`,
310
- });
311
- const verifyResp = await handleChannelInbound(
312
- verifyReq,
313
- undefined,
314
- TEST_BEARER_TOKEN,
315
- );
316
- const verifyJson = (await verifyResp.json()) as Record<string, unknown>;
317
-
318
- expect(verifyJson.accepted).toBe(true);
319
- expect(verifyJson.verificationOutcome).toBe("verified");
320
- });
321
260
  });
@@ -1,4 +1,35 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ // ── Module mocks ──────────────────────────────────────────────────
4
+
5
+ /**
6
+ * Captured messages from injectMessageIntoParent → findConversation → enqueueMessage.
7
+ * Each test clears this before use.
8
+ */
9
+ const capturedNotifications: {
10
+ parentConversationId: string;
11
+ message: string;
12
+ }[] = [];
13
+
14
+ mock.module("../daemon/conversation-store.js", () => ({
15
+ findConversation: (id: string) => ({
16
+ enqueueMessage: (content: string) => {
17
+ capturedNotifications.push({
18
+ parentConversationId: id,
19
+ message: content,
20
+ });
21
+ return { queued: true };
22
+ },
23
+ persistUserMessage: async () => "mock-msg",
24
+ runAgentLoop: async () => {},
25
+ }),
26
+ addConversation: () => {},
27
+ removeConversation: () => {},
28
+ }));
29
+
30
+ mock.module("../runtime/assistant-event-hub.js", () => ({
31
+ broadcastMessage: () => {},
32
+ }));
2
33
 
3
34
  import type { ServerMessage } from "../daemon/message-protocol.js";
4
35
  import { SubagentManager } from "../subagent/manager.js";
@@ -108,8 +139,13 @@ function makeForkState(
108
139
  });
109
140
  }
110
141
 
142
+ function clearCaptured(): void {
143
+ capturedNotifications.length = 0;
144
+ }
145
+
111
146
  describe("Fork completion notifications", () => {
112
147
  test("fork completion notification includes last_n: 1 guidance", async () => {
148
+ clearCaptured();
113
149
  const manager = new SubagentManager();
114
150
  const subagentId = "fork-1";
115
151
  const state = makeForkState(subagentId);
@@ -119,21 +155,16 @@ describe("Fork completion notifications", () => {
119
155
  managed.conversation!.persistUserMessage = () => "msg-1";
120
156
  managed.conversation!.runAgentLoop = async () => {};
121
157
 
122
- const notifications: { parentConversationId: string; message: string }[] =
123
- [];
124
- manager.onSubagentFinished = (parentConversationId, message) => {
125
- notifications.push({ parentConversationId, message });
126
- };
127
-
128
158
  await asInternals(manager).runSubagent(subagentId, "Analyze data");
129
159
 
130
- expect(notifications).toHaveLength(1);
131
- expect(notifications[0].message).toContain("last_n: 1");
160
+ expect(capturedNotifications).toHaveLength(1);
161
+ expect(capturedNotifications[0].message).toContain("last_n: 1");
132
162
 
133
163
  asInternals(manager).stopSweep();
134
164
  });
135
165
 
136
166
  test("fork completion notification includes internal-processing instruction", async () => {
167
+ clearCaptured();
137
168
  const manager = new SubagentManager();
138
169
  const subagentId = "fork-1";
139
170
  const state = makeForkState(subagentId);
@@ -143,19 +174,13 @@ describe("Fork completion notifications", () => {
143
174
  managed.conversation!.persistUserMessage = () => "msg-1";
144
175
  managed.conversation!.runAgentLoop = async () => {};
145
176
 
146
- const notifications: { parentConversationId: string; message: string }[] =
147
- [];
148
- manager.onSubagentFinished = (parentConversationId, message) => {
149
- notifications.push({ parentConversationId, message });
150
- };
151
-
152
177
  await asInternals(manager).runSubagent(subagentId, "Analyze data");
153
178
 
154
- expect(notifications).toHaveLength(1);
155
- expect(notifications[0].message).toContain(
179
+ expect(capturedNotifications).toHaveLength(1);
180
+ expect(capturedNotifications[0].message).toContain(
156
181
  "do NOT share raw fork output with the user",
157
182
  );
158
- expect(notifications[0].message).toContain(
183
+ expect(capturedNotifications[0].message).toContain(
159
184
  '[Fork "Analysis fork" completed]',
160
185
  );
161
186
 
@@ -163,6 +188,7 @@ describe("Fork completion notifications", () => {
163
188
  });
164
189
 
165
190
  test("fork failure notification uses [Fork prefix", async () => {
191
+ clearCaptured();
166
192
  const manager = new SubagentManager();
167
193
  const subagentId = "fork-1";
168
194
  const state = makeForkState(subagentId);
@@ -174,20 +200,14 @@ describe("Fork completion notifications", () => {
174
200
  throw new Error("Context too large");
175
201
  };
176
202
 
177
- const notifications: { parentConversationId: string; message: string }[] =
178
- [];
179
- manager.onSubagentFinished = (parentConversationId, message) => {
180
- notifications.push({ parentConversationId, message });
181
- };
182
-
183
203
  await asInternals(manager).runSubagent(subagentId, "Analyze data");
184
204
 
185
- expect(notifications).toHaveLength(1);
186
- expect(notifications[0].message).toContain(
205
+ expect(capturedNotifications).toHaveLength(1);
206
+ expect(capturedNotifications[0].message).toContain(
187
207
  '[Fork "Analysis fork" failed]',
188
208
  );
189
- expect(notifications[0].message).toContain("Context too large");
190
- expect(notifications[0].message).not.toContain("[Subagent");
209
+ expect(capturedNotifications[0].message).toContain("Context too large");
210
+ expect(capturedNotifications[0].message).not.toContain("[Subagent");
191
211
 
192
212
  asInternals(manager).stopSweep();
193
213
  });
@@ -233,6 +253,7 @@ describe("Status response includes isFork", () => {
233
253
 
234
254
  describe("Regular sub-agent notifications are unchanged", () => {
235
255
  test("regular completed subagent uses [Subagent prefix", async () => {
256
+ clearCaptured();
236
257
  const manager = new SubagentManager();
237
258
  const subagentId = "sub-1";
238
259
  const state = makeState(subagentId);
@@ -242,25 +263,20 @@ describe("Regular sub-agent notifications are unchanged", () => {
242
263
  managed.conversation!.persistUserMessage = () => "msg-1";
243
264
  managed.conversation!.runAgentLoop = async () => {};
244
265
 
245
- const notifications: { parentConversationId: string; message: string }[] =
246
- [];
247
- manager.onSubagentFinished = (parentConversationId, message) => {
248
- notifications.push({ parentConversationId, message });
249
- };
250
-
251
266
  await asInternals(manager).runSubagent(subagentId, "Do something");
252
267
 
253
- expect(notifications).toHaveLength(1);
254
- expect(notifications[0].message).toContain(
268
+ expect(capturedNotifications).toHaveLength(1);
269
+ expect(capturedNotifications[0].message).toContain(
255
270
  '[Subagent "Test subagent" completed]',
256
271
  );
257
- expect(notifications[0].message).not.toContain("[Fork");
258
- expect(notifications[0].message).not.toContain("last_n: 1");
272
+ expect(capturedNotifications[0].message).not.toContain("[Fork");
273
+ expect(capturedNotifications[0].message).not.toContain("last_n: 1");
259
274
 
260
275
  asInternals(manager).stopSweep();
261
276
  });
262
277
 
263
278
  test("regular failed subagent uses [Subagent prefix", async () => {
279
+ clearCaptured();
264
280
  const manager = new SubagentManager();
265
281
  const subagentId = "sub-1";
266
282
  const state = makeState(subagentId);
@@ -272,19 +288,13 @@ describe("Regular sub-agent notifications are unchanged", () => {
272
288
  throw new Error("Something went wrong");
273
289
  };
274
290
 
275
- const notifications: { parentConversationId: string; message: string }[] =
276
- [];
277
- manager.onSubagentFinished = (parentConversationId, message) => {
278
- notifications.push({ parentConversationId, message });
279
- };
280
-
281
291
  await asInternals(manager).runSubagent(subagentId, "Do something");
282
292
 
283
- expect(notifications).toHaveLength(1);
284
- expect(notifications[0].message).toContain(
293
+ expect(capturedNotifications).toHaveLength(1);
294
+ expect(capturedNotifications[0].message).toContain(
285
295
  '[Subagent "Test subagent" failed]',
286
296
  );
287
- expect(notifications[0].message).not.toContain("[Fork");
297
+ expect(capturedNotifications[0].message).not.toContain("[Fork");
288
298
 
289
299
  asInternals(manager).stopSweep();
290
300
  });
@@ -1,4 +1,35 @@
1
- import { describe, expect, test } from "bun:test";
1
+ import { describe, expect, mock, test } from "bun:test";
2
+
3
+ // ── Module mocks ──────────────────────────────────────────────────
4
+
5
+ /**
6
+ * Captured messages from injectMessageIntoParent → findConversation → enqueueMessage.
7
+ * Each test clears this before use.
8
+ */
9
+ const capturedNotifications: {
10
+ parentConversationId: string;
11
+ message: string;
12
+ }[] = [];
13
+
14
+ mock.module("../daemon/conversation-store.js", () => ({
15
+ findConversation: (id: string) => ({
16
+ enqueueMessage: (content: string) => {
17
+ capturedNotifications.push({
18
+ parentConversationId: id,
19
+ message: content,
20
+ });
21
+ return { queued: true };
22
+ },
23
+ persistUserMessage: async () => "mock-msg",
24
+ runAgentLoop: async () => {},
25
+ }),
26
+ addConversation: () => {},
27
+ removeConversation: () => {},
28
+ }));
29
+
30
+ mock.module("../runtime/assistant-event-hub.js", () => ({
31
+ broadcastMessage: () => {},
32
+ }));
2
33
 
3
34
  import type { ServerMessage } from "../daemon/message-protocol.js";
4
35
  import { SubagentManager } from "../subagent/manager.js";
@@ -94,19 +125,18 @@ function makeState(
94
125
  };
95
126
  }
96
127
 
128
+ function clearCaptured(): void {
129
+ capturedNotifications.length = 0;
130
+ }
131
+
97
132
  describe("SubagentManager abort notification", () => {
98
133
  test("abort notifies parent with do-not-respawn message", () => {
134
+ clearCaptured();
99
135
  const manager = new SubagentManager();
100
136
  const subagentId = "sub-1";
101
137
  const state = makeState(subagentId);
102
138
  injectFakeSubagent(manager, subagentId, state);
103
139
 
104
- const notifications: { parentConversationId: string; message: string }[] =
105
- [];
106
- manager.onSubagentFinished = (parentConversationId, message) => {
107
- notifications.push({ parentConversationId, message });
108
- };
109
-
110
140
  const clientMessages: ServerMessage[] = [];
111
141
  const sendToClient = (msg: ServerMessage) => clientMessages.push(msg);
112
142
 
@@ -114,21 +144,16 @@ describe("SubagentManager abort notification", () => {
114
144
 
115
145
  expect(result).toBe(true);
116
146
  expect(state.status).toBe("aborted");
117
- expect(notifications).toHaveLength(1);
118
- expect(notifications[0].message).toContain("explicitly aborted");
119
- expect(notifications[0].message).toContain("Do NOT re-spawn");
147
+ expect(capturedNotifications).toHaveLength(1);
148
+ expect(capturedNotifications[0].message).toContain("explicitly aborted");
149
+ expect(capturedNotifications[0].message).toContain("Do NOT re-spawn");
120
150
  });
121
151
 
122
- test("abort notification routes to parent sender, not aborting sender", () => {
152
+ test("abort notification goes to parent conversation via findConversation", () => {
153
+ clearCaptured();
123
154
  const manager = new SubagentManager();
124
155
  const subagentId = "sub-1";
125
- const state = makeState(subagentId);
126
-
127
- // Track which sender onSubagentFinished receives.
128
- let notificationSender: unknown = null;
129
- manager.onSubagentFinished = (_pid, _message, sender) => {
130
- notificationSender = sender;
131
- };
156
+ const state = makeState(subagentId); // parentConversationId = 'parent-sess-1'
132
157
 
133
158
  // The parent's stored sender (set at spawn time).
134
159
  const parentSender = () => {};
@@ -141,9 +166,9 @@ describe("SubagentManager abort notification", () => {
141
166
 
142
167
  manager.abort(subagentId, abortingSender);
143
168
 
144
- // onSubagentFinished should receive the parent's sender, not the aborting one.
145
- expect(notificationSender).toBe(parentSender);
146
- expect(notificationSender).not.toBe(abortingSender);
169
+ // Notification should be routed to the parent conversation via findConversation.
170
+ expect(capturedNotifications).toHaveLength(1);
171
+ expect(capturedNotifications[0].parentConversationId).toBe("parent-sess-1");
147
172
  });
148
173
 
149
174
  test("abort sends subagent_status_changed to client", () => {
@@ -195,21 +220,18 @@ describe("SubagentManager abort notification", () => {
195
220
  });
196
221
 
197
222
  test("abort without sendToClient sets status but does not notify", () => {
223
+ clearCaptured();
198
224
  const manager = new SubagentManager();
199
225
  const subagentId = "sub-1";
200
226
  const state = makeState(subagentId);
201
227
  injectFakeSubagent(manager, subagentId, state);
202
228
 
203
- let notified = false;
204
- manager.onSubagentFinished = () => {
205
- notified = true;
206
- };
207
-
208
229
  const result = manager.abort(subagentId);
209
230
 
210
231
  expect(result).toBe(true);
211
232
  expect(state.status).toBe("aborted");
212
- expect(notified).toBe(false);
233
+ // Without parentSendToClient, abort skips both the status update and notification.
234
+ expect(capturedNotifications).toHaveLength(0);
213
235
  });
214
236
 
215
237
  test("abort rejects when callerConversationId does not match parent", () => {
@@ -249,27 +271,26 @@ describe("SubagentManager abort notification", () => {
249
271
  expect(state.status).toBe("aborted");
250
272
  });
251
273
 
252
- test("abort with suppressNotification skips onSubagentFinished", () => {
274
+ test("abort with suppressNotification skips parent notification", () => {
275
+ clearCaptured();
253
276
  const manager = new SubagentManager();
254
277
  const subagentId = "sub-1";
255
278
  const state = makeState(subagentId);
256
279
  injectFakeSubagent(manager, subagentId, state);
257
280
 
258
- const notifications: string[] = [];
259
- manager.onSubagentFinished = (_pid, message) => notifications.push(message);
260
-
261
281
  const result = manager.abort(subagentId, () => {}, undefined, {
262
282
  suppressNotification: true,
263
283
  });
264
284
 
265
285
  expect(result).toBe(true);
266
286
  expect(state.status).toBe("aborted");
267
- expect(notifications).toHaveLength(0);
287
+ expect(capturedNotifications).toHaveLength(0);
268
288
  });
269
289
  });
270
290
 
271
291
  describe("SubagentManager notifyParent (via runSubagent)", () => {
272
292
  test("completed subagent notifies parent to use subagent_read", async () => {
293
+ clearCaptured();
273
294
  const manager = new SubagentManager();
274
295
  const subagentId = "sub-1";
275
296
  const state = makeState(subagentId);
@@ -280,12 +301,6 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
280
301
  managed.conversation!.persistUserMessage = () => "msg-1";
281
302
  managed.conversation!.runAgentLoop = async () => {};
282
303
 
283
- const notifications: { parentConversationId: string; message: string }[] =
284
- [];
285
- manager.onSubagentFinished = (parentConversationId, message) => {
286
- notifications.push({ parentConversationId, message });
287
- };
288
-
289
304
  await asInternals(manager).runSubagent(subagentId, "Do something");
290
305
 
291
306
  expect(state.status).toBe("completed");
@@ -294,17 +309,18 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
294
309
  outputTokens: 50,
295
310
  estimatedCost: 0.005,
296
311
  });
297
- expect(notifications).toHaveLength(1);
298
- expect(notifications[0].parentConversationId).toBe("parent-sess-1");
299
- expect(notifications[0].message).toContain(
312
+ expect(capturedNotifications).toHaveLength(1);
313
+ expect(capturedNotifications[0].parentConversationId).toBe("parent-sess-1");
314
+ expect(capturedNotifications[0].message).toContain(
300
315
  '[Subagent "Test subagent" completed]',
301
316
  );
302
- expect(notifications[0].message).toContain("subagent_read");
317
+ expect(capturedNotifications[0].message).toContain("subagent_read");
303
318
 
304
319
  asInternals(manager).stopSweep();
305
320
  });
306
321
 
307
322
  test("failed subagent notifies parent with error and asks user before retry", async () => {
323
+ clearCaptured();
308
324
  const manager = new SubagentManager();
309
325
  const subagentId = "sub-1";
310
326
  const state = makeState(subagentId);
@@ -318,12 +334,6 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
318
334
  throw new Error("API rate limit exceeded");
319
335
  };
320
336
 
321
- const notifications: { parentConversationId: string; message: string }[] =
322
- [];
323
- manager.onSubagentFinished = (parentConversationId, message) => {
324
- notifications.push({ parentConversationId, message });
325
- };
326
-
327
337
  await asInternals(manager).runSubagent(subagentId, "Do something");
328
338
 
329
339
  expect(state.status).toBe("failed");
@@ -333,15 +343,18 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
333
343
  outputTokens: 50,
334
344
  estimatedCost: 0.005,
335
345
  });
336
- expect(notifications).toHaveLength(1);
337
- expect(notifications[0].message).toContain("failed");
338
- expect(notifications[0].message).toContain("API rate limit exceeded");
339
- expect(notifications[0].message).toContain("Do NOT re-spawn");
346
+ expect(capturedNotifications).toHaveLength(1);
347
+ expect(capturedNotifications[0].message).toContain("failed");
348
+ expect(capturedNotifications[0].message).toContain(
349
+ "API rate limit exceeded",
350
+ );
351
+ expect(capturedNotifications[0].message).toContain("Do NOT re-spawn");
340
352
 
341
353
  asInternals(manager).stopSweep();
342
354
  });
343
355
 
344
356
  test("failed subagent does not notify if already aborted", async () => {
357
+ clearCaptured();
345
358
  const manager = new SubagentManager();
346
359
  const subagentId = "sub-1";
347
360
  const state = makeState(subagentId, { status: "aborted" });
@@ -354,16 +367,10 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
354
367
  throw new Error("Conversation aborted");
355
368
  };
356
369
 
357
- const notifications: { parentConversationId: string; message: string }[] =
358
- [];
359
- manager.onSubagentFinished = (parentConversationId, message) => {
360
- notifications.push({ parentConversationId, message });
361
- };
362
-
363
370
  await asInternals(manager).runSubagent(subagentId, "Do something");
364
371
 
365
372
  // Should NOT notify — status was already terminal (aborted).
366
- expect(notifications).toHaveLength(0);
373
+ expect(capturedNotifications).toHaveLength(0);
367
374
 
368
375
  asInternals(manager).stopSweep();
369
376
  });
@@ -371,6 +378,7 @@ describe("SubagentManager notifyParent (via runSubagent)", () => {
371
378
 
372
379
  describe("SubagentManager abortAllForParent", () => {
373
380
  test("aborts all active children of a parent", () => {
381
+ clearCaptured();
374
382
  const manager = new SubagentManager();
375
383
  injectFakeSubagent(manager, "sub-1", makeState("sub-1"));
376
384
  injectFakeSubagent(manager, "sub-2", makeState("sub-2"));
@@ -380,13 +388,10 @@ describe("SubagentManager abortAllForParent", () => {
380
388
  makeState("sub-3", { status: "completed" }),
381
389
  );
382
390
 
383
- const notifications: string[] = [];
384
- manager.onSubagentFinished = (_pid, message) => notifications.push(message);
385
-
386
391
  const count = manager.abortAllForParent("parent-sess-1", () => {});
387
392
 
388
393
  expect(count).toBe(2); // sub-1 and sub-2, not sub-3 (already completed)
389
- expect(notifications).toHaveLength(2);
394
+ expect(capturedNotifications).toHaveLength(2);
390
395
 
391
396
  // All children should be disposed — parent is going away.
392
397
  expect(manager.getState("sub-1")).toBeUndefined();
@@ -422,6 +427,7 @@ describe("SubagentManager sharedRequestTimestamps", () => {
422
427
 
423
428
  describe("SubagentManager abort race guard", () => {
424
429
  test("completed subagent does not notify if already aborted", async () => {
430
+ clearCaptured();
425
431
  const manager = new SubagentManager();
426
432
  const subagentId = "sub-1";
427
433
  const state = makeState(subagentId, { status: "aborted" });
@@ -436,16 +442,10 @@ describe("SubagentManager abort race guard", () => {
436
442
  { role: "assistant", content: [{ type: "text", text: "Done!" }] },
437
443
  ];
438
444
 
439
- const notifications: { parentConversationId: string; message: string }[] =
440
- [];
441
- manager.onSubagentFinished = (parentConversationId, message) => {
442
- notifications.push({ parentConversationId, message });
443
- };
444
-
445
445
  await asInternals(manager).runSubagent(subagentId, "Do something");
446
446
 
447
447
  // Should NOT notify — status was already terminal (aborted) when loop finished.
448
- expect(notifications).toHaveLength(0);
448
+ expect(capturedNotifications).toHaveLength(0);
449
449
  // Status should remain aborted, not overwritten to completed.
450
450
  expect(state.status).toBe("aborted");
451
451