@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
@@ -0,0 +1,389 @@
1
+ /**
2
+ * Host app-control proxy.
3
+ *
4
+ * Proxies app-control actions (start, observe, press, combo, type, click,
5
+ * drag, stop) to the desktop client. Targets a specific application by
6
+ * bundle ID or process name — distinct from the system-wide computer-use
7
+ * proxy ({@link HostCuProxy}).
8
+ *
9
+ * Lifecycle (pending map, timeout, abort SSE, dispose, isAvailable) lives
10
+ * in {@link HostProxyBase}; this class layers app-control-specific state
11
+ * (PNG-hash loop guard) and the result-payload → ToolExecutionResult
12
+ * translation on top.
13
+ *
14
+ * **Session lock.** Only one conversation may hold an active app-control
15
+ * session at a time, and that session is bound to a specific target app.
16
+ * The lock is module-level (`activeAppControlSession`) because the session
17
+ * targets the user's actual desktop application, which is a host-wide
18
+ * resource. It is acquired on a successful `app_control_start` (storing
19
+ * `(conversationId, app)`) and released when the owning proxy's
20
+ * `dispose()` fires.
21
+ *
22
+ * `app_control_start` is the only tool that can acquire the lock — the
23
+ * user's medium-risk approval at start time is the consent boundary. All
24
+ * other tools (observe / press / combo / sequence / type / click / drag)
25
+ * require the calling conversation to own an active session targeting the
26
+ * same `app`; otherwise the call is rejected before any host dispatch.
27
+ * This prevents prompt-injected tool calls from sending raw input to
28
+ * arbitrary apps without the user having approved control of that
29
+ * specific app.
30
+ *
31
+ * **No step cap.** Unlike {@link HostCuProxy} which enforces a per-session
32
+ * step ceiling via `loadConfig().maxStepsPerSession`, app-control sessions
33
+ * are not capped. App-control flows are typically narrower (single-app,
34
+ * shorter horizons) and the loop guard plus user oversight are the
35
+ * intended safeguards.
36
+ */
37
+
38
+ import { createHash } from "node:crypto";
39
+
40
+ import type { ContentBlock } from "../providers/types.js";
41
+ import type { ToolExecutionResult } from "../tools/types.js";
42
+ import { getLogger } from "../util/logger.js";
43
+ import { HostProxyBase, HostProxyRequestError } from "./host-proxy-base.js";
44
+ import type {
45
+ HostAppControlInput,
46
+ HostAppControlResultPayload,
47
+ } from "./message-types/host-app-control.js";
48
+
49
+ const log = getLogger("host-app-control-proxy");
50
+
51
+ // ---------------------------------------------------------------------------
52
+ // Constants
53
+ // ---------------------------------------------------------------------------
54
+
55
+ const REQUEST_TIMEOUT_MS = 60 * 1000;
56
+ // Threshold of 4 means the warning fires on the 5th identical observation:
57
+ // the first observation establishes the baseline (count = 0), each
58
+ // subsequent identical observation increments the counter, so count = 4 is
59
+ // reached on the 5th total observation.
60
+ const STUCK_REPEAT_THRESHOLD = 4;
61
+
62
+ // ---------------------------------------------------------------------------
63
+ // Module-level session lock
64
+ // ---------------------------------------------------------------------------
65
+
66
+ /**
67
+ * Active app-control session: the conversation that owns the lock and the
68
+ * `app` it was approved against. Set on a successful `app_control_start`;
69
+ * cleared by the owning proxy's `dispose()`.
70
+ */
71
+ export interface ActiveAppControlSession {
72
+ conversationId: string;
73
+ /**
74
+ * The exact `app` string the user approved at start time (bundle ID or
75
+ * process name — preserved as-is). Compared case-insensitively against
76
+ * the `app` of subsequent non-start tool calls.
77
+ */
78
+ app: string;
79
+ }
80
+
81
+ /**
82
+ * Currently active session, or `undefined` when no session is held.
83
+ *
84
+ * Exported for test inspection only. Production code paths must not read
85
+ * or mutate this directly — use the proxy methods.
86
+ */
87
+ let activeAppControlSession: ActiveAppControlSession | undefined;
88
+
89
+ /** Test-only helper: read current session. */
90
+ export function _getActiveAppControlSession():
91
+ | ActiveAppControlSession
92
+ | undefined {
93
+ return activeAppControlSession;
94
+ }
95
+
96
+ /** Test-only helper: clear session between test cases. */
97
+ export function _resetActiveAppControlSession(): void {
98
+ activeAppControlSession = undefined;
99
+ }
100
+
101
+ /**
102
+ * Test-only helper: prime the active session without a full `start` round-trip.
103
+ * Useful for tests that exercise non-start tool paths and don't need to
104
+ * verify the start flow itself.
105
+ */
106
+ export function _setActiveAppControlSession(
107
+ session: ActiveAppControlSession,
108
+ ): void {
109
+ activeAppControlSession = session;
110
+ }
111
+
112
+ /**
113
+ * Validate a non-start tool call against the active session. Returns a
114
+ * `ToolExecutionResult` (with `isError: true`) when the call should be
115
+ * rejected; returns `null` when the call is authorized to dispatch.
116
+ *
117
+ * `app` matching is case-insensitive (macOS bundle IDs are
118
+ * case-insensitive in practice) but strict on form: `"Safari"` and
119
+ * `"com.apple.Safari"` do not match — the user approved a specific string
120
+ * and substituting a different form requires a new approval.
121
+ */
122
+ function checkNonStartAuthorization(
123
+ input: HostAppControlInput,
124
+ conversationId: string,
125
+ ): ToolExecutionResult | null {
126
+ if (activeAppControlSession == null) {
127
+ return {
128
+ content:
129
+ "No app-control session is active. Call app_control_start to request " +
130
+ "user approval to control the target app, then retry.",
131
+ isError: true,
132
+ };
133
+ }
134
+ if (activeAppControlSession.conversationId !== conversationId) {
135
+ return {
136
+ content:
137
+ `Another conversation (${activeAppControlSession.conversationId}) currently ` +
138
+ `holds the app-control session. Wait for it to finish, or call ` +
139
+ `app_control_stop from that conversation first.`,
140
+ isError: true,
141
+ };
142
+ }
143
+ // `app` is required on every non-start variant of HostAppControlInput
144
+ // except `stop`, and `stop` short-circuits in conversation-surfaces and
145
+ // does not reach this method in production. A stop reaching here would
146
+ // be a defensive bug — surface it explicitly rather than dispatch.
147
+ const requestedApp = (input as { app?: string }).app;
148
+ if (requestedApp == null) {
149
+ return {
150
+ content:
151
+ "Tool input missing required 'app' field; cannot validate against " +
152
+ "the active app-control session.",
153
+ isError: true,
154
+ };
155
+ }
156
+ if (
157
+ requestedApp.toLowerCase() !== activeAppControlSession.app.toLowerCase()
158
+ ) {
159
+ return {
160
+ content:
161
+ `Active app-control session targets ${activeAppControlSession.app}; ` +
162
+ `cannot send actions to ${requestedApp}. Call app_control_stop and ` +
163
+ `app_control_start to switch apps.`,
164
+ isError: true,
165
+ };
166
+ }
167
+ return null;
168
+ }
169
+
170
+ // ---------------------------------------------------------------------------
171
+ // HostAppControlProxy
172
+ // ---------------------------------------------------------------------------
173
+
174
+ export class HostAppControlProxy extends HostProxyBase<
175
+ HostAppControlInput,
176
+ HostAppControlResultPayload
177
+ > {
178
+ /** Conversation that owns this proxy instance. Used by `dispose()` to release the session lock only when this proxy is the holder. */
179
+ private readonly conversationId: string;
180
+
181
+ /** sha256 hex of the most recent observation's `pngBase64`, or undefined. */
182
+ private lastObservationHash?: string;
183
+
184
+ /**
185
+ * Number of consecutive observations whose PNG hash matched the previous
186
+ * one. Reset to 0 when a different hash is observed. When this reaches
187
+ * {@link STUCK_REPEAT_THRESHOLD}, results carry a `"stuck"` warning.
188
+ */
189
+ private observationHashRepeatCount = 0;
190
+
191
+ constructor(conversationId: string) {
192
+ super({
193
+ capabilityName: "host_app_control",
194
+ requestEventName: "host_app_control_request",
195
+ cancelEventName: "host_app_control_cancel",
196
+ resultPendingKind: "host_app_control",
197
+ timeoutMs: REQUEST_TIMEOUT_MS,
198
+ disposedMessage: "Host app-control proxy disposed",
199
+ });
200
+ this.conversationId = conversationId;
201
+ }
202
+
203
+ // ---------------------------------------------------------------------------
204
+ // State accessors (testing / external inspection)
205
+ // ---------------------------------------------------------------------------
206
+
207
+ get observationRepeatCount(): number {
208
+ return this.observationHashRepeatCount;
209
+ }
210
+
211
+ // ---------------------------------------------------------------------------
212
+ // Public request entry point
213
+ // ---------------------------------------------------------------------------
214
+
215
+ /**
216
+ * Dispatch an app-control tool call to the desktop client. Catches the
217
+ * base's typed lifecycle errors (timeout/aborted/disposed) and returns
218
+ * a `ToolExecutionResult` instead of letting them bubble.
219
+ */
220
+ async request(
221
+ toolName: string,
222
+ input: HostAppControlInput,
223
+ conversationId: string,
224
+ signal: AbortSignal,
225
+ ): Promise<ToolExecutionResult> {
226
+ if (signal.aborted) {
227
+ return { content: "Aborted", isError: true };
228
+ }
229
+
230
+ // Authorization gate. `start` acquires the session lock (the user's
231
+ // medium-risk approval is the consent boundary); all other tools must
232
+ // belong to the active session and target the same `app`. Without this
233
+ // gate, prompt-injected calls would bypass the start-time approval and
234
+ // send raw input to arbitrary apps.
235
+ if (input.tool === "start") {
236
+ if (
237
+ activeAppControlSession != null &&
238
+ activeAppControlSession.conversationId !== conversationId
239
+ ) {
240
+ return {
241
+ content:
242
+ `Another conversation (${activeAppControlSession.conversationId}) currently holds the ` +
243
+ `app-control session. Wait for it to finish, or call app_control_stop ` +
244
+ `from that conversation first.`,
245
+ isError: true,
246
+ };
247
+ }
248
+ } else {
249
+ const sessionError = checkNonStartAuthorization(input, conversationId);
250
+ if (sessionError != null) {
251
+ return sessionError;
252
+ }
253
+ }
254
+
255
+ try {
256
+ const payload = await this.dispatchRequest(
257
+ toolName,
258
+ input,
259
+ conversationId,
260
+ signal,
261
+ );
262
+ return this.handleSuccess(input, payload);
263
+ } catch (err) {
264
+ if (err instanceof HostProxyRequestError) {
265
+ if (err.reason === "timeout") {
266
+ log.warn({ toolName }, "Host app-control proxy request timed out");
267
+ return {
268
+ content:
269
+ "Host app-control proxy timed out waiting for client response",
270
+ isError: true,
271
+ };
272
+ }
273
+ if (err.reason === "aborted") {
274
+ return { content: "Aborted", isError: true };
275
+ }
276
+ }
277
+ // `disposed` and any other unexpected errors propagate.
278
+ throw err;
279
+ }
280
+ }
281
+
282
+ // ---------------------------------------------------------------------------
283
+ // Result handling
284
+ // ---------------------------------------------------------------------------
285
+
286
+ private handleSuccess(
287
+ input: HostAppControlInput,
288
+ payload: HostAppControlResultPayload,
289
+ ): ToolExecutionResult {
290
+ // Update PNG-hash loop tracking only for the "running" state — other
291
+ // states (missing/minimized) intentionally won't carry a
292
+ // representative window screenshot, so they should not feed the guard.
293
+ let stuck = false;
294
+ if (payload.state === "running" && payload.pngBase64) {
295
+ const hash = createHash("sha256").update(payload.pngBase64).digest("hex");
296
+ if (hash === this.lastObservationHash) {
297
+ this.observationHashRepeatCount++;
298
+ } else {
299
+ this.observationHashRepeatCount = 0;
300
+ }
301
+ this.lastObservationHash = hash;
302
+ if (this.observationHashRepeatCount >= STUCK_REPEAT_THRESHOLD) {
303
+ stuck = true;
304
+ }
305
+ }
306
+
307
+ // Store the exact `app` form for validation against subsequent
308
+ // non-start tool calls.
309
+ if (input.tool === "start" && payload.state === "running") {
310
+ activeAppControlSession = {
311
+ conversationId: this.conversationId,
312
+ app: input.app,
313
+ };
314
+ }
315
+
316
+ return this.formatResult(payload, stuck);
317
+ }
318
+
319
+ private formatResult(
320
+ payload: HostAppControlResultPayload,
321
+ stuck: boolean,
322
+ ): ToolExecutionResult {
323
+ const parts: string[] = [];
324
+
325
+ if (stuck) {
326
+ parts.push(
327
+ `WARNING: ${this.observationHashRepeatCount} consecutive observations ` +
328
+ `produced an identical screenshot — the app appears stuck. Try a ` +
329
+ `different action or call app_control_stop and restart.`,
330
+ );
331
+ parts.push("");
332
+ }
333
+
334
+ parts.push(`State: ${payload.state}`);
335
+
336
+ if (payload.windowBounds) {
337
+ const { x, y, width, height } = payload.windowBounds;
338
+ parts.push(`Window bounds: ${width}x${height} at (${x}, ${y})`);
339
+ }
340
+
341
+ if (payload.executionResult) {
342
+ parts.push("");
343
+ parts.push(payload.executionResult);
344
+ }
345
+
346
+ const isError = payload.executionError != null;
347
+ const errorPrefix = isError
348
+ ? `Action failed: ${payload.executionError}`
349
+ : null;
350
+
351
+ const baseContent = parts.join("\n").trim() || `State: ${payload.state}`;
352
+ const content = errorPrefix
353
+ ? `${errorPrefix}\n\n${baseContent}`
354
+ : baseContent;
355
+
356
+ const contentBlocks: ContentBlock[] = [];
357
+ if (payload.pngBase64) {
358
+ contentBlocks.push({
359
+ type: "image",
360
+ source: {
361
+ type: "base64",
362
+ media_type: "image/png",
363
+ data: payload.pngBase64,
364
+ },
365
+ });
366
+ }
367
+
368
+ return {
369
+ content,
370
+ isError,
371
+ ...(contentBlocks.length > 0 ? { contentBlocks } : {}),
372
+ };
373
+ }
374
+
375
+ // ---------------------------------------------------------------------------
376
+ // Lifecycle
377
+ // ---------------------------------------------------------------------------
378
+
379
+ /**
380
+ * Reject pending requests via the base, then release the session lock
381
+ * if this proxy is the holder. Idempotent: safe to call multiple times.
382
+ */
383
+ override dispose(): void {
384
+ super.dispose();
385
+ if (activeAppControlSession?.conversationId === this.conversationId) {
386
+ activeAppControlSession = undefined;
387
+ }
388
+ }
389
+ }
@@ -5,25 +5,19 @@ import {
5
5
  assistantEventHub,
6
6
  broadcastMessage,
7
7
  } from "../runtime/assistant-event-hub.js";
