@vellumai/assistant 0.7.1 → 0.7.3

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 (739) hide show
  1. package/ARCHITECTURE.md +48 -50
  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/memory.md +5 -2
  7. package/docs/architecture/security.md +20 -0
  8. package/docs/plugins.md +7 -9
  9. package/knip.json +1 -0
  10. package/node_modules/@vellumai/gateway-client/src/index.ts +1 -0
  11. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +52 -5
  12. package/node_modules/@vellumai/gateway-client/src/types.ts +11 -0
  13. package/node_modules/@vellumai/service-contracts/package.json +2 -0
  14. package/node_modules/@vellumai/service-contracts/src/__tests__/contracts.test.ts +4 -0
  15. package/node_modules/@vellumai/service-contracts/src/__tests__/ingress.test.ts +107 -0
  16. package/node_modules/@vellumai/service-contracts/src/index.ts +5 -1
  17. package/node_modules/@vellumai/service-contracts/src/ingress.ts +24 -0
  18. package/node_modules/@vellumai/service-contracts/src/twilio-ingress.ts +84 -0
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  20. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  21. package/node_modules/@vellumai/twilio-client/bun.lock +24 -0
  22. package/node_modules/@vellumai/twilio-client/package.json +18 -0
  23. package/node_modules/@vellumai/twilio-client/src/__tests__/twilio-client.test.ts +128 -0
  24. package/node_modules/@vellumai/twilio-client/src/index.ts +179 -0
  25. package/node_modules/@vellumai/twilio-client/tsconfig.json +20 -0
  26. package/openapi.yaml +1020 -40
  27. package/package.json +6 -3
  28. package/src/__tests__/app-builder-tool-scripts.test.ts +3 -3
  29. package/src/__tests__/app-bundler.test.ts +170 -1
  30. package/src/__tests__/app-control-flow.test.ts +384 -0
  31. package/src/__tests__/app-control-no-global-cgevent.test.ts +98 -0
  32. package/src/__tests__/app-control-tool-schemas.test.ts +621 -0
  33. package/src/__tests__/app-executors.test.ts +30 -43
  34. package/src/__tests__/approval-routes-http.test.ts +23 -6
  35. package/src/__tests__/assistant-event-hub-machine-name.test.ts +146 -0
  36. package/src/__tests__/assistant-event-hub-targeted.test.ts +257 -0
  37. package/src/__tests__/assistant-event-hub.test.ts +157 -2
  38. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -7
  39. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  40. package/src/__tests__/background-shell-host-bash.test.ts +14 -15
  41. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  42. package/src/__tests__/bootstrap-turn-cleanup.test.ts +44 -0
  43. package/src/__tests__/btw-routes.test.ts +13 -4
  44. package/src/__tests__/call-controller.test.ts +49 -1
  45. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  46. package/src/__tests__/call-domain.test.ts +0 -2
  47. package/src/__tests__/call-routes-http.test.ts +0 -2
  48. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  49. package/src/__tests__/channel-readiness-service.test.ts +62 -2
  50. package/src/__tests__/checker.test.ts +3 -4
  51. package/src/__tests__/config-loader-backfill.test.ts +461 -147
  52. package/src/__tests__/config-loader-platform-defaults.test.ts +196 -0
  53. package/src/__tests__/config-schema-cmd.test.ts +0 -1
  54. package/src/__tests__/config-schema.test.ts +1 -0
  55. package/src/__tests__/config-set-platform-guard.test.ts +48 -4
  56. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +20 -11
  57. package/src/__tests__/config-watcher.test.ts +142 -71
  58. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  59. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  60. package/src/__tests__/context-search-fanout.test.ts +0 -1
  61. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  62. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  63. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  64. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  65. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  66. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  67. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  68. package/src/__tests__/conversation-app-control-instantiation.test.ts +392 -0
  69. package/src/__tests__/conversation-app-control-lifecycle.test.ts +237 -0
  70. package/src/__tests__/conversation-error.test.ts +150 -3
  71. package/src/__tests__/conversation-init.benchmark.test.ts +0 -2
  72. package/src/__tests__/conversation-lifecycle.test.ts +36 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +283 -0
  74. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  76. package/src/__tests__/conversation-routes-disk-view.test.ts +6 -0
  77. package/src/__tests__/conversation-routes-guardian-reply.test.ts +120 -72
  78. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  79. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  80. package/src/__tests__/conversation-slash-commands.test.ts +0 -4
  81. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  82. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  83. package/src/__tests__/conversation-store.test.ts +0 -18
  84. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +202 -0
  85. package/src/__tests__/conversation-surfaces-app-control.test.ts +328 -0
  86. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  87. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  88. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  89. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  90. package/src/__tests__/credential-execution-feature-gates.test.ts +5 -12
  91. package/src/__tests__/credential-execution-managed-contract.test.ts +3 -131
  92. package/src/__tests__/credentials-cli.test.ts +12 -12
  93. package/src/__tests__/cu-unified-flow.test.ts +351 -23
  94. package/src/__tests__/daemon-credential-client.test.ts +101 -19
  95. package/src/__tests__/date-context.test.ts +164 -2
  96. package/src/__tests__/db-schedule-syntax-migration.test.ts +2 -0
  97. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  98. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  99. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  100. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  101. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  102. package/src/__tests__/disk-usage.test.ts +150 -0
  103. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  104. package/src/__tests__/events-client-registration.test.ts +52 -0
  105. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  106. package/src/__tests__/file-write-tool.test.ts +4 -10
  107. package/src/__tests__/filing-service.test.ts +3 -4
  108. package/src/__tests__/gateway-only-enforcement.test.ts +0 -1
  109. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -2
  110. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -2
  111. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +0 -1
  112. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  113. package/src/__tests__/heartbeat-service.test.ts +968 -2
  114. package/src/__tests__/helpers/call-route-handler.ts +7 -1
  115. package/src/__tests__/host-app-control-proxy.test.ts +772 -0
  116. package/src/__tests__/host-app-control-routes.test.ts +263 -0
  117. package/src/__tests__/host-bash-proxy.test.ts +439 -47
  118. package/src/__tests__/host-bash-routes.test.ts +459 -0
  119. package/src/__tests__/host-browser-proxy.test.ts +24 -22
  120. package/src/__tests__/host-browser-routes.test.ts +39 -13
  121. package/src/__tests__/host-cu-proxy.test.ts +248 -52
  122. package/src/__tests__/host-cu-routes-targeted.test.ts +429 -0
  123. package/src/__tests__/host-file-edit-tool.test.ts +47 -1
  124. package/src/__tests__/host-file-proxy-targeted.test.ts +378 -0
  125. package/src/__tests__/host-file-proxy.test.ts +301 -45
  126. package/src/__tests__/host-file-read-tool.test.ts +17 -0
  127. package/src/__tests__/host-file-routes-targeted.test.ts +420 -0
  128. package/src/__tests__/host-file-write-tool.test.ts +42 -1
  129. package/src/__tests__/host-proxy-base.test.ts +312 -0
  130. package/src/__tests__/host-shell-tool.test.ts +22 -4
  131. package/src/__tests__/host-transfer-proxy-targeted.test.ts +932 -0
  132. package/src/__tests__/host-transfer-proxy.test.ts +121 -22
  133. package/src/__tests__/host-transfer-routes-targeted.test.ts +662 -0
  134. package/src/__tests__/http-user-message-parity.test.ts +108 -1
  135. package/src/__tests__/identity-intro-cache.test.ts +29 -0
  136. package/src/__tests__/identity-routes.test.ts +103 -1
  137. package/src/__tests__/init-feature-flag-overrides.test.ts +26 -3
  138. package/src/__tests__/injector-chain.test.ts +18 -6
  139. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  140. package/src/__tests__/inline-command-runner.test.ts +0 -1
  141. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -11
  142. package/src/__tests__/integration-status.test.ts +85 -5
  143. package/src/__tests__/intent-routing.test.ts +0 -1
  144. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +95 -5
  145. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +17 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +0 -1
  148. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  149. package/src/__tests__/mcp-auth-routes.test.ts +197 -0
  150. package/src/__tests__/mcp-cli.test.ts +338 -2
  151. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  152. package/src/__tests__/memory-jobs-worker-lanes.test.ts +188 -0
  153. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  154. package/src/__tests__/migration-import-commit-http.test.ts +108 -2
  155. package/src/__tests__/mock-gateway-ipc.ts +1 -0
  156. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  157. package/src/__tests__/oauth-cli.test.ts +0 -2
  158. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  159. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  160. package/src/__tests__/oauth2-gateway-transport.test.ts +0 -1
  161. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  162. package/src/__tests__/openai-provider.test.ts +45 -8
  163. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  164. package/src/__tests__/persistence-secret-redaction.test.ts +299 -0
  165. package/src/__tests__/platform-bash-auto-approve.test.ts +5 -9
  166. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  167. package/src/__tests__/platform.test.ts +2 -1
  168. package/src/__tests__/playbook-execution.test.ts +0 -43
  169. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  170. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -25
  171. package/src/__tests__/process-message-background-slack.test.ts +2 -0
  172. package/src/__tests__/provider-commit-message-generator.test.ts +0 -1
  173. package/src/__tests__/provider-tool-name.test.ts +23 -0
  174. package/src/__tests__/public-ingress-urls.test.ts +97 -0
  175. package/src/__tests__/relay-server.test.ts +15 -4
  176. package/src/__tests__/require-fresh-approval.test.ts +0 -1
  177. package/src/__tests__/retry-backoff.test.ts +87 -0
  178. package/src/__tests__/runtime-events-sse.test.ts +2 -2
  179. package/src/__tests__/sanitize-config-for-transfer.test.ts +24 -2
  180. package/src/__tests__/schedule-retry.test.ts +715 -0
  181. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  182. package/src/__tests__/script-proxy-mitm-handler.test.ts +1 -1
  183. package/src/__tests__/secret-ingress-http.test.ts +1 -1
  184. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  185. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -1
  186. package/src/__tests__/skill-feature-flags.test.ts +43 -41
  187. package/src/__tests__/skill-load-feature-flag.test.ts +13 -14
  188. package/src/__tests__/skill-load-inline-command.test.ts +0 -51
  189. package/src/__tests__/skill-load-inline-includes.test.ts +0 -43
  190. package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
  191. package/src/__tests__/skill-script-runner-sandbox.test.ts +0 -1
  192. package/src/__tests__/slack-channel-config.test.ts +9 -14
  193. package/src/__tests__/suggestion-routes.test.ts +46 -0
  194. package/src/__tests__/system-prompt-ask-mode.test.ts +0 -1
  195. package/src/__tests__/system-prompt.test.ts +0 -1
  196. package/src/__tests__/telegram-config.test.ts +0 -1
  197. package/src/__tests__/test-preload.ts +8 -0
  198. package/src/__tests__/tool-approval-handler.test.ts +3 -4
  199. package/src/__tests__/tool-audit-listener.test.ts +48 -0
  200. package/src/__tests__/tool-execute-pipeline.test.ts +0 -1
  201. package/src/__tests__/tool-execution-abort-cleanup.test.ts +0 -1
  202. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -1
  203. package/src/__tests__/tool-executor.test.ts +0 -1
  204. package/src/__tests__/twilio-config.test.ts +3 -16
  205. package/src/__tests__/twilio-routes.test.ts +3 -5
  206. package/src/__tests__/twilio-validation.test.ts +93 -0
  207. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -4
  208. package/src/__tests__/verification-control-plane-policy.test.ts +2 -4
  209. package/src/__tests__/voice-ingress-preflight.test.ts +19 -0
  210. package/src/__tests__/workspace-migration-006-services-config.test.ts +3 -2
  211. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  212. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  213. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  214. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +1 -5
  215. package/src/__tests__/workspace-migration-down-functions.test.ts +8 -8
  216. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  217. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +10 -6
  218. package/src/approvals/guardian-decision-primitive.ts +13 -0
  219. package/src/approvals/guardian-request-resolvers.ts +16 -17
  220. package/src/backup/__tests__/paths.test.ts +0 -22
  221. package/src/backup/__tests__/restore.test.ts +51 -151
  222. package/src/backup/paths.ts +2 -18
  223. package/src/backup/restore.ts +107 -231
  224. package/src/backup/snapshot-lock.ts +2 -27
  225. package/src/bundler/app-bundler.ts +51 -3
  226. package/src/bundler/compiler-tools.ts +3 -2
  227. package/src/calls/call-conversation-messages.ts +46 -10
  228. package/src/calls/relay-server.ts +4 -44
  229. package/src/calls/twilio-config.ts +2 -17
  230. package/src/calls/twilio-rest.ts +33 -105
  231. package/src/calls/twilio-routes.ts +11 -12
  232. package/src/channels/types.ts +8 -7
  233. package/src/cli/commands/__tests__/backup.test.ts +6 -277
  234. package/src/cli/commands/__tests__/gateway.test.ts +288 -0
  235. package/src/cli/commands/__tests__/memory-v2.test.ts +4 -0
  236. package/src/cli/commands/__tests__/webhooks.test.ts +0 -5
  237. package/src/cli/commands/backup.ts +6 -331
  238. package/src/cli/commands/bash.ts +35 -108
  239. package/src/cli/commands/clients.ts +36 -37
  240. package/src/cli/commands/contacts.ts +137 -25
  241. package/src/cli/commands/conversations.ts +2 -5
  242. package/src/cli/commands/credentials.ts +71 -7
  243. package/src/cli/commands/domain.ts +66 -15
  244. package/src/cli/commands/gateway.ts +183 -0
  245. package/src/cli/commands/keys.ts +9 -6
  246. package/src/cli/commands/mcp.ts +116 -156
  247. package/src/cli/commands/memory-v2.ts +303 -7
  248. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  249. package/src/cli/commands/oauth/connect.ts +127 -1
  250. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -4
  251. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -3
  252. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -3
  253. package/src/cli/commands/platform/__tests__/status.test.ts +116 -21
  254. package/src/cli/commands/platform/disconnect.ts +5 -4
  255. package/src/cli/commands/platform/index.ts +16 -25
  256. package/src/cli/commands/status.ts +57 -0
  257. package/src/cli/lib/daemon-credential-client.ts +110 -28
  258. package/src/cli/program.ts +6 -2
  259. package/src/config/assistant-feature-flags.ts +79 -12
  260. package/src/config/bundled-skills/acp/SKILL.md +6 -0
  261. package/src/config/bundled-skills/acp/TOOLS.json +1 -22
  262. package/src/config/bundled-skills/app-builder/SKILL.md +14 -109
  263. package/src/config/bundled-skills/app-builder/TOOLS.json +1 -28
  264. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -10
  265. package/src/config/bundled-skills/app-control/SKILL.md +75 -0
  266. package/src/config/bundled-skills/app-control/TOOLS.json +299 -0
  267. package/src/config/bundled-skills/app-control/tools/app-control-click.ts +12 -0
  268. package/src/config/bundled-skills/app-control/tools/app-control-combo.ts +12 -0
  269. package/src/config/bundled-skills/app-control/tools/app-control-drag.ts +12 -0
  270. package/src/config/bundled-skills/app-control/tools/app-control-observe.ts +12 -0
  271. package/src/config/bundled-skills/app-control/tools/app-control-press.ts +12 -0
  272. package/src/config/bundled-skills/app-control/tools/app-control-sequence.ts +12 -0
  273. package/src/config/bundled-skills/app-control/tools/app-control-start.ts +12 -0
  274. package/src/config/bundled-skills/app-control/tools/app-control-stop.ts +12 -0
  275. package/src/config/bundled-skills/app-control/tools/app-control-type.ts +12 -0
  276. package/src/config/bundled-skills/computer-use/SKILL.md +6 -0
  277. package/src/config/bundled-skills/computer-use/TOOLS.json +67 -43
  278. package/src/config/bundled-skills/contacts/TOOLS.json +0 -16
  279. package/src/config/bundled-skills/document/TOOLS.json +0 -8
  280. package/src/config/bundled-skills/followups/TOOLS.json +0 -12
  281. package/src/config/bundled-skills/image-studio/SKILL.md +4 -0
  282. package/src/config/bundled-skills/image-studio/TOOLS.json +0 -4
  283. package/src/config/bundled-skills/media-processing/TOOLS.json +0 -24
  284. package/src/config/bundled-skills/messaging/TOOLS.json +0 -40
  285. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  286. package/src/config/bundled-skills/phone-calls/TOOLS.json +0 -12
  287. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +25 -4
  288. package/src/config/bundled-skills/playbooks/TOOLS.json +0 -16
  289. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  290. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  291. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  292. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  293. package/src/config/bundled-skills/schedule/TOOLS.json +14 -14
  294. package/src/config/bundled-skills/sequences/TOOLS.json +0 -36
  295. package/src/config/bundled-skills/settings/SKILL.md +4 -0
  296. package/src/config/bundled-skills/settings/TOOLS.json +0 -12
  297. package/src/config/bundled-skills/skill-management/SKILL.md +6 -0
  298. package/src/config/bundled-skills/skill-management/TOOLS.json +0 -8
  299. package/src/config/bundled-skills/subagent/SKILL.md +6 -2
  300. package/src/config/bundled-skills/subagent/TOOLS.json +0 -20
  301. package/src/config/bundled-skills/transcribe/SKILL.md +4 -0
  302. package/src/config/bundled-skills/transcribe/TOOLS.json +0 -4
  303. package/src/config/bundled-tool-registry.ts +21 -0
  304. package/src/config/env-registry.ts +0 -2
  305. package/src/config/env.ts +19 -20
  306. package/src/config/feature-flag-registry.json +47 -135
  307. package/src/config/loader.ts +197 -104
  308. package/src/config/sanitize-for-transfer.ts +2 -0
  309. package/src/config/schemas/__tests__/memory-lifecycle.test.ts +80 -0
  310. package/src/config/schemas/__tests__/memory-v2.test.ts +17 -9
  311. package/src/config/schemas/call-site-catalog.ts +14 -0
  312. package/src/config/schemas/calls.ts +0 -9
  313. package/src/config/schemas/channels.ts +0 -5
  314. package/src/config/schemas/heartbeat.ts +64 -1
  315. package/src/config/schemas/ingress.ts +10 -6
  316. package/src/config/schemas/llm.ts +7 -10
  317. package/src/config/schemas/memory-lifecycle.ts +90 -24
  318. package/src/config/schemas/memory-v2.ts +121 -13
  319. package/src/config/schemas/platform.ts +49 -3
  320. package/src/config/schemas/services.ts +29 -15
  321. package/src/config/schemas/skills.ts +0 -6
  322. package/src/config/seed-inference-profiles.ts +230 -33
  323. package/src/contacts/contact-store.ts +0 -55
  324. package/src/contacts/contacts-write.ts +0 -27
  325. package/src/context/window-manager.ts +1 -2
  326. package/src/credential-execution/feature-gates.ts +10 -10
  327. package/src/credential-execution/process-manager.ts +12 -41
  328. package/src/daemon/__tests__/conversation-tool-setup.test.ts +187 -5
  329. package/src/daemon/assistant-attachments.ts +4 -4
  330. package/src/daemon/bootstrap-turn-cleanup.ts +45 -0
  331. package/src/daemon/config-watcher.ts +89 -60
  332. package/src/daemon/conversation-agent-loop-handlers.ts +27 -3
  333. package/src/daemon/conversation-agent-loop.ts +202 -61
  334. package/src/daemon/conversation-error.ts +87 -15
  335. package/src/daemon/conversation-lifecycle.ts +9 -4
  336. package/src/daemon/conversation-process.ts +24 -11
  337. package/src/daemon/conversation-runtime-assembly.ts +28 -2
  338. package/src/daemon/conversation-store.ts +2 -2
  339. package/src/daemon/conversation-surfaces.ts +305 -4
  340. package/src/daemon/conversation-tool-setup.ts +66 -62
  341. package/src/daemon/conversation.ts +38 -24
  342. package/src/daemon/date-context.ts +71 -22
  343. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  344. package/src/daemon/disk-pressure-guard.ts +343 -0
  345. package/src/daemon/disk-pressure-policy.ts +163 -0
  346. package/src/daemon/doordash-steps.ts +1 -1
  347. package/src/daemon/handlers/shared.ts +4 -2
  348. package/src/daemon/handlers/skills.ts +3 -4
  349. package/src/daemon/host-app-control-proxy.ts +389 -0
  350. package/src/daemon/host-bash-proxy.ts +117 -82
  351. package/src/daemon/host-browser-proxy.ts +67 -82
  352. package/src/daemon/host-cu-proxy.ts +127 -86
  353. package/src/daemon/host-file-proxy.ts +129 -69
  354. package/src/daemon/host-proxy-base.ts +294 -0
  355. package/src/daemon/host-proxy-preactivation.ts +82 -0
  356. package/src/daemon/host-transfer-proxy.ts +338 -129
  357. package/src/daemon/lifecycle.ts +194 -145
  358. package/src/daemon/meet-host-supervisor.ts +4 -4
  359. package/src/daemon/meet-manifest-loader.ts +0 -1
  360. package/src/daemon/memory-v2-startup.ts +14 -4
  361. package/src/daemon/message-protocol.ts +6 -8
  362. package/src/daemon/message-types/contacts.ts +23 -1
  363. package/src/daemon/message-types/conversations.ts +15 -8
  364. package/src/daemon/message-types/disk-pressure.ts +9 -0
  365. package/src/daemon/message-types/host-app-control.ts +150 -0
  366. package/src/daemon/message-types/host-bash.ts +4 -0
  367. package/src/daemon/message-types/host-cu.ts +2 -0
  368. package/src/daemon/message-types/host-file.ts +4 -0
  369. package/src/daemon/message-types/host-transfer.ts +3 -0
  370. package/src/daemon/message-types/messages.ts +3 -0
  371. package/src/daemon/message-types/schedules.ts +8 -3
  372. package/src/daemon/message-types/skills.ts +2 -2
  373. package/src/daemon/process-message.ts +18 -1
  374. package/src/daemon/profiler-run-store.ts +5 -5
  375. package/src/daemon/shutdown-handlers.ts +0 -3
  376. package/src/daemon/tool-setup-types.ts +51 -0
  377. package/src/daemon/tool-side-effects.ts +1 -1
  378. package/src/documents/document-store.ts +85 -0
  379. package/src/events/tool-audit-listener.ts +2 -1
  380. package/src/filing/filing-service.ts +30 -5
  381. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +24 -23
  382. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +252 -0
  383. package/src/heartbeat/heartbeat-run-store.ts +249 -0
  384. package/src/heartbeat/heartbeat-service.ts +459 -54
  385. package/src/home/__tests__/post-connect-feed.test.ts +99 -0
  386. package/src/home/__tests__/relationship-state-writer.test.ts +11 -9
  387. package/src/home/__tests__/suggested-prompts.test.ts +89 -0
  388. package/src/home/feed-scheduler.ts +18 -0
  389. package/src/home/post-connect-feed.ts +68 -0
  390. package/src/home/relationship-state-writer.ts +17 -92
  391. package/src/home/suggested-prompts.ts +46 -10
  392. package/src/inbound/platform-callback-registration.ts +8 -15
  393. package/src/inbound/public-ingress-urls.ts +32 -34
  394. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  395. package/src/ipc/__tests__/route-error-envelope.test.ts +80 -0
  396. package/src/ipc/assistant-server.ts +70 -3
  397. package/src/ipc/cli-client.ts +32 -1
  398. package/src/ipc/gateway-client.ts +37 -3
  399. package/src/live-voice/live-voice-archive.ts +4 -4
  400. package/src/live-voice/live-voice-metrics.ts +10 -10
  401. package/src/live-voice/protocol.ts +5 -7
  402. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +304 -0
  403. package/src/mcp/mcp-auth-orchestrator.ts +213 -0
  404. package/src/mcp/mcp-auth-state.ts +133 -0
  405. package/src/mcp/mcp-oauth-provider.ts +19 -0
  406. package/src/media/image-service.ts +1 -7
  407. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  408. package/src/memory/__tests__/jobs-store-job-classes.test.ts +24 -0
  409. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  412. package/src/memory/__tests__/qdrant-client-sentinel.test.ts +49 -0
  413. package/src/memory/__tests__/sparse-tokenize.test.ts +66 -0
  414. package/src/memory/admin.ts +5 -9
  415. package/src/memory/anisotropy.test.ts +247 -0
  416. package/src/memory/anisotropy.ts +443 -0
  417. package/src/memory/auto-analysis-constants.ts +17 -0
  418. package/src/memory/auto-analysis-guard.ts +5 -15
  419. package/src/memory/canonical-guardian-store.ts +7 -7
  420. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +122 -0
  421. package/src/memory/context-search/agent-protocol.ts +6 -6
  422. package/src/memory/context-search/agent-runner.ts +51 -9
  423. package/src/memory/context-search/sources/conversations.ts +2 -11
  424. package/src/memory/context-search/sources/memory-v2.ts +22 -9
  425. package/src/memory/context-search/sources/memory.ts +0 -1
  426. package/src/memory/context-search/types.ts +0 -1
  427. package/src/memory/conversation-crud.ts +5 -13
  428. package/src/memory/conversation-key-store.ts +2 -15
  429. package/src/memory/db-init.ts +6 -0
  430. package/src/memory/embedding-backend.ts +9 -21
  431. package/src/memory/embedding-runtime-manager.ts +119 -5
  432. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +81 -25
  433. package/src/memory/graph/conversation-graph-memory.ts +43 -78
  434. package/src/memory/graph/extraction.ts +1 -3
  435. package/src/memory/graph/graph-search.test.ts +10 -67
  436. package/src/memory/graph/graph-search.ts +9 -20
  437. package/src/memory/graph/retriever.test.ts +6 -0
  438. package/src/memory/graph/retriever.ts +34 -10
  439. package/src/memory/graph/tools.ts +1 -1
  440. package/src/memory/indexer.ts +54 -45
  441. package/src/memory/job-handlers/backfill.ts +2 -11
  442. package/src/memory/job-handlers/cleanup.ts +43 -0
  443. package/src/memory/job-handlers/embedding.ts +6 -8
  444. package/src/memory/job-handlers/summarization.ts +2 -7
  445. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +8 -2
  446. package/src/memory/jobs/embed-concept-page.ts +28 -2
  447. package/src/memory/jobs/embed-pkb-file.test.ts +2 -2
  448. package/src/memory/jobs-store.ts +114 -22
  449. package/src/memory/jobs-worker.ts +193 -106
  450. package/src/memory/memory-v2-activation-log-store.ts +33 -15
  451. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  452. package/src/memory/migrations/237-heartbeat-runs.ts +45 -0
  453. package/src/memory/migrations/238-schedule-retry-policy.ts +20 -0
  454. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  455. package/src/memory/migrations/index.ts +6 -0
  456. package/src/memory/migrations/registry.ts +8 -0
  457. package/src/memory/pkb/pkb-search.test.ts +6 -0
  458. package/src/memory/pkb/pkb-search.ts +7 -0
  459. package/src/memory/qdrant-client.ts +49 -32
  460. package/src/memory/rerank-local.ts +374 -0
  461. package/src/memory/schema/infrastructure.ts +15 -0
  462. package/src/memory/search/semantic.ts +13 -67
  463. package/src/memory/sparse-tokenize.ts +49 -0
  464. package/src/memory/trace-event-store.ts +1 -17
  465. package/src/memory/v2/__tests__/activation.test.ts +387 -344
  466. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  467. package/src/memory/v2/__tests__/injection.test.ts +181 -169
  468. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  469. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  470. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  471. package/src/memory/v2/__tests__/sim.test.ts +154 -188
  472. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  473. package/src/memory/v2/__tests__/sparse-bm25.test.ts +292 -0
  474. package/src/memory/v2/__tests__/static-context.test.ts +76 -2
  475. package/src/memory/v2/activation.ts +213 -239
  476. package/src/memory/v2/consolidation-job.ts +65 -17
  477. package/src/memory/v2/constants.ts +7 -0
  478. package/src/memory/v2/injection.ts +123 -103
  479. package/src/memory/v2/prompts/consolidation.ts +348 -92
  480. package/src/memory/v2/qdrant.ts +198 -1
  481. package/src/memory/v2/reranker.ts +177 -0
  482. package/src/memory/v2/sim.ts +113 -77
  483. package/src/memory/v2/skill-content.ts +4 -3
  484. package/src/memory/v2/skill-store.ts +91 -53
  485. package/src/memory/v2/sparse-bm25.ts +245 -0
  486. package/src/memory/v2/static-context.ts +28 -5
  487. package/src/memory/v2/types.ts +10 -10
  488. package/src/messaging/providers/gmail/types.ts +0 -49
  489. package/src/messaging/providers/slack/adapter.ts +1 -31
  490. package/src/messaging/providers/slack/types.ts +0 -32
  491. package/src/notifications/README.md +10 -10
  492. package/src/notifications/broadcaster.ts +1 -1
  493. package/src/notifications/copy-composer.ts +13 -0
  494. package/src/notifications/guardian-question-mode.ts +5 -5
  495. package/src/notifications/signal.ts +4 -0
  496. package/src/oauth/AGENTS.md +3 -1
  497. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  498. package/src/oauth/connect-orchestrator.ts +6 -0
  499. package/src/oauth/connection-resolver.test.ts +66 -1
  500. package/src/oauth/connection-resolver.ts +55 -1
  501. package/src/oauth/credential-token-resolver.ts +1 -3
  502. package/src/oauth/manual-token-connection.ts +0 -4
  503. package/src/oauth/oauth-connect-state.ts +77 -0
  504. package/src/oauth/seed-providers.ts +58 -1
  505. package/src/outbound-proxy/index.ts +1 -37
  506. package/src/outbound-proxy/logging.ts +1 -1
  507. package/src/outbound-proxy/policy.ts +6 -5
  508. package/src/outbound-proxy/router.ts +2 -1
  509. package/src/permissions/approval-policy.test.ts +6 -275
  510. package/src/permissions/approval-policy.ts +0 -51
  511. package/src/permissions/checker.test.ts +0 -1
  512. package/src/permissions/checker.ts +3 -17
  513. package/src/permissions/gateway-threshold-reader.ts +2 -0
  514. package/src/permissions/prompter.ts +34 -1
  515. package/src/permissions/secret-prompter.ts +6 -2
  516. package/src/plugins/defaults/injectors.ts +35 -2
  517. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  518. package/src/plugins/types.ts +7 -0
  519. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  520. package/src/proactive-artifact/decision.test.ts +226 -0
  521. package/src/proactive-artifact/decision.ts +165 -0
  522. package/src/proactive-artifact/index.ts +7 -0
  523. package/src/proactive-artifact/job.test.ts +867 -0
  524. package/src/proactive-artifact/job.ts +352 -0
  525. package/src/proactive-artifact/message-copy.ts +41 -0
  526. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  527. package/src/proactive-artifact/trigger-state.ts +119 -0
  528. package/src/prompts/bootstrap-cleanup.ts +27 -0
  529. package/src/prompts/normalize-onboarding.ts +80 -0
  530. package/src/prompts/persona-resolver.ts +101 -9
  531. package/src/prompts/system-prompt.ts +23 -24
  532. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  533. package/src/prompts/templates/SOUL.md +13 -1
  534. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  535. package/src/providers/model-intents.ts +7 -0
  536. package/src/providers/openrouter/client.ts +8 -0
  537. package/src/providers/retry.ts +50 -0
  538. package/src/providers/speech-to-text/provider-catalog.ts +7 -8
  539. package/src/providers/types.ts +1 -0
  540. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  541. package/src/runtime/agent-wake.ts +238 -100
  542. package/src/runtime/assistant-event-hub.ts +151 -99
  543. package/src/runtime/auth/__tests__/middleware.test.ts +11 -56
  544. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  545. package/src/runtime/auth/middleware.ts +0 -96
  546. package/src/runtime/auth/route-policy.ts +32 -0
  547. package/src/runtime/auth/same-actor.ts +216 -0
  548. package/src/runtime/btw-sidechain.ts +2 -3
  549. package/src/runtime/channel-invite-transport.ts +2 -48
  550. package/src/runtime/channel-invite-transports/email.ts +1 -1
  551. package/src/runtime/channel-invite-transports/slack.ts +1 -1
  552. package/src/runtime/channel-invite-transports/telegram.ts +1 -1
  553. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  554. package/src/runtime/channel-invite-transports/whatsapp.ts +1 -1
  555. package/src/runtime/channel-invite-types.ts +54 -0
  556. package/src/runtime/channel-readiness-service.ts +32 -13
  557. package/src/runtime/channel-retry-sweep.ts +65 -1
  558. package/src/runtime/guardian-reply-router.ts +10 -0
  559. package/src/runtime/http-server.ts +3 -329
  560. package/src/runtime/http-types.ts +0 -5
  561. package/src/runtime/local-actor-identity.ts +52 -11
  562. package/src/runtime/migrations/__tests__/vbundle-import-parity.test.ts +413 -0
  563. package/src/runtime/migrations/__tests__/vbundle-import-policy.test.ts +260 -0
  564. package/src/runtime/migrations/__tests__/vbundle-import-version-compat.test.ts +189 -0
  565. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +153 -1
  566. package/src/runtime/migrations/__tests__/vbundle-symlink-importer.test.ts +451 -0
  567. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming-importer.test.ts +0 -0
  568. package/src/runtime/migrations/__tests__/vbundle-symlink-streaming.test.ts +515 -0
  569. package/src/runtime/migrations/__tests__/vbundle-symlink-tar.test.ts +437 -0
  570. package/src/runtime/migrations/__tests__/vbundle-symlink-walker.test.ts +319 -0
  571. package/src/runtime/migrations/__tests__/vbundle-validator-v1-schema.test.ts +51 -1
  572. package/src/runtime/migrations/migration-transport.ts +7 -7
  573. package/src/runtime/migrations/vbundle-builder.ts +327 -60
  574. package/src/runtime/migrations/vbundle-import-analyzer.ts +4 -4
  575. package/src/runtime/migrations/vbundle-import-policy.ts +172 -0
  576. package/src/runtime/migrations/vbundle-importer.ts +245 -68
  577. package/src/runtime/migrations/vbundle-streaming-importer.ts +326 -35
  578. package/src/runtime/migrations/vbundle-streaming-validator.ts +157 -4
  579. package/src/runtime/migrations/vbundle-tar-stream.ts +15 -6
  580. package/src/runtime/migrations/vbundle-validator.ts +114 -0
  581. package/src/runtime/pending-interactions.ts +43 -9
  582. package/src/runtime/routes/__tests__/backup-routes.test.ts +22 -150
  583. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  584. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +98 -5
  585. package/src/runtime/routes/__tests__/gateway-log-routes.test.ts +242 -0
  586. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +112 -0
  587. package/src/runtime/routes/approval-interception-types.ts +13 -0
  588. package/src/runtime/routes/approval-strategies/guardian-text-engine-strategy.ts +1 -1
  589. package/src/runtime/routes/backup-routes.ts +15 -38
  590. package/src/runtime/routes/btw-routes.ts +14 -37
  591. package/src/runtime/routes/client-routes.ts +21 -2
  592. package/src/runtime/routes/contact-prompt-routes.ts +183 -0
  593. package/src/runtime/routes/contact-routes.ts +0 -25
  594. package/src/runtime/routes/conversation-query-routes.ts +36 -1
  595. package/src/runtime/routes/conversation-routes.ts +65 -39
  596. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  597. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  598. package/src/runtime/routes/document-pdf-renderer.ts +169 -0
  599. package/src/runtime/routes/documents-routes.ts +32 -75
  600. package/src/runtime/routes/errors.ts +19 -4
  601. package/src/runtime/routes/events-routes.ts +38 -0
  602. package/src/runtime/routes/gateway-log-routes.ts +79 -0
  603. package/src/runtime/routes/guardian-approval-interception.ts +2 -8
  604. package/src/runtime/routes/heartbeat-routes.ts +103 -38
  605. package/src/runtime/routes/host-app-control-routes.ts +134 -0
  606. package/src/runtime/routes/host-bash-routes.ts +56 -6
  607. package/src/runtime/routes/host-browser-routes.ts +108 -13
  608. package/src/runtime/routes/host-cu-routes.ts +66 -9
  609. package/src/runtime/routes/host-file-routes.ts +54 -5
  610. package/src/runtime/routes/host-transfer-routes.ts +122 -19
  611. package/src/runtime/routes/http-adapter.ts +1 -0
  612. package/src/runtime/routes/identity-intro-cache.ts +30 -0
  613. package/src/runtime/routes/identity-routes.ts +21 -180
  614. package/src/runtime/routes/inbound-message-handler.ts +78 -21
  615. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +0 -7
  616. package/src/runtime/routes/inbound-stages/edit-intercept.ts +0 -8
  617. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  618. package/src/runtime/routes/inbound-stages/transcribe-audio.test.ts +0 -20
  619. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +5 -13
  620. package/src/runtime/routes/index.ts +14 -0
  621. package/src/runtime/routes/mcp-auth-routes.ts +132 -0
  622. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  623. package/src/runtime/routes/memory-item-routes.ts +10 -12
  624. package/src/runtime/routes/memory-v2-routes.ts +474 -1
  625. package/src/runtime/routes/migration-routes.ts +96 -0
  626. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  627. package/src/runtime/routes/schedule-routes.ts +7 -0
  628. package/src/runtime/verification-outbound-actions.ts +4 -4
  629. package/src/runtime/verification-templates.ts +4 -7
  630. package/src/schedule/integration-status.ts +66 -2
  631. package/src/schedule/recurrence-engine.ts +4 -1
  632. package/src/schedule/retry-backoff.ts +18 -0
  633. package/src/schedule/retry-policy.ts +82 -0
  634. package/src/schedule/run-script.ts +37 -5
  635. package/src/schedule/schedule-recovery.ts +64 -0
  636. package/src/schedule/schedule-store.ts +106 -2
  637. package/src/schedule/scheduler-types.ts +25 -0
  638. package/src/schedule/scheduler.ts +83 -39
  639. package/src/security/encrypted-store.ts +2 -0
  640. package/src/security/oauth-callback-registry.ts +8 -0
  641. package/src/security/secure-keys.ts +55 -0
  642. package/src/sequence/analytics.ts +5 -5
  643. package/src/sequence/engine.ts +1 -1
  644. package/src/skills/catalog-files.ts +2 -8
  645. package/src/skills/include-graph.ts +5 -5
  646. package/src/skills/remote-skill-policy.ts +10 -16
  647. package/src/skills/skill-file-provider.ts +1 -1
  648. package/src/skills/skill-file-types.ts +13 -0
  649. package/src/skills/skillssh-audit-types.ts +28 -0
  650. package/src/skills/skillssh-registry.ts +8 -21
  651. package/src/subagent/index.ts +1 -7
  652. package/src/subagent/manager.ts +1 -15
  653. package/src/tasks/task-runner.ts +0 -1
  654. package/src/tasks/task-store.ts +0 -3
  655. package/src/telemetry/types.ts +2 -0
  656. package/src/telemetry/usage-telemetry-reporter.test.ts +21 -0
  657. package/src/telemetry/usage-telemetry-reporter.ts +1 -0
  658. package/src/tools/app-control/skill-proxy-bridge.ts +28 -0
  659. package/src/tools/apps/executors.ts +56 -69
  660. package/src/tools/background-tool-registry.ts +17 -3
  661. package/src/tools/browser/__tests__/browser-status.test.ts +21 -18
  662. package/src/tools/browser/browser-execution.ts +2 -2
  663. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +55 -4
  664. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +12 -6
  665. package/src/tools/browser/cdp-client/factory.ts +23 -24
  666. package/src/tools/browser/cdp-client/index.ts +1 -14
  667. package/src/tools/computer-use/definitions.ts +42 -20
  668. package/src/tools/executor.ts +2 -0
  669. package/src/tools/host-filesystem/edit.test.ts +151 -0
  670. package/src/tools/host-filesystem/edit.ts +68 -0
  671. package/src/tools/host-filesystem/read.test.ts +129 -0
  672. package/src/tools/host-filesystem/read.ts +68 -0
  673. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  674. package/src/tools/host-filesystem/transfer.ts +78 -3
  675. package/src/tools/host-filesystem/write.test.ts +134 -0
  676. package/src/tools/host-filesystem/write.ts +68 -0
  677. package/src/tools/host-terminal/host-shell.ts +66 -1
  678. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  679. package/src/tools/memory/register.test.ts +12 -9
  680. package/src/tools/memory/register.ts +1 -2
  681. package/src/tools/provider-tool-name.ts +28 -0
  682. package/src/tools/registry.ts +30 -9
  683. package/src/tools/schedule/create.ts +6 -0
  684. package/src/tools/schedule/list.ts +2 -0
  685. package/src/tools/schedule/update.ts +10 -0
  686. package/src/tools/shared/filesystem/file-ops-service.ts +2 -0
  687. package/src/tools/shared/filesystem/path-policy.ts +25 -1
  688. package/src/tools/skills/load.ts +0 -32
  689. package/src/tools/terminal/shell.ts +9 -1
  690. package/src/tools/tool-approval-handler.ts +32 -11
  691. package/src/tools/types.ts +28 -2
  692. package/src/tts/provider-catalog.ts +3 -5
  693. package/src/usage/pricing.ts +1 -1
  694. package/src/util/disk-usage.ts +138 -0
  695. package/src/util/platform.ts +21 -11
  696. package/src/util/process-liveness.ts +26 -0
  697. package/src/workspace/hatched-date.ts +86 -0
  698. package/src/workspace/heartbeat-service.ts +19 -0
  699. package/src/workspace/migrations/003-seed-device-id.ts +1 -1
  700. package/src/workspace/migrations/006-services-config.ts +8 -5
  701. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +3 -9
  702. package/src/workspace/migrations/021-move-signals-to-workspace.ts +4 -10
  703. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +4 -10
  704. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +4 -11
  705. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +3 -10
  706. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +3 -2
  707. package/src/workspace/migrations/050-seed-main-agent-opus-callsite.ts +2 -1
  708. package/src/workspace/migrations/059-move-pid-to-workspace.ts +3 -8
  709. package/src/workspace/migrations/061-move-backup-key-to-workspace.ts +3 -8
  710. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  711. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  712. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  713. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  714. package/src/workspace/migrations/AGENTS.md +1 -1
  715. package/src/workspace/migrations/migrate-to-workspace-volume.ts +4 -10
  716. package/src/workspace/migrations/registry.ts +8 -0
  717. package/src/workspace/migrations/utils.ts +21 -0
  718. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  719. package/src/__tests__/host-browser-e2e-cloud.test.ts +0 -443
  720. package/src/__tests__/host-browser-e2e-self-hosted-capability.test.ts +0 -226
  721. package/src/__tests__/host-browser-ws-events-e2e.test.ts +0 -427
  722. package/src/__tests__/twilio-rest.test.ts +0 -34
  723. package/src/backup/__tests__/backup-key.test.ts +0 -152
  724. package/src/backup/__tests__/backup-worker.test.ts +0 -782
  725. package/src/backup/__tests__/offsite-writer.test.ts +0 -641
  726. package/src/backup/__tests__/stream-crypt.test.ts +0 -228
  727. package/src/backup/backup-key.ts +0 -137
  728. package/src/backup/backup-worker.ts +0 -472
  729. package/src/backup/offsite-writer.ts +0 -222
  730. package/src/backup/stream-crypt.ts +0 -263
  731. package/src/daemon/message-types/pairing.ts +0 -58
  732. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  733. package/src/memory/v2/skill-qdrant.ts +0 -395
  734. package/src/outbound-proxy/config.ts +0 -20
  735. package/src/outbound-proxy/health.ts +0 -18
  736. package/src/outbound-proxy/types.ts +0 -150
  737. package/src/runtime/capability-tokens.ts +0 -190
  738. package/src/signals/bash.ts +0 -198
  739. package/src/signals/mcp-reload.ts +0 -18
