@vellumai/assistant 0.7.2 → 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 (347) hide show
  1. package/ARCHITECTURE.md +16 -1
  2. package/docs/architecture/memory.md +5 -2
  3. package/node_modules/@vellumai/gateway-client/src/ipc-client.ts +13 -4
  4. package/node_modules/@vellumai/skill-host-contracts/src/assistant-event.ts +0 -9
  5. package/node_modules/@vellumai/slack-text/src/index.test.ts +18 -35
  6. package/node_modules/@vellumai/slack-text/src/index.ts +2 -48
  7. package/openapi.yaml +449 -22
  8. package/package.json +1 -1
  9. package/src/__tests__/app-control-flow.test.ts +21 -11
  10. package/src/__tests__/assistant-event-hub.test.ts +48 -0
  11. package/src/__tests__/assistant-event.test.ts +0 -10
  12. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -7
  13. package/src/__tests__/assistant-feature-flags-integration.test.ts +18 -0
  14. package/src/__tests__/auto-analysis-end-to-end.test.ts +62 -1
  15. package/src/__tests__/background-workers-disk-pressure.test.ts +268 -0
  16. package/src/__tests__/call-conversation-messages.test.ts +8 -2
  17. package/src/__tests__/channel-inbound-disk-pressure.test.ts +537 -0
  18. package/src/__tests__/channel-readiness-service.test.ts +4 -2
  19. package/src/__tests__/config-loader-backfill.test.ts +379 -0
  20. package/src/__tests__/config-schema.test.ts +1 -0
  21. package/src/__tests__/config-watcher-cleanup-throttle.test.ts +18 -9
  22. package/src/__tests__/config-watcher.test.ts +140 -69
  23. package/src/__tests__/context-search-agent-runner.test.ts +61 -3
  24. package/src/__tests__/context-search-conversations-source.test.ts +0 -24
  25. package/src/__tests__/context-search-fanout.test.ts +0 -1
  26. package/src/__tests__/context-search-memory-source.test.ts +3 -7
  27. package/src/__tests__/context-search-memory-v2-source.test.ts +0 -2
  28. package/src/__tests__/context-search-pkb-source.test.ts +0 -1
  29. package/src/__tests__/context-search-workspace-source.test.ts +0 -1
  30. package/src/__tests__/conversation-abort-tool-results.test.ts +6 -0
  31. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +223 -0
  32. package/src/__tests__/conversation-agent-loop.test.ts +454 -5
  33. package/src/__tests__/conversation-error.test.ts +150 -3
  34. package/src/__tests__/conversation-process-callsite.test.ts +43 -0
  35. package/src/__tests__/conversation-provider-retry-repair.test.ts +6 -0
  36. package/src/__tests__/conversation-runtime-assembly.test.ts +65 -0
  37. package/src/__tests__/conversation-slash-unknown.test.ts +6 -0
  38. package/src/__tests__/conversation-speed-override.test.ts +0 -3
  39. package/src/__tests__/conversation-store.test.ts +0 -18
  40. package/src/__tests__/conversation-surfaces-app-control.test.ts +15 -4
  41. package/src/__tests__/conversation-surfaces-data-persist.test.ts +404 -0
  42. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +2 -5
  43. package/src/__tests__/conversation-workspace-injection.test.ts +6 -0
  44. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +6 -0
  45. package/src/__tests__/credentials-cli.test.ts +7 -0
  46. package/src/__tests__/cu-unified-flow.test.ts +176 -10
  47. package/src/__tests__/date-context.test.ts +164 -2
  48. package/src/__tests__/disk-pressure-guard.test.ts +262 -0
  49. package/src/__tests__/disk-pressure-lifecycle.test.ts +168 -0
  50. package/src/__tests__/disk-pressure-policy.test.ts +241 -0
  51. package/src/__tests__/disk-pressure-routes.test.ts +379 -0
  52. package/src/__tests__/disk-pressure-tools.test.ts +277 -0
  53. package/src/__tests__/disk-usage.test.ts +150 -0
  54. package/src/__tests__/events-client-registration.test.ts +52 -0
  55. package/src/__tests__/events-dev-bypass-actor.test.ts +162 -0
  56. package/src/__tests__/file-write-tool.test.ts +4 -10
  57. package/src/__tests__/filing-service.test.ts +3 -4
  58. package/src/__tests__/heartbeat-disk-pressure.test.ts +183 -0
  59. package/src/__tests__/heartbeat-service.test.ts +260 -11
  60. package/src/__tests__/host-app-control-proxy.test.ts +195 -25
  61. package/src/__tests__/host-bash-proxy.test.ts +227 -34
  62. package/src/__tests__/host-bash-routes.test.ts +178 -13
  63. package/src/__tests__/host-cu-proxy.test.ts +210 -3
  64. package/src/__tests__/host-cu-routes-targeted.test.ts +141 -12
  65. package/src/__tests__/host-file-proxy-targeted.test.ts +48 -9
  66. package/src/__tests__/host-file-proxy.test.ts +268 -6
  67. package/src/__tests__/host-file-routes-targeted.test.ts +175 -17
  68. package/src/__tests__/host-transfer-proxy-targeted.test.ts +408 -59
  69. package/src/__tests__/host-transfer-routes-targeted.test.ts +232 -17
  70. package/src/__tests__/http-user-message-parity.test.ts +107 -1
  71. package/src/__tests__/injector-chain.test.ts +18 -6
  72. package/src/__tests__/injector-disk-pressure.test.ts +224 -0
  73. package/src/__tests__/managed-profile-guard.test.ts +18 -0
  74. package/src/__tests__/mcp-abort-signal.test.ts +130 -0
  75. package/src/__tests__/memory-admin-recall.test.ts +3 -11
  76. package/src/__tests__/memory-retrieval-pipeline.test.ts +22 -1
  77. package/src/__tests__/normalize-onboarding.test.ts +180 -0
  78. package/src/__tests__/oauth-connect-routes.test.ts +316 -0
  79. package/src/__tests__/oauth-provider-seed-logos.test.ts +24 -2
  80. package/src/__tests__/onboarding-persona-write.test.ts +308 -0
  81. package/src/__tests__/openai-provider.test.ts +45 -8
  82. package/src/__tests__/persist-onboarding-artifacts.test.ts +44 -64
  83. package/src/__tests__/platform-callback-registration.test.ts +21 -4
  84. package/src/__tests__/platform.test.ts +2 -1
  85. package/src/__tests__/playbook-execution.test.ts +0 -43
  86. package/src/__tests__/plugin-tool-contribution.test.ts +47 -0
  87. package/src/__tests__/prechat-onboarding-contract.test.ts +214 -27
  88. package/src/__tests__/provider-tool-name.test.ts +23 -0
  89. package/src/__tests__/relay-server.test.ts +15 -4
  90. package/src/__tests__/runtime-events-sse.test.ts +4 -8
  91. package/src/__tests__/scheduler-disk-pressure.test.ts +148 -0
  92. package/src/__tests__/secret-ingress-http.test.ts +0 -1
  93. package/src/__tests__/suggestion-routes.test.ts +46 -0
  94. package/src/__tests__/twilio-validation.test.ts +2 -2
  95. package/src/__tests__/workspace-migration-065-bump-stale-heartbeat-interval.test.ts +122 -0
  96. package/src/__tests__/workspace-migration-066-seed-heartbeat-callsite-cost-default.test.ts +285 -0
  97. package/src/__tests__/workspace-migration-068-release-notes-local-timezone.test.ts +90 -0
  98. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +90 -0
  99. package/src/approvals/guardian-decision-primitive.ts +13 -0
  100. package/src/approvals/guardian-request-resolvers.ts +16 -17
  101. package/src/backup/snapshot-lock.ts +2 -27
  102. package/src/bundler/compiler-tools.ts +3 -2
  103. package/src/calls/call-conversation-messages.ts +46 -10
  104. package/src/cli/commands/__tests__/webhooks.test.ts +0 -4
  105. package/src/cli/commands/bash.ts +35 -108
  106. package/src/cli/commands/contacts.ts +64 -25
  107. package/src/cli/commands/credentials.ts +56 -0
  108. package/src/cli/commands/memory-v2.ts +7 -6
  109. package/src/cli/commands/oauth/__tests__/connect.test.ts +437 -1
  110. package/src/cli/commands/oauth/connect.ts +127 -1
  111. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -3
  112. package/src/cli/commands/platform/__tests__/connect.test.ts +7 -1
  113. package/src/cli/commands/platform/__tests__/disconnect.test.ts +7 -1
  114. package/src/cli/commands/platform/__tests__/status.test.ts +103 -6
  115. package/src/cli/commands/platform/index.ts +16 -7
  116. package/src/cli/commands/status.ts +57 -0
  117. package/src/cli/program.ts +4 -2
  118. package/src/config/assistant-feature-flags.ts +13 -3
  119. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +4 -3
  120. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +13 -7
  121. package/src/config/bundled-skills/playbooks/tools/playbook-create.ts +2 -2
  122. package/src/config/bundled-skills/playbooks/tools/playbook-delete.ts +2 -2
  123. package/src/config/bundled-skills/playbooks/tools/playbook-list.ts +2 -2
  124. package/src/config/bundled-skills/playbooks/tools/playbook-update.ts +2 -2
  125. package/src/config/env.ts +0 -8
  126. package/src/config/feature-flag-registry.json +27 -3
  127. package/src/config/loader.ts +127 -8
  128. package/src/config/schemas/__tests__/memory-v2.test.ts +10 -5
  129. package/src/config/schemas/call-site-catalog.ts +14 -0
  130. package/src/config/schemas/channels.ts +0 -5
  131. package/src/config/schemas/heartbeat.ts +1 -1
  132. package/src/config/schemas/llm.ts +2 -0
  133. package/src/config/schemas/memory-lifecycle.ts +13 -0
  134. package/src/config/schemas/memory-v2.ts +75 -11
  135. package/src/config/schemas/platform.ts +43 -3
  136. package/src/config/schemas/services.ts +28 -0
  137. package/src/config/seed-inference-profiles.ts +230 -33
  138. package/src/contacts/contact-store.ts +0 -25
  139. package/src/daemon/__tests__/conversation-tool-setup.test.ts +86 -25
  140. package/src/daemon/assistant-attachments.ts +4 -4
  141. package/src/daemon/config-watcher.ts +85 -57
  142. package/src/daemon/conversation-agent-loop-handlers.ts +6 -0
  143. package/src/daemon/conversation-agent-loop.ts +170 -33
  144. package/src/daemon/conversation-error.ts +87 -15
  145. package/src/daemon/conversation-lifecycle.ts +1 -3
  146. package/src/daemon/conversation-process.ts +8 -0
  147. package/src/daemon/conversation-runtime-assembly.ts +26 -0
  148. package/src/daemon/conversation-store.ts +2 -2
  149. package/src/daemon/conversation-surfaces.ts +195 -15
  150. package/src/daemon/conversation-tool-setup.ts +57 -14
  151. package/src/daemon/conversation.ts +17 -22
  152. package/src/daemon/date-context.ts +71 -22
  153. package/src/daemon/disk-pressure-background-gate.ts +73 -0
  154. package/src/daemon/disk-pressure-guard.ts +343 -0
  155. package/src/daemon/disk-pressure-policy.ts +163 -0
  156. package/src/daemon/handlers/shared.ts +0 -1
  157. package/src/daemon/handlers/skills.ts +3 -4
  158. package/src/daemon/host-app-control-proxy.ts +137 -41
  159. package/src/daemon/host-bash-proxy.ts +46 -21
  160. package/src/daemon/host-cu-proxy.ts +49 -3
  161. package/src/daemon/host-file-proxy.ts +43 -7
  162. package/src/daemon/host-transfer-proxy.ts +95 -4
  163. package/src/daemon/lifecycle.ts +79 -28
  164. package/src/daemon/meet-host-supervisor.ts +4 -4
  165. package/src/daemon/meet-manifest-loader.ts +0 -1
  166. package/src/daemon/memory-v2-startup.ts +14 -4
  167. package/src/daemon/message-protocol.ts +3 -0
  168. package/src/daemon/message-types/conversations.ts +4 -0
  169. package/src/daemon/message-types/disk-pressure.ts +9 -0
  170. package/src/daemon/message-types/messages.ts +3 -0
  171. package/src/daemon/profiler-run-store.ts +5 -5
  172. package/src/daemon/tool-setup-types.ts +2 -2
  173. package/src/documents/document-store.ts +85 -0
  174. package/src/filing/filing-service.ts +30 -5
  175. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +9 -16
  176. package/src/heartbeat/__tests__/heartbeat-run-store.test.ts +36 -0
  177. package/src/heartbeat/heartbeat-run-store.ts +13 -0
  178. package/src/heartbeat/heartbeat-service.ts +205 -31
  179. package/src/home/feed-scheduler.ts +18 -0
  180. package/src/inbound/platform-callback-registration.ts +8 -15
  181. package/src/ipc/__tests__/clients-list-ipc.test.ts +169 -0
  182. package/src/ipc/assistant-server.ts +56 -2
  183. package/src/ipc/gateway-client.ts +37 -3
  184. package/src/live-voice/live-voice-archive.ts +4 -4
  185. package/src/live-voice/protocol.ts +5 -7
  186. package/src/media/image-service.ts +1 -7
  187. package/src/memory/__tests__/fixtures/memory-v2-activation-fixtures.ts +21 -13
  188. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +52 -22
  189. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +0 -6
  190. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +272 -0
  191. package/src/memory/admin.ts +5 -9
  192. package/src/memory/context-search/agent-runner.ts +19 -2
  193. package/src/memory/context-search/sources/conversations.ts +2 -11
  194. package/src/memory/context-search/sources/memory-v2.ts +5 -4
  195. package/src/memory/context-search/sources/memory.ts +0 -1
  196. package/src/memory/context-search/types.ts +0 -1
  197. package/src/memory/conversation-crud.ts +4 -12
  198. package/src/memory/db-init.ts +2 -0
  199. package/src/memory/embedding-runtime-manager.ts +119 -5
  200. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +32 -21
  201. package/src/memory/graph/conversation-graph-memory.ts +42 -54
  202. package/src/memory/graph/extraction.ts +1 -3
  203. package/src/memory/graph/graph-search.test.ts +10 -67
  204. package/src/memory/graph/graph-search.ts +1 -20
  205. package/src/memory/graph/retriever.test.ts +6 -0
  206. package/src/memory/graph/retriever.ts +6 -10
  207. package/src/memory/indexer.ts +54 -45
  208. package/src/memory/job-handlers/backfill.ts +2 -11
  209. package/src/memory/job-handlers/cleanup.ts +43 -0
  210. package/src/memory/job-handlers/embedding.ts +6 -8
  211. package/src/memory/job-handlers/summarization.ts +2 -7
  212. package/src/memory/jobs-store.ts +48 -0
  213. package/src/memory/jobs-worker.ts +81 -43
  214. package/src/memory/memory-v2-activation-log-store.ts +32 -14
  215. package/src/memory/memory-v2-concept-frequency.ts +169 -0
  216. package/src/memory/migrations/239-trace-events-created-at-index.ts +18 -0
  217. package/src/memory/migrations/index.ts +1 -0
  218. package/src/memory/pkb/pkb-search.test.ts +6 -0
  219. package/src/memory/qdrant-client.ts +0 -13
  220. package/src/memory/rerank-local.ts +374 -0
  221. package/src/memory/search/semantic.ts +6 -67
  222. package/src/memory/trace-event-store.ts +1 -17
  223. package/src/memory/v2/__tests__/activation.test.ts +311 -250
  224. package/src/memory/v2/__tests__/consolidation-job.test.ts +40 -8
  225. package/src/memory/v2/__tests__/injection.test.ts +157 -167
  226. package/src/memory/v2/__tests__/prompts-consolidation.test.ts +61 -2
  227. package/src/memory/v2/__tests__/qdrant.test.ts +16 -0
  228. package/src/memory/v2/__tests__/reranker.test.ts +338 -0
  229. package/src/memory/v2/__tests__/sim.test.ts +5 -199
  230. package/src/memory/v2/__tests__/skill-store.test.ts +71 -65
  231. package/src/memory/v2/__tests__/static-context.test.ts +76 -1
  232. package/src/memory/v2/activation.ts +149 -156
  233. package/src/memory/v2/consolidation-job.ts +62 -12
  234. package/src/memory/v2/injection.ts +47 -60
  235. package/src/memory/v2/prompts/consolidation.ts +36 -1
  236. package/src/memory/v2/qdrant.ts +99 -0
  237. package/src/memory/v2/reranker.ts +177 -0
  238. package/src/memory/v2/sim.ts +10 -84
  239. package/src/memory/v2/skill-content.ts +4 -3
  240. package/src/memory/v2/skill-store.ts +82 -59
  241. package/src/memory/v2/static-context.ts +22 -0
  242. package/src/memory/v2/types.ts +10 -10
  243. package/src/notifications/copy-composer.ts +13 -0
  244. package/src/notifications/signal.ts +4 -0
  245. package/src/oauth/AGENTS.md +3 -1
  246. package/src/oauth/__tests__/oauth-connect-state.test.ts +137 -0
  247. package/src/oauth/connect-orchestrator.ts +2 -0
  248. package/src/oauth/connection-resolver.test.ts +66 -1
  249. package/src/oauth/connection-resolver.ts +55 -1
  250. package/src/oauth/oauth-connect-state.ts +77 -0
  251. package/src/oauth/seed-providers.ts +58 -1
  252. package/src/plugins/defaults/injectors.ts +35 -2
  253. package/src/plugins/defaults/memory-retrieval.ts +5 -6
  254. package/src/plugins/types.ts +7 -0
  255. package/src/proactive-artifact/aux-message-injector.ts +74 -0
  256. package/src/proactive-artifact/decision.test.ts +226 -0
  257. package/src/proactive-artifact/decision.ts +165 -0
  258. package/src/proactive-artifact/index.ts +7 -0
  259. package/src/proactive-artifact/job.test.ts +867 -0
  260. package/src/proactive-artifact/job.ts +352 -0
  261. package/src/proactive-artifact/message-copy.ts +41 -0
  262. package/src/proactive-artifact/trigger-state.test.ts +277 -0
  263. package/src/proactive-artifact/trigger-state.ts +119 -0
  264. package/src/prompts/normalize-onboarding.ts +80 -0
  265. package/src/prompts/persona-resolver.ts +101 -9
  266. package/src/prompts/system-prompt.ts +21 -7
  267. package/src/prompts/templates/BOOTSTRAP.md +13 -5
  268. package/src/providers/__tests__/retry-callsite.test.ts +222 -1
  269. package/src/providers/model-intents.ts +7 -0
  270. package/src/providers/openrouter/client.ts +8 -0
  271. package/src/providers/retry.ts +50 -0
  272. package/src/providers/types.ts +1 -0
  273. package/src/runtime/__tests__/agent-wake.test.ts +456 -3
  274. package/src/runtime/agent-wake.ts +238 -100
  275. package/src/runtime/assistant-event-hub.ts +36 -6
  276. package/src/runtime/assistant-event.ts +0 -1
  277. package/src/runtime/auth/__tests__/route-policy.test.ts +64 -0
  278. package/src/runtime/auth/route-policy.ts +14 -1
  279. package/src/runtime/auth/same-actor.ts +216 -0
  280. package/src/runtime/channel-retry-sweep.ts +65 -1
  281. package/src/runtime/guardian-reply-router.ts +10 -0
  282. package/src/runtime/local-actor-identity.ts +52 -11
  283. package/src/runtime/pending-interactions.ts +8 -0
  284. package/src/runtime/routes/__tests__/client-routes.test.ts +155 -0
  285. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +0 -5
  286. package/src/runtime/routes/__tests__/heartbeat-routes.test.ts +1 -1
  287. package/src/runtime/routes/client-routes.ts +20 -2
  288. package/src/runtime/routes/contact-routes.ts +0 -25
  289. package/src/runtime/routes/conversation-routes.ts +35 -26
  290. package/src/runtime/routes/debug-bash-routes.ts +163 -0
  291. package/src/runtime/routes/disk-pressure-routes.ts +121 -0
  292. package/src/runtime/routes/document-pdf-renderer.ts +6 -2
  293. package/src/runtime/routes/documents-routes.ts +2 -75
  294. package/src/runtime/routes/events-routes.ts +41 -9
  295. package/src/runtime/routes/host-bash-routes.ts +23 -3
  296. package/src/runtime/routes/host-cu-routes.ts +33 -6
  297. package/src/runtime/routes/host-file-routes.ts +32 -6
  298. package/src/runtime/routes/host-transfer-routes.ts +79 -16
  299. package/src/runtime/routes/identity-routes.ts +7 -138
  300. package/src/runtime/routes/inbound-message-handler.ts +77 -12
  301. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +3 -0
  302. package/src/runtime/routes/index.ts +6 -0
  303. package/src/runtime/routes/memory-item-routes.test.ts +41 -15
  304. package/src/runtime/routes/memory-v2-routes.ts +33 -0
  305. package/src/runtime/routes/oauth-connect-routes.ts +153 -0
  306. package/src/runtime/verification-outbound-actions.ts +4 -4
  307. package/src/schedule/run-script.ts +37 -5
  308. package/src/schedule/scheduler.ts +20 -1
  309. package/src/security/encrypted-store.ts +2 -0
  310. package/src/security/secure-keys.ts +55 -0
  311. package/src/skills/remote-skill-policy.ts +4 -10
  312. package/src/subagent/index.ts +1 -7
  313. package/src/subagent/manager.ts +1 -15
  314. package/src/tasks/task-runner.ts +0 -1
  315. package/src/tasks/task-store.ts +0 -3
  316. package/src/tools/background-tool-registry.ts +17 -3
  317. package/src/tools/host-filesystem/edit.test.ts +151 -0
  318. package/src/tools/host-filesystem/edit.ts +43 -1
  319. package/src/tools/host-filesystem/read.test.ts +129 -0
  320. package/src/tools/host-filesystem/read.ts +43 -1
  321. package/src/tools/host-filesystem/transfer.test.ts +127 -2
  322. package/src/tools/host-filesystem/transfer.ts +56 -11
  323. package/src/tools/host-filesystem/write.test.ts +134 -0
  324. package/src/tools/host-filesystem/write.ts +43 -1
  325. package/src/tools/host-terminal/host-shell.ts +13 -6
  326. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  327. package/src/tools/memory/register.test.ts +12 -9
  328. package/src/tools/memory/register.ts +1 -2
  329. package/src/tools/provider-tool-name.ts +28 -0
  330. package/src/tools/registry.ts +30 -9
  331. package/src/tools/terminal/shell.ts +9 -1
  332. package/src/tools/tool-approval-handler.ts +31 -6
  333. package/src/tools/types.ts +24 -2
  334. package/src/tts/provider-catalog.ts +3 -5
  335. package/src/util/disk-usage.ts +138 -0
  336. package/src/util/platform.ts +21 -11
  337. package/src/util/process-liveness.ts +26 -0
  338. package/src/workspace/heartbeat-service.ts +19 -0
  339. package/src/workspace/migrations/065-bump-stale-heartbeat-interval.ts +60 -0
  340. package/src/workspace/migrations/066-seed-heartbeat-callsite-cost-default.ts +146 -0
  341. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +72 -0
  342. package/src/workspace/migrations/068-release-notes-local-timezone.ts +65 -0
  343. package/src/workspace/migrations/registry.ts +8 -0
  344. package/src/__tests__/conversation-tool-setup-memory-scope.test.ts +0 -167
  345. package/src/memory/v2/__tests__/skill-qdrant.test.ts +0 -657
  346. package/src/memory/v2/skill-qdrant.ts +0 -404
  347. package/src/signals/bash.ts +0 -198