8
+ import {
9
+ ambiguousSameUserError,
10
+ enforceSameActorOrErrorResult,
11
+ pickSameUserAutoResolve,
12
+ } from "../runtime/auth/same-actor.js";
8
13
  import * as pendingInteractions from "../runtime/pending-interactions.js";
9
14
  import { formatShellOutput } from "../tools/shared/shell-output.js";
10
15
  import type { ToolExecutionResult } from "../tools/types.js";
11
16
  import { AssistantError, ErrorCode } from "../util/errors.js";
12
17
  import { getLogger } from "../util/logger.js";
13
- import type { ServerMessage } from "./message-protocol.js";
14
18
 
15
19
  const log = getLogger("host-bash-proxy");
16
20
 
17
- interface PendingRequest {
18
- resolve: (result: ToolExecutionResult) => void;
19
- reject: (err: Error) => void;
20
- timer: ReturnType<typeof setTimeout>;
21
- timeoutSec: number;
22
- conversationId: string;
23
- /** Detach the abort listener from the caller's signal. No-op when no signal was passed. */
24
- detachAbort: () => void;
25
- }
26
-
27
21
  export class HostBashProxy {
28
22
  private static _instance: HostBashProxy | null = null;
29
23
 
@@ -53,8 +47,6 @@ export class HostBashProxy {
53
47
  HostBashProxy._instance = null;
54
48
  }
55
49
 
56
- private pending = new Map<string, PendingRequest>();
57
-
58
50
  /**
59
51
  * Whether a client with `host_bash` capability is connected.
60
52
  */
@@ -64,71 +56,105 @@ export class HostBashProxy {
64
56
  );
65
57
  }