@@ -12,32 +12,40 @@ mock.module("../config/loader.js", () => ({
12
12
  getConfig: () => mockConfig,
13
13
  loadConfig: () => mockConfig,
14
14
  invalidateConfigCache: () => {},
15
- saveConfig: () => {},
16
15
  }));
17
16
 
18
17
  const sentMessages: unknown[] = [];
19
- const resolvedInteractionIds: string[] = [];
18
+ const sentMessageOptions: unknown[] = [];
20
19
  let mockHasClient = false;
20
+ type MockClient = {
21
+ clientId: string;
22
+ capabilities: string[];
23
+ actorPrincipalId?: string;
24
+ };
25
+ let mockCapableClients: Array<MockClient> = [];
26
+ let mockClientRegistry: Map<string, MockClient> = new Map();
21
27
 
22
28
  mock.module("../runtime/assistant-event-hub.js", () => ({
23
- broadcastMessage: (msg: unknown) => sentMessages.push(msg),
29
+ broadcastMessage: (
30
+ msg: unknown,
31
+ _conversationId?: string,
32
+ options?: unknown,
33
+ ) => {
34
+ sentMessages.push(msg);
35
+ sentMessageOptions.push(options);
36
+ },
24
37
  assistantEventHub: {
25
38
  getMostRecentClientByCapability: (cap: string) =>
26
39
  cap === "host_bash" && mockHasClient ? { id: "mock-client" } : null,
40
+ listClientsByCapability: (_cap: string) => mockCapableClients,
41
+ getClientById: (clientId: string) => mockClientRegistry.get(clientId),
42
+ getActorPrincipalIdForClient: (clientId: string) =>
43
+ mockClientRegistry.get(clientId)?.actorPrincipalId,
27
44
  },
28
45
  }));