@@ -28,8 +28,9 @@ mock.module("../runtime/pending-interactions.js", () => ({
28
28
 
29
29
  const {
30
30
  HostAppControlProxy,
31
- _getActiveAppControlConversationId,
32
- _resetActiveAppControlConversationId,
31
+ _getActiveAppControlSession,
32
+ _resetActiveAppControlSession,
33
+ _setActiveAppControlSession,
33
34
  } = await import("../daemon/host-app-control-proxy.js");
34
35
 
35
36
  import type { HostAppControlResultPayload } from "../daemon/message-types/host-app-control.js";
@@ -58,11 +59,11 @@ describe("HostAppControlProxy", () => {
58
59
  sentMessages.length = 0;
59
60
  resolvedInteractionIds.length = 0;
60
61
  mockHasClient = false;
61
- _resetActiveAppControlConversationId();
62
+ _resetActiveAppControlSession();
62
63
  });
63
64
 
64
65
  afterEach(() => {
65
- _resetActiveAppControlConversationId();
66
+ _resetActiveAppControlSession();
66
67
  });
67
68
 
68
69
  // -------------------------------------------------------------------------
@@ -120,8 +121,10 @@ describe("HostAppControlProxy", () => {
120
121
  },
121
122
  });
122
123
 
123
- // Singleton lock acquired by this conversation.
124
- expect(_getActiveAppControlConversationId()).toBe("conv-1");
124
+ // Session lock acquired by this conversation, bound to the started app.
125
+ const session = _getActiveAppControlSession();
126
+ expect(session?.conversationId).toBe("conv-1");
127
+ expect(session?.app).toBe("com.example.editor");
125
128
 
126
129
  proxy.dispose();
127
130
  });