66
58
 
67
- private send(msg: ServerMessage): void {
68
- broadcastMessage(msg, undefined, { targetCapability: "host_bash" });
69
- }
70
-
71
59
  request(
72
60
  input: {
73
61
  command: string;
74
62
  working_dir?: string;
75
63
  timeout_seconds?: number;
76
64
  env?: Record<string, string>;
65
+ targetClientId?: string;
77
66
  },
78
67
  conversationId: string,
79
68
  signal?: AbortSignal,
69
+ // Principal ID of the actor on whose behalf this request is initiated.
70
+ sourceActorPrincipalId?: string,
80
71
  ): Promise<ToolExecutionResult> {
81
72
  if (signal?.aborted) {
82
73
  const result = formatShellOutput("", "Aborted", null, false, 0);
83
74
  return Promise.resolve(result);
84
75
  }
85
76
 
77
+ let resolvedTargetClientId: string | undefined;
78
+
79
+ if (input.targetClientId) {
80
+ const target = assistantEventHub.getClientById(input.targetClientId);
81
+ if (!target || !target.capabilities.includes("host_bash")) {
82
+ return Promise.resolve({
83
+ content: `Error: client "${input.targetClientId}" is not connected or does not support host_bash. Run \`assistant clients list --capability host_bash\` to see available clients.`,
84
+ isError: true,
85
+ });
86
+ }
87
+ resolvedTargetClientId = input.targetClientId;
88
+ } else {
89
+ // Auto-resolve to the unique same-user client. Reject (rather than
90
+ // broadcast) when multiple same-user clients are connected so that
91
+ // a single targeted-style request cannot fan out across every one
92
+ // of the user's machines. Zero same-user matches falls through to
93
+ // the existing untargeted code path.
94
+ const resolved = pickSameUserAutoResolve({
95
+ hub: assistantEventHub,
96
+ capability: "host_bash",
97
+ sourceActorPrincipalId,
98
+ });
99
+ if (resolved.kind === "ambiguous") {
100
+ return Promise.resolve(ambiguousSameUserError("host_bash"));
101
+ }
102
+ resolvedTargetClientId =
103
+ resolved.kind === "match" ? resolved.clientId : undefined;
104
+ }
105
+
106
+ // Targeted requests must be bound to the same authenticated user as the
107
+ // target client. Fail closed at request time — before pendingInteractions
108
+ // registration and before broadcast — so a same-daemon caller cannot
109
+ // execute on another user's connected client.
110
+ if (resolvedTargetClientId != null) {
111
+ const rejection = enforceSameActorOrErrorResult({
112
+ hub: assistantEventHub,
113
+ sourceActorPrincipalId,
114
+ targetClientId: resolvedTargetClientId,
115
+ op: "host_bash",
116
+ });
117
+ if (rejection) return Promise.resolve(rejection);
118
+ }
119
+
86
120
  const requestId = uuid();
87
121
 
88
122
  return new Promise<ToolExecutionResult>((resolve, reject) => {
89
123
  const shellMaxTimeoutSec = getConfig().timeouts.shellMaxTimeoutSec;
90
124
  const timeoutSec = input.timeout_seconds ?? shellMaxTimeoutSec;
91
- // Proxy timeout: slightly after client-side timeout, but before executor's outer timeout
92
125
  const proxyTimeoutSec = timeoutSec + 3;
93
126
 
94
- // Declared up-front so onAbort (defined before detachAbort is assigned)
95
- // can close over a stable reference once it's wired below.
96
127
  let detachAbort: () => void = () => {};
97
128
 
98
129
  const timer = setTimeout(() => {
99
- this.pending.delete(requestId);
100
- detachAbort();
101
130
  pendingInteractions.resolve(requestId);
102
131
  log.warn(
103
132
  { requestId, command: input.command },
104
133
  "Host bash proxy request timed out",
105
134
  );
106
- resolve(
107
- formatShellOutput(
108
- "",
109
- "Host bash proxy timed out waiting for client response",
110
- null,
111
- true,
112
- timeoutSec,
113
- ),
114
- );
135
+ const timeoutMessage = resolvedTargetClientId
136
+ ? `Host bash proxy timed out waiting for response from client ${resolvedTargetClientId}`
137
+ : "Host bash proxy timed out waiting for client response";
138
+ resolve(formatShellOutput("", timeoutMessage, null, true, timeoutSec));
115
139
  }, proxyTimeoutSec * 1000);
116
140
 
117
141
  if (signal) {
118
142
  const onAbort = () => {
119
- if (this.pending.has(requestId)) {
120
- clearTimeout(timer);
121
- this.pending.delete(requestId);
122
- detachAbort();
143
+ if (pendingInteractions.get(requestId)) {
123
144
  pendingInteractions.resolve(requestId);
124
145
  try {
125
- this.send({
126
- type: "host_bash_cancel",
127
- requestId,
146
+ broadcastMessage(
147
+ {
148
+ type: "host_bash_cancel",
149
+ requestId,
150
+ conversationId,
151
+ targetClientId: resolvedTargetClientId,
152
+ },
128
153
  conversationId,
129
- });
154
+ { targetClientId: resolvedTargetClientId },
155
+ );
130
156
  } catch {
131
- // Best-effort cancel notification — connection may already be closed.
157
+ // Best-effort cancel notification
132
158
  }
133
159
  resolve(formatShellOutput("", "Aborted", null, false, 0));
134
160
  }
@@ -137,31 +163,41 @@ export class HostBashProxy {
137
163
  detachAbort = () => signal.removeEventListener("abort", onAbort);
138
164
  }
139
165
 
140
- this.pending.set(requestId, {
141
- resolve,
142
- reject,
143
- timer,
144
- timeoutSec,
166
+ pendingInteractions.register(requestId, {
145
167
  conversationId,
168
+ kind: "host_bash",
169
+ rpcResolve: resolve,
170
+ rpcReject: reject,
171
+ timer,
146
172
  detachAbort,
173
+ targetClientId: resolvedTargetClientId,
174
+ targetActorPrincipalId:
175
+ resolvedTargetClientId != null
176
+ ? assistantEventHub.getActorPrincipalIdForClient(
177
+ resolvedTargetClientId,
178
+ )
179
+ : undefined,
180
+ metadata: { timeoutSec },
147
181
  });
148
182
 
149
183
  try {
150
- this.send({
151
- type: "host_bash_request",
152
- requestId,
153
- conversationId,
154
- command: input.command,
155
- working_dir: input.working_dir,
156
- timeout_seconds: input.timeout_seconds,
157
- ...(input.env && Object.keys(input.env).length > 0
184
+ broadcastMessage(
185
+ {
186
+ type: "host_bash_request",
187
+ requestId,
188
+ conversationId,
189
+ command: input.command,
190
+ working_dir: input.working_dir,
191
+ timeout_seconds: input.timeout_seconds,
192
+ targetClientId: resolvedTargetClientId,
193
+ ...(input.env && Object.keys(input.env).length > 0
158
194
  ? { env: input.env }
159
195
  : {}),
160
- });
196
+ },
197
+ conversationId,
198
+ { targetClientId: resolvedTargetClientId },
199
+ );
161
200
  } catch (err) {
162
- clearTimeout(timer);
163
- this.pending.delete(requestId);
164
- detachAbort();
165
201
  pendingInteractions.resolve(requestId);
166
202
  log.warn(
167
203
  { requestId, command: input.command, err },
@@ -172,7 +208,10 @@ export class HostBashProxy {
172
208
  });
173
209
  }
174
210
 
175
- resolve(
211
+ /**
212
+ * Process a client result and resolve the RPC. Called by route handlers.
213
+ */
214
+ resolveResult(
176
215
  requestId: string,
177
216
  response: {
178
217
  stdout: string;
@@ -181,49 +220,45 @@ export class HostBashProxy {
181
220
  timedOut: boolean;
182
221
  },
183
222
  ): void {
184
- const entry = this.pending.get(requestId);
185
- if (!entry) {
223
+ const interaction = pendingInteractions.resolve(requestId);
224
+ if (!interaction?.rpcResolve) {
186
225
  log.warn({ requestId }, "No pending host bash request for response");
187
226
  return;
188
227
  }
189
- clearTimeout(entry.timer);
190
- entry.detachAbort();
191
- this.pending.delete(requestId);
228
+ const timeoutSec = (interaction.metadata?.timeoutSec as number) ?? 0;
192
229
  const result = formatShellOutput(
193
230
  response.stdout,
194
231
  response.stderr,
195
232
  response.exitCode,
196
233
  response.timedOut,
197
- entry.timeoutSec,
234
+ timeoutSec,
198
235
  );
199
- entry.resolve(result);
200
- }
201
-
202
- hasPendingRequest(requestId: string): boolean {
203
- return this.pending.has(requestId);
236
+ interaction.rpcResolve(result);
204
237
  }
205
238
 
206
239
  dispose(): void {
207
- for (const [requestId, entry] of this.pending) {
208
- clearTimeout(entry.timer);
209
- entry.detachAbort();
210
- pendingInteractions.resolve(requestId);
211
- try {
212
- this.send({
240
+ for (const entry of pendingInteractions.getByKind("host_bash")) {
241
+ pendingInteractions.resolve(entry.requestId);
242
+ try {
243
+ broadcastMessage(
244
+ {
213
245
  type: "host_bash_cancel",
214
- requestId,
246
+ requestId: entry.requestId,
215
247
  conversationId: entry.conversationId,
216
- });
217
- } catch {
218
- // Best-effort cancel notification — connection may already be closed.
219
- }
220
- entry.reject(
248
+ targetClientId: entry.targetClientId,
249
+ },
250
+ entry.conversationId,
251
+ { targetClientId: entry.targetClientId },
252
+ );
253
+ } catch {
254
+ // Best-effort cancel notification — connection may already be closed.
255
+ }
256
+ entry.rpcReject?.(
221
257
  new AssistantError(
222
258
  "Host bash proxy disposed",
223
259
  ErrorCode.INTERNAL_ERROR,
224
260
  ),
225
261
  );
226
262
  }
227
- this.pending.clear();
228
263
  }
229
264
  }