29
46
 
30
- mock.module("../runtime/pending-interactions.js", () => ({
31
- resolve: (requestId: string) => {
32
- resolvedInteractionIds.push(requestId);
33
- return undefined;
34
- },
35
- get: () => undefined,
36
- getByKind: () => [],
37
- getByConversation: () => [],
38
- removeByConversation: () => {},
39
- }));
40
-
47
+ // Use the REAL pending-interactions module the proxy self-registers here.
48
+ const pendingInteractions = await import("../runtime/pending-interactions.js");
41
49
  const { HostBashProxy } = await import("../daemon/host-bash-proxy.js");
42
50
 
43
51
  describe("HostBashProxy", () => {
@@ -45,14 +53,42 @@ describe("HostBashProxy", () => {
45
53
 
46
54
  function setup() {
47
55
  sentMessages.length = 0;
48
- resolvedInteractionIds.length = 0;
56
+ sentMessageOptions.length = 0;
49
57
  mockHasClient = false;
58
+ mockCapableClients = [];
59
+ mockClientRegistry = new Map();
60
+ pendingInteractions.clear();
50
61
  proxy = new (HostBashProxy as any)();
51
62
  }
52
63
 
64
+ function setupSingleClient(
65
+ clientId: string = "client-1",
66
+ actorPrincipalId: string = "user-A",
67
+ ) {
68
+ const entry: MockClient = {
69
+ clientId,
70
+ capabilities: ["host_bash"],
71
+ actorPrincipalId,
72
+ };
73
+ mockCapableClients = [entry];
74
+ mockClientRegistry.set(clientId, entry);
75
+ }
76
+
77
+ function setupMultipleClients(clientIds: string[]) {
78
+ mockCapableClients = clientIds.map((id) => ({
79
+ clientId: id,
80
+ capabilities: ["host_bash"],
81
+ actorPrincipalId: "user-A",
82
+ }));
83
+ for (const entry of mockCapableClients) {
84
+ mockClientRegistry.set(entry.clientId, entry);
85
+ }
86
+ }
87
+
53
88
  afterEach(() => {
54
89
  proxy?.dispose();
55
90
  HostBashProxy.reset();
91
+ pendingInteractions.clear();
56
92
  });
57
93
 
58
94
  describe("request/resolve lifecycle (happy path)", () => {
@@ -74,10 +110,10 @@ describe("HostBashProxy", () => {
74
110
  expect(typeof sent.requestId).toBe("string");
75
111
 
76
112
  const requestId = sent.requestId as string;
77
- expect(proxy.hasPendingRequest(requestId)).toBe(true);
113
+ expect(pendingInteractions.get(requestId)).toBeDefined();
78
114
 
79
115
  // Simulate client response
80
- proxy.resolve(requestId, {
116
+ proxy.resolveResult(requestId, {
81
117
  stdout: "hello\n",
82
118
  stderr: "",
83
119
  exitCode: 0,
@@ -87,7 +123,7 @@ describe("HostBashProxy", () => {
87
123
  const result = await resultPromise;
88
124
  expect(result.content).toContain("hello");
89
125
  expect(result.isError).toBe(false);
90
- expect(proxy.hasPendingRequest(requestId)).toBe(false);
126
+ expect(pendingInteractions.get(requestId)).toBeUndefined();
91
127
  });
92
128
 
93
129
  test("forwards env field in host_bash_request message", async () => {
@@ -107,7 +143,7 @@ describe("HostBashProxy", () => {
107
143
  expect(sent.env).toEqual({ VELLUM_UNTRUSTED_SHELL: "1" });
108
144
 
109
145
  const requestId = sent.requestId as string;
110
- proxy.resolve(requestId, {
146
+ proxy.resolveResult(requestId, {
111
147
  stdout: "locked\n",
112
148
  stderr: "",
113
149
  exitCode: 0,
@@ -129,7 +165,7 @@ describe("HostBashProxy", () => {
129
165
  expect(sent.env).toBeUndefined();
130
166
 
131
167
  const requestId = sent.requestId as string;
132
- proxy.resolve(requestId, {
168
+ proxy.resolveResult(requestId, {
133
169
  stdout: "normal\n",
134
170
  stderr: "",
135
171
  exitCode: 0,
@@ -147,7 +183,7 @@ describe("HostBashProxy", () => {
147
183
  const sent = sentMessages[0] as Record<string, unknown>;
148
184
  const requestId = sent.requestId as string;
149
185
 
150
- proxy.resolve(requestId, {
186
+ proxy.resolveResult(requestId, {
151
187
  stdout: "",
152
188
  stderr: "command not found",
153
189
  exitCode: 127,
@@ -170,7 +206,7 @@ describe("HostBashProxy", () => {
170
206
  const sent = sentMessages[0] as Record<string, unknown>;
171
207
  const requestId = sent.requestId as string;
172
208
 
173
- proxy.resolve(requestId, {
209
+ proxy.resolveResult(requestId, {
174
210
  stdout: "partial",
175
211
  stderr: "",
176
212
  exitCode: null,
@@ -196,10 +232,10 @@ describe("HostBashProxy", () => {
196
232
 
197
233
  const sent = sentMessages[0] as Record<string, unknown>;
198
234
  const requestId = sent.requestId as string;
199
- expect(proxy.hasPendingRequest(requestId)).toBe(true);
235
+ expect(pendingInteractions.get(requestId)).toBeDefined();
200
236
 
201
237
  // Resolve to avoid test hanging
202
- proxy.resolve(requestId, {
238
+ proxy.resolveResult(requestId, {
203
239
  stdout: "",
204
240
  stderr: "",
205
241
  exitCode: 0,
@@ -226,13 +262,13 @@ describe("HostBashProxy", () => {
226
262
 
227
263
  const sent = sentMessages[0] as Record<string, unknown>;
228
264
  const requestId = sent.requestId as string;
229
- expect(proxy.hasPendingRequest(requestId)).toBe(true);
265
+ expect(pendingInteractions.get(requestId)).toBeDefined();
230
266
 
231
267
  controller.abort();
232
268
 
233
269
  const result = await resultPromise;
234
270
  expect(result.content).toContain("Aborted");
235
- expect(proxy.hasPendingRequest(requestId)).toBe(false);
271
+ expect(pendingInteractions.get(requestId)).toBeUndefined();
236
272
  });
237
273
 
238
274
  test("sends host_bash_cancel to client on abort", async () => {
@@ -300,11 +336,11 @@ describe("HostBashProxy", () => {
300
336
 
301
337
  const sent = sentMessages[0] as Record<string, unknown>;
302
338
  const requestId = sent.requestId as string;
303
- expect(proxy.hasPendingRequest(requestId)).toBe(true);
339
+ expect(pendingInteractions.get(requestId)).toBeDefined();
304
340
 
305
341
  proxy.dispose();
306
342
 
307
- expect(proxy.hasPendingRequest(requestId)).toBe(false);
343
+ expect(pendingInteractions.get(requestId)).toBeUndefined();
308
344
  expect(resultPromise).rejects.toThrow("Host bash proxy disposed");
309
345
  });
310
346
 
@@ -336,7 +372,7 @@ describe("HostBashProxy", () => {
336
372
  });
337
373
 
338
374
  describe("late resolve after abort", () => {
339
- test("resolve is a no-op after abort (entry already deleted)", async () => {
375
+ test("resolveResult is a no-op after abort (entry already deleted)", async () => {
340
376
  setup();
341
377
 
342
378
  const controller = new AbortController();
@@ -353,23 +389,23 @@ describe("HostBashProxy", () => {
353
389
  const result = await resultPromise;
354
390
  expect(result.content).toContain("Aborted");
355
391
 
356
- // Late resolve should be silently ignored (no throw, no double-resolve)
357
- proxy.resolve(requestId, {
392
+ // Late resolveResult should be silently ignored (no throw, no double-resolve)
393
+ proxy.resolveResult(requestId, {
358
394
  stdout: "late",
359
395
  stderr: "",
360
396
  exitCode: 0,
361
397
  timedOut: false,
362
398
  });
363
399
 
364
- expect(proxy.hasPendingRequest(requestId)).toBe(false);
400
+ expect(pendingInteractions.get(requestId)).toBeUndefined();
365
401
  });
366
402
  });
367
403
 
368
- describe("resolve with unknown requestId", () => {
404
+ describe("resolveResult with unknown requestId", () => {
369
405
  test("silently ignores unknown requestId", () => {
370
406
  setup();
371
407
  // Should not throw
372
- proxy.resolve("unknown-id", {
408
+ proxy.resolveResult("unknown-id", {
373
409
  stdout: "",
374
410
  stderr: "",
375
411
  exitCode: 0,
@@ -401,7 +437,7 @@ describe("HostBashProxy", () => {
401
437
  return { signal: source, addCalls, removeCalls };
402
438
  }
403
439
 
404
- test("removes abort listener from signal after resolve completes", async () => {
440
+ test("removes abort listener from signal after resolveResult completes", async () => {
405
441
  setup();
406
442
  const controller = new AbortController();
407
443
  const spy = spySignal(controller.signal);
@@ -417,7 +453,7 @@ describe("HostBashProxy", () => {
417
453
 
418
454
  const requestId = (sentMessages[0] as Record<string, unknown>)
419
455
  .requestId as string;
420
- proxy.resolve(requestId, {
456
+ proxy.resolveResult(requestId, {
421
457
  stdout: "hello\n",
422
458
  stderr: "",
423
459
  exitCode: 0,
@@ -465,8 +501,8 @@ describe("HostBashProxy", () => {
465
501
  });
466
502
  });
467
503
 
468
- describe("pendingInteractions.resolve callback", () => {
469
- test("fires on abort", async () => {
504
+ describe("pendingInteractions cleanup", () => {
505
+ test("cleans up on abort", async () => {
470
506
  setup();
471
507
 
472
508
  const controller = new AbortController();
@@ -478,14 +514,15 @@ describe("HostBashProxy", () => {
478
514
 
479
515
  const sent = sentMessages[0] as Record<string, unknown>;
480
516
  const requestId = sent.requestId as string;
517
+ expect(pendingInteractions.get(requestId)).toBeDefined();
481
518
 
482
519
  controller.abort();
483
520
  await resultPromise;
484
521
 
485
- expect(resolvedInteractionIds).toEqual([requestId]);
522
+ expect(pendingInteractions.get(requestId)).toBeUndefined();
486
523
  });
487
524
 
488
- test("fires for each pending request on dispose", () => {
525
+ test("cleans up for each pending request on dispose", () => {
489
526
  setup();
490
527
 
491
528
  const p1 = proxy.request({ command: "echo a" }, "session-1");
@@ -497,15 +534,16 @@ describe("HostBashProxy", () => {
497
534
  (m) => m.requestId as string,
498
535
  );
499
536
  expect(ids).toHaveLength(2);
537
+ expect(pendingInteractions.get(ids[0])).toBeDefined();
538
+ expect(pendingInteractions.get(ids[1])).toBeDefined();
500
539
 
501
540
  proxy.dispose();
502
541
 
503
- expect(resolvedInteractionIds).toHaveLength(2);
504
- expect(resolvedInteractionIds).toContain(ids[0]);
505
- expect(resolvedInteractionIds).toContain(ids[1]);
542
+ expect(pendingInteractions.get(ids[0])).toBeUndefined();
543
+ expect(pendingInteractions.get(ids[1])).toBeUndefined();
506
544
  });
507
545
 
508
- test("does not fire on normal client-initiated resolve", async () => {
546
+ test("cleans up on normal client-initiated resolveResult", async () => {
509
547
  setup();
510
548
 
511
549
  const resultPromise = proxy.request(
@@ -515,9 +553,9 @@ describe("HostBashProxy", () => {
515
553
 
516
554
  const sent = sentMessages[0] as Record<string, unknown>;
517
555
  const requestId = sent.requestId as string;
556
+ expect(pendingInteractions.get(requestId)).toBeDefined();
518
557
 
519
- // Normal resolve from client — should NOT trigger pendingInteractions.resolve
520
- proxy.resolve(requestId, {
558
+ proxy.resolveResult(requestId, {
521
559
  stdout: "hello",
522
560
  stderr: "",
523
561
  exitCode: 0,
@@ -525,7 +563,361 @@ describe("HostBashProxy", () => {
525
563
  });
526
564
 
527
565
  await resultPromise;
528
- expect(resolvedInteractionIds).toEqual([]);
566
+ expect(pendingInteractions.get(requestId)).toBeUndefined();
567
+ });
568
+ });
569
+
570
+ describe("target client routing", () => {
571
+ test("auto-resolves when exactly one capable client is connected", async () => {
572
+ setup();
573
+ setupSingleClient("client-abc", "user-A");
574
+
575
+ const resultPromise = proxy.request(
576
+ { command: "echo hello" },
577
+ "session-1",
578
+ undefined,
579
+ "user-A",
580
+ );
581
+
582
+ expect(sentMessages).toHaveLength(1);
583
+ const sent = sentMessages[0] as Record<string, unknown>;
584
+ expect(sent.targetClientId).toBe("client-abc");
585
+
586
+ // Options passed to broadcastMessage should also have targetClientId
587
+ const opts = sentMessageOptions[0] as Record<string, unknown> | undefined;
588
+ expect(opts?.targetClientId).toBe("client-abc");
589
+
590
+ const requestId = sent.requestId as string;
591
+ proxy.resolveResult(requestId, {
592
+ stdout: "hello\n",
593
+ stderr: "",
594
+ exitCode: 0,
595
+ timedOut: false,
596
+ });
597
+
598
+ const result = await resultPromise;
599
+ expect(result.isError).toBe(false);
600
+ });
601
+
602
+ test("uses explicit targetClientId when it is valid", async () => {
603
+ setup();
604
+ setupSingleClient("client-abc", "user-A");
605
+ // Also register a second client so we're sure explicit targeting works
606
+ const entry2: MockClient = {
607
+ clientId: "client-xyz",
608
+ capabilities: ["host_bash"],
609
+ actorPrincipalId: "user-A",
610
+ };
611
+ mockCapableClients.push(entry2);
612
+ mockClientRegistry.set("client-xyz", entry2);
613
+
614
+ const resultPromise = proxy.request(
615
+ { command: "echo hello", targetClientId: "client-abc" },
616
+ "session-1",
617
+ undefined,
618
+ "user-A",
619
+ );
620
+
621
+ expect(sentMessages).toHaveLength(1);
622
+ const sent = sentMessages[0] as Record<string, unknown>;
623
+ expect(sent.targetClientId).toBe("client-abc");
624
+
625
+ const opts = sentMessageOptions[0] as Record<string, unknown> | undefined;
626
+ expect(opts?.targetClientId).toBe("client-abc");
627
+
628
+ const requestId = sent.requestId as string;
629
+ proxy.resolveResult(requestId, {
630
+ stdout: "ok\n",
631
+ stderr: "",
632
+ exitCode: 0,
633
+ timedOut: false,
634
+ });
635
+
636
+ const result = await resultPromise;
637
+ expect(result.isError).toBe(false);
638
+ });
639
+
640
+ test("returns error for explicit targetClientId that is not connected", async () => {
641
+ setup();
642
+ setupSingleClient("client-abc", "user-A");
643
+
644
+ const result = await proxy.request(
645
+ { command: "echo hello", targetClientId: "client-unknown" },
646
+ "session-1",
647
+ undefined,
648
+ "user-A",
649
+ );
650
+
651
+ // Should return error without broadcasting
652
+ expect(result.isError).toBe(true);
653
+ expect(result.content).toContain("client-unknown");
654
+ expect(result.content).toContain(
655
+ "assistant clients list --capability host_bash",
656
+ );
657
+ expect(sentMessages).toHaveLength(0);
658
+ });
659
+
660
+ test("returns error for explicit targetClientId that is connected but lacks host_bash", async () => {
661
+ setup();
662
+ // Register a client without host_bash capability
663
+ mockClientRegistry.set("client-no-bash", {
664
+ clientId: "client-no-bash",
665
+ capabilities: [],
666
+ actorPrincipalId: "user-A",
667
+ });
668
+
669
+ const result = await proxy.request(
670
+ { command: "echo hello", targetClientId: "client-no-bash" },
671
+ "session-1",
672
+ undefined,
673
+ "user-A",
674
+ );
675
+
676
+ expect(result.isError).toBe(true);
677
+ expect(result.content).toContain("client-no-bash");
678
+ expect(result.content).toContain("does not support host_bash");
679
+ expect(sentMessages).toHaveLength(0);
680
+ });
681
+
682
+ test("rejects ambiguously when multiple same-user capable clients are connected and no targetClientId", async () => {
683
+ // Regression: previously fell through to untargeted broadcast, fanning
684
+ // a single targeted-style request out across every same-user machine.
685
+ setup();
686
+ setupMultipleClients(["client-1", "client-2", "client-3"]);
687
+
688
+ const result = await proxy.request(
689
+ { command: "echo hello" },
690
+ "session-1",
691
+ undefined,
692
+ "user-A",
693
+ );
694
+
695
+ expect(result.isError).toBe(true);
696
+ expect(result.content).toContain("target_client_id");
697
+ // No broadcast happened
698
+ expect(sentMessages).toHaveLength(0);
699
+ });
700
+
701
+ test("falls through to broadcast when zero capable clients (existing timeout path)", async () => {
702
+ setup();
703
+ // mockCapableClients is empty (default), so capableClients.length === 0
704
+
705
+ const resultPromise = proxy.request(
706
+ { command: "echo hello" },
707
+ "session-1",
708
+ );
709
+
710
+ // Should still broadcast (no early return)
711
+ expect(sentMessages).toHaveLength(1);
712
+ const sent = sentMessages[0] as Record<string, unknown>;
713
+ expect(sent.type).toBe("host_bash_request");
714
+ // targetClientId is undefined when no clients present
715
+ expect(sent.targetClientId).toBeUndefined();
716
+
717
+ // Manually resolve to clean up
718
+ const requestId = sent.requestId as string;
719
+ proxy.resolveResult(requestId, {
720
+ stdout: "",
721
+ stderr: "",
722
+ exitCode: 0,
723
+ timedOut: false,
724
+ });
725
+
726
+ await resultPromise;
727
+ });
728
+
729
+ test("includes targetClientId in timeout error message when client was resolved", async () => {
730
+ setup();
731
+ setupSingleClient("client-mac", "user-A");
732
+
733
+ jest.useFakeTimers();
734
+ try {
735
+ const resultPromise = proxy.request(
736
+ { command: "echo slow", timeout_seconds: 30 },
737
+ "session-1",
738
+ undefined,
739
+ "user-A",
740
+ );
741
+
742
+ // Proxy timeout = 33s; advance past it
743
+ jest.advanceTimersByTime(34 * 1000);
744
+
745
+ const result = await resultPromise;
746
+ expect(result.isError).toBe(true);
747
+ expect(result.content).toContain("client-mac");
748
+ } finally {
749
+ jest.useRealTimers();
750
+ }
751
+ });
752
+ });
753
+
754
+ describe("same-user binding (sourceActorPrincipalId)", () => {
755
+ const SAME_USER_REJECTION =
756
+ "Submitting actor does not match the target client's actor for this request. The targeted client's authenticated user must submit the result.";
757
+
758
+ test("same-user targeted request succeeds", async () => {
759
+ setup();
760
+ setupSingleClient("client-abc", "user-A");
761
+
762
+ const resultPromise = proxy.request(
763
+ { command: "echo hello", targetClientId: "client-abc" },
764
+ "session-1",
765
+ undefined,
766
+ "user-A",
767
+ );
768
+
769
+ expect(sentMessages).toHaveLength(1);
770
+ const sent = sentMessages[0] as Record<string, unknown>;
771
+ expect(sent.type).toBe("host_bash_request");
772
+ expect(sent.targetClientId).toBe("client-abc");
773
+ const requestId = sent.requestId as string;
774
+ expect(pendingInteractions.get(requestId)).toBeDefined();
775
+
776
+ proxy.resolveResult(requestId, {
777
+ stdout: "hello\n",
778
+ stderr: "",
779
+ exitCode: 0,
780
+ timedOut: false,
781
+ });
782
+ await resultPromise;
783
+ });
784
+
785
+ test("cross-user targeted request rejected", async () => {
786
+ setup();
787
+ setupSingleClient("client-abc", "user-A");
788
+
789
+ const result = await proxy.request(
790
+ { command: "echo hello", targetClientId: "client-abc" },
791
+ "session-1",
792
+ undefined,
793
+ "user-B",
794
+ );
795
+
796
+ expect(result.isError).toBe(true);
797
+ expect(result.content).toBe(SAME_USER_REJECTION);
798
+ // No broadcast and no pending registration
799
+ expect(sentMessages).toHaveLength(0);
800
+ });
801
+
802
+ test("target client missing actorPrincipalId rejected", async () => {
803
+ setup();
804
+ // Register a client without an actorPrincipalId (legacy/service-token).
805
+ const entry: MockClient = {
806
+ clientId: "client-abc",
807
+ capabilities: ["host_bash"],
808
+ };
809
+ mockCapableClients = [entry];
810
+ mockClientRegistry.set("client-abc", entry);
811
+
812
+ const result = await proxy.request(
813
+ { command: "echo hello", targetClientId: "client-abc" },
814
+ "session-1",
815
+ undefined,
816
+ "user-A",
817
+ );
818
+
819
+ expect(result.isError).toBe(true);
820
+ expect(result.content).toBe(SAME_USER_REJECTION);
821
+ expect(sentMessages).toHaveLength(0);
822
+ });
823
+
824
+ test("source missing actorPrincipalId rejected when targeting", async () => {
825
+ setup();
826
+ setupSingleClient("client-abc", "user-A");
827
+
828
+ const result = await proxy.request(
829
+ { command: "echo hello", targetClientId: "client-abc" },
830
+ "session-1",
831
+ undefined,
832
+ undefined,
833
+ );
834
+
835
+ expect(result.isError).toBe(true);
836
+ expect(result.content).toBe(SAME_USER_REJECTION);
837
+ expect(sentMessages).toHaveLength(0);
838
+ });
839
+
840
+ test("untargeted local flow unchanged when no auto-resolve match", async () => {
841
+ setup();
842
+ // No capable clients connected — untargeted path runs.
843
+
844
+ const resultPromise = proxy.request(
845
+ { command: "echo hello" },
846
+ "session-1",
847
+ undefined,
848
+ "user-A",
849
+ );
850
+
851
+ expect(sentMessages).toHaveLength(1);
852
+ const sent = sentMessages[0] as Record<string, unknown>;
853
+ expect(sent.type).toBe("host_bash_request");
854
+ expect(sent.targetClientId).toBeUndefined();
855
+
856
+ const requestId = sent.requestId as string;
857
+ proxy.resolveResult(requestId, {
858
+ stdout: "hello\n",
859
+ stderr: "",
860
+ exitCode: 0,
861
+ timedOut: false,
862
+ });
863
+ await resultPromise;
864
+ });
865
+
866
+ test("auto-resolve to same-user client succeeds", async () => {
867
+ setup();
868
+ setupSingleClient("client-abc", "user-A");
869
+
870
+ const resultPromise = proxy.request(
871
+ { command: "echo hello" },
872
+ "session-1",
873
+ undefined,
874
+ "user-A",
875
+ );
876
+
877
+ expect(sentMessages).toHaveLength(1);
878
+ const sent = sentMessages[0] as Record<string, unknown>;
879
+ expect(sent.targetClientId).toBe("client-abc");
880
+
881
+ const requestId = sent.requestId as string;
882
+ proxy.resolveResult(requestId, {
883
+ stdout: "hello\n",
884
+ stderr: "",
885
+ exitCode: 0,
886
+ timedOut: false,
887
+ });
888
+ await resultPromise;
889
+ });
890
+
891
+ test("auto-resolve to different-user client falls through to untargeted", async () => {
892
+ setup();
893
+ // Single capable client owned by user-B; caller is user-A.
894
+ setupSingleClient("client-abc", "user-B");
895
+
896
+ const resultPromise = proxy.request(
897
+ { command: "echo hello" },
898
+ "session-1",
899
+ undefined,
900
+ "user-A",
901
+ );
902
+
903
+ // Auto-resolve must NOT pick the cross-user client; the untargeted
904
+ // broadcast path runs instead.
905
+ expect(sentMessages).toHaveLength(1);
906
+ const sent = sentMessages[0] as Record<string, unknown>;
907
+ expect(sent.type).toBe("host_bash_request");
908
+ expect(sent.targetClientId).toBeUndefined();
909
+
910
+ const opts = sentMessageOptions[0] as Record<string, unknown> | undefined;
911
+ expect(opts?.targetClientId).toBeUndefined();
912
+
913
+ const requestId = sent.requestId as string;
914
+ proxy.resolveResult(requestId, {
915
+ stdout: "hello\n",
916
+ stderr: "",
917
+ exitCode: 0,
918
+ timedOut: false,
919
+ });
920
+ await resultPromise;
529
921
  });
530
922
  });
531
923
  });