@@ -130,6 +133,22 @@ describe("HostAppControlProxy", () => {
130
133
  const proxy = new HostAppControlProxy("conv-1");
131
134
  const controller = new AbortController();
132
135
 
136
+ // Acquire a session first so the click below passes the auth gate
137
+ // and reaches dispatch.
138
+ const startCtrl = new AbortController();
139
+ const startPromise = proxy.request(
140
+ "app_control_start",
141
+ { tool: "start", app: "com.example.editor" },
142
+ "conv-1",
143
+ startCtrl.signal,
144
+ );
145
+ proxy.resolve(
146
+ (sentMessages[0] as Record<string, unknown>).requestId as string,
147
+ payload({ pngBase64: PNG_A }),
148
+ );
149
+ await startPromise;
150
+ sentMessages.length = 0;
151
+
133
152
  const resultPromise = proxy.request(
134
153
  "app_control_click",
135
154
  { tool: "click", app: "com.example.editor", x: 100, y: 200 },
@@ -157,10 +176,10 @@ describe("HostAppControlProxy", () => {
157
176
  });
158
177
 
159
178
  // -------------------------------------------------------------------------
160
- // (b) Singleton lock
179
+ // (b) Session lock
161
180
  // -------------------------------------------------------------------------
162
181
 
163
- describe("singleton lock", () => {
182
+ describe("session lock", () => {
164
183
  test("second conversation's start returns isError naming the holder", async () => {
165
184
  const proxy1 = new HostAppControlProxy("conv-1");
166
185
  const ctrl1 = new AbortController();
@@ -175,7 +194,7 @@ describe("HostAppControlProxy", () => {
175
194
  proxy1.resolve(sent1.requestId as string, payload({ pngBase64: PNG_A }));
176
195
  await p1;
177
196
 
178
- expect(_getActiveAppControlConversationId()).toBe("conv-1");
197
+ expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
179
198
 
180
199
  // Second conversation tries to start — should be rejected without
181
200
  // sending any envelope.
@@ -235,14 +254,33 @@ describe("HostAppControlProxy", () => {
235
254
  proxy.dispose();
236
255
  });
237
256
 
238
- test("non-start tools are not gated by the lock", async () => {
239
- const proxy = new HostAppControlProxy("conv-2");
257
+ test("non-start tool with no active session is rejected before dispatch", async () => {
258
+ const proxy = new HostAppControlProxy("conv-1");
240
259
  const ctrl = new AbortController();
241
260
 
242
- // Pretend another conversation already owns the session by manually
243
- // priming the lock via a successful start in conv-1.
261
+ const result = await proxy.request(
262
+ "app_control_type",
263
+ {
264
+ tool: "type",
265
+ app: "com.example.editor",
266
+ text: "rm -rf ~",
267
+ },
268
+ "conv-1",
269
+ ctrl.signal,
270
+ );
271
+
272
+ expect(result.isError).toBe(true);
273
+ expect(result.content).toContain("No app-control session is active");
274
+ expect(result.content).toContain("app_control_start");
275
+ expect(sentMessages).toHaveLength(0); // No envelope dispatched
276
+
277
+ proxy.dispose();
278
+ });
279
+
280
+ test("non-start tool from non-owning conversation is rejected", async () => {
244
281
  const proxyOwner = new HostAppControlProxy("conv-1");
245
282
  const startCtrl = new AbortController();
283
+
246
284
  const pStart = proxyOwner.request(
247
285
  "app_control_start",
248
286
  { tool: "start", app: "com.example.editor" },
@@ -254,27 +292,139 @@ describe("HostAppControlProxy", () => {
254
292
  payload({ pngBase64: PNG_A }),
255
293
  );
256
294
  await pStart;
257
-
258
295
  sentMessages.length = 0;
259
296
 
260
- // conv-2 issues a non-start toolproxy must NOT short-circuit on
261
- // the lock; the dispatch goes through.
262
- const observePromise = proxy.request(
297
+ // conv-2 tries to observe the app conv-1 owns — must be rejected
298
+ // before any host dispatch.
299
+ const proxyOther = new HostAppControlProxy("conv-2");
300
+ const ctrl = new AbortController();
301
+ const result = await proxyOther.request(
263
302
  "app_control_observe",
264
303
  { tool: "observe", app: "com.example.editor" },
265
304
  "conv-2",
266
305
  ctrl.signal,
267
306
  );
307
+
308
+ expect(result.isError).toBe(true);
309
+ expect(result.content).toContain("conv-1");
310
+ expect(result.content).toContain("currently");
311
+ expect(sentMessages).toHaveLength(0);
312
+
313
+ proxyOwner.dispose();
314
+ proxyOther.dispose();
315
+ });
316
+
317
+ test("non-start tool with mismatched app is rejected (cross-app bypass)", async () => {
318
+ const proxy = new HostAppControlProxy("conv-1");
319
+ const startCtrl = new AbortController();
320
+
321
+ // User approves control of the editor.
322
+ const pStart = proxy.request(
323
+ "app_control_start",
324
+ { tool: "start", app: "com.example.editor" },
325
+ "conv-1",
326
+ startCtrl.signal,
327
+ );
328
+ proxy.resolve(
329
+ (sentMessages[0] as Record<string, unknown>).requestId as string,
330
+ payload({ pngBase64: PNG_A }),
331
+ );
332
+ await pStart;
333
+ sentMessages.length = 0;
334
+
335
+ // The model attempts to type into a different app — must be
336
+ // rejected with an informative error.
337
+ const ctrl = new AbortController();
338
+ const result = await proxy.request(
339
+ "app_control_type",
340
+ {
341
+ tool: "type",
342
+ app: "com.apple.Terminal",
343
+ text: "rm -rf ~",
344
+ },
345
+ "conv-1",
346
+ ctrl.signal,
347
+ );
348
+
349
+ expect(result.isError).toBe(true);
350
+ expect(result.content).toContain("com.example.editor");
351
+ expect(result.content).toContain("com.apple.Terminal");
352
+ expect(result.content).toContain("app_control_stop");
353
+ expect(sentMessages).toHaveLength(0);
354
+
355
+ proxy.dispose();
356
+ });
357
+
358
+ test("non-start tool with case-different but otherwise matching app is allowed", async () => {
359
+ const proxy = new HostAppControlProxy("conv-1");
360
+ const startCtrl = new AbortController();
361
+
362
+ const pStart = proxy.request(
363
+ "app_control_start",
364
+ { tool: "start", app: "com.apple.Safari" },
365
+ "conv-1",
366
+ startCtrl.signal,
367
+ );
368
+ proxy.resolve(
369
+ (sentMessages[0] as Record<string, unknown>).requestId as string,
370
+ payload({ pngBase64: PNG_A }),
371
+ );
372
+ await pStart;
373
+ sentMessages.length = 0;
374
+
375
+ // Different casing of the same bundle ID — bundle IDs are
376
+ // case-insensitive on macOS, so this should pass the gate.
377
+ const ctrl = new AbortController();
378
+ const obsPromise = proxy.request(
379
+ "app_control_observe",
380
+ { tool: "observe", app: "COM.APPLE.SAFARI" },
381
+ "conv-1",
382
+ ctrl.signal,
383
+ );
384
+ expect(sentMessages).toHaveLength(1);
385
+ proxy.resolve(
386
+ (sentMessages[0] as Record<string, unknown>).requestId as string,
387
+ payload({ pngBase64: PNG_B }),
388
+ );
389
+ const result = await obsPromise;
390
+ expect(result.isError).toBe(false);
391
+
392
+ proxy.dispose();
393
+ });
394
+
395
+ test("non-start tool from owning conversation with matching app dispatches", async () => {
396
+ const proxy = new HostAppControlProxy("conv-1");
397
+ const startCtrl = new AbortController();
398
+
399
+ const pStart = proxy.request(
400
+ "app_control_start",
401
+ { tool: "start", app: "com.example.editor" },
402
+ "conv-1",
403
+ startCtrl.signal,
404
+ );
405
+ proxy.resolve(
406
+ (sentMessages[0] as Record<string, unknown>).requestId as string,
407
+ payload({ pngBase64: PNG_A }),
408
+ );
409
+ await pStart;
410
+ sentMessages.length = 0;
411
+
412
+ const ctrl = new AbortController();
413
+ const obsPromise = proxy.request(
414
+ "app_control_observe",
415
+ { tool: "observe", app: "com.example.editor" },
416
+ "conv-1",
417
+ ctrl.signal,
418
+ );
268
419
  expect(sentMessages).toHaveLength(1);
269
420
  const sent = sentMessages[0] as Record<string, unknown>;
270
421
  expect(sent.toolName).toBe("app_control_observe");
271
422
 
272
423
  proxy.resolve(sent.requestId as string, payload({ pngBase64: PNG_B }));
273
- const result = await observePromise;
424
+ const result = await obsPromise;
274
425
  expect(result.isError).toBe(false);
275
426
 
276
427
  proxy.dispose();
277
- proxyOwner.dispose();
278
428
  });
279
429
  });
280
430
 
@@ -286,6 +436,10 @@ describe("HostAppControlProxy", () => {
286
436
  test("attaches stuck warning after 5 identical observations", async () => {
287
437
  const proxy = new HostAppControlProxy("conv-1");
288
438
  const ctrl = new AbortController();
439
+ _setActiveAppControlSession({
440
+ conversationId: "conv-1",
441
+ app: "com.example.editor",
442
+ });
289
443
 
290
444
  // First observation establishes the baseline (count = 0).
291
445
  const p0 = proxy.request(
@@ -341,6 +495,10 @@ describe("HostAppControlProxy", () => {
341
495
  test("resets repeat count when the screenshot hash differs", async () => {
342
496
  const proxy = new HostAppControlProxy("conv-1");
343
497
  const ctrl = new AbortController();
498
+ _setActiveAppControlSession({
499
+ conversationId: "conv-1",
500
+ app: "com.example.editor",
501
+ });
344
502
 
345
503
  // Establish baseline at PNG_A.
346
504
  const p1 = proxy.request(
@@ -391,6 +549,10 @@ describe("HostAppControlProxy", () => {
391
549
  test("non-running states do not feed the loop guard", async () => {
392
550
  const proxy = new HostAppControlProxy("conv-1");
393
551
  const ctrl = new AbortController();
552
+ _setActiveAppControlSession({
553
+ conversationId: "conv-1",
554
+ app: "com.example.editor",
555
+ });
394
556
 
395
557
  // Several observations with state != running (and identical PNGs)
396
558
  // should not increment the repeat count.
@@ -435,10 +597,10 @@ describe("HostAppControlProxy", () => {
435
597
  payload({ pngBase64: PNG_A }),
436
598
  );
437
599
  await p1;
438
- expect(_getActiveAppControlConversationId()).toBe("conv-1");
600
+ expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
439
601
 
440
602
  proxy1.dispose();
441
- expect(_getActiveAppControlConversationId()).toBeUndefined();
603
+ expect(_getActiveAppControlSession()).toBeUndefined();
442
604
 
443
605
  // Now a new conversation can acquire the lock.
444
606
  sentMessages.length = 0;
@@ -458,7 +620,7 @@ describe("HostAppControlProxy", () => {
458
620
  );
459
621
  const result = await p2;
460
622
  expect(result.isError).toBe(false);
461
- expect(_getActiveAppControlConversationId()).toBe("conv-2");
623
+ expect(_getActiveAppControlSession()?.conversationId).toBe("conv-2");
462
624
 
463
625
  proxy2.dispose();
464
626
  });
@@ -478,16 +640,16 @@ describe("HostAppControlProxy", () => {
478
640
  payload({ pngBase64: PNG_A }),
479
641
  );
480
642
  await pStart;
481
- expect(_getActiveAppControlConversationId()).toBe("conv-1");
643
+ expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
482
644
 
483
645
  // A different conversation's proxy disposes — the lock should remain
484
646
  // with conv-1.
485
647
  const proxyOther = new HostAppControlProxy("conv-2");
486
648
  proxyOther.dispose();
487
- expect(_getActiveAppControlConversationId()).toBe("conv-1");
649
+ expect(_getActiveAppControlSession()?.conversationId).toBe("conv-1");
488
650
 
489
651
  proxyOwner.dispose();
490
- expect(_getActiveAppControlConversationId()).toBeUndefined();
652
+ expect(_getActiveAppControlSession()).toBeUndefined();
491
653
  });
492
654
  });
493
655
 
@@ -499,6 +661,10 @@ describe("HostAppControlProxy", () => {
499
661
  test("propagates abort and emits cancel envelope", async () => {
500
662
  const proxy = new HostAppControlProxy("conv-1");
501
663
  const controller = new AbortController();
664
+ _setActiveAppControlSession({
665
+ conversationId: "conv-1",
666
+ app: "com.example.editor",
667
+ });
502
668
 
503
669
  const resultPromise = proxy.request(
504
670
  "app_control_observe",
@@ -557,6 +723,10 @@ describe("HostAppControlProxy", () => {
557
723
  test("100 sequential requests dispatch without an artificial limit", async () => {
558
724
  const proxy = new HostAppControlProxy("conv-1");
559
725
  const ctrl = new AbortController();
726
+ _setActiveAppControlSession({
727
+ conversationId: "conv-1",
728
+ app: "com.example.editor",
729
+ });
560
730
 
561
731
  for (let i = 0; i < 100; i++) {
562
732
  const p = proxy.request(