@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
@@ -47,11 +47,24 @@ mock.module("../daemon/host-transfer-proxy.js", () => ({
47
47
  getTargetClientIdForTransfer(_transferId: string) {
48
48
  return stubTargetClientId;
49
49
  },
50
+ getTargetActorPrincipalIdForTransfer(_transferId: string) {
51
+ return stubTargetClientId
52
+ ? clientActors.get(stubTargetClientId)
53
+ : undefined;
54
+ },
50
55
  getTransferContent(transferId: string) {
51
56
  getTransferContentCalls.push(transferId);
52
- return { buffer: Buffer.from("data"), sizeBytes: 4, sha256: "abc123" };
57
+ return {
58
+ buffer: Buffer.from("data"),
59
+ sizeBytes: 4,
60
+ sha256: "abc123",
61
+ };
53
62
  },
54
- async receiveTransferContent(transferId: string, _data: Buffer, _sha256: string) {
63
+ async receiveTransferContent(
64
+ transferId: string,
65
+ _data: Buffer,
66
+ _sha256: string,
67
+ ) {
55
68
  receiveTransferContentCalls.push(transferId);
56
69
  return { accepted: true };
57
70
  },
@@ -63,12 +76,20 @@ mock.module("../daemon/host-transfer-proxy.js", () => ({
63
76
  },
64
77
  }));
65
78
 
79
+ // Stub event hub so tests control what actorPrincipalId is associated with
80
+ // each connected client.
81
+ const clientActors = new Map<string, string>();
82
+
83
+ mock.module("../runtime/assistant-event-hub.js", () => ({
84
+ assistantEventHub: {
85
+ getActorPrincipalIdForClient: (clientId: string) =>
86
+ clientActors.get(clientId),
87
+ },
88
+ }));
89
+
66
90
  // ── Real imports (after mocks) ──────────────────────────────────────────────
67
91
 
68
- import {
69
- BadRequestError,
70
- ForbiddenError,
71
- } from "../runtime/routes/errors.js";
92
+ import { BadRequestError, ForbiddenError } from "../runtime/routes/errors.js";
72
93
  import { ROUTES } from "../runtime/routes/host-transfer-routes.js";
73
94
 
74
95
  afterAll(() => {
@@ -93,10 +114,19 @@ const TEST_TRANSFER_ID = "transfer-abc";
93
114
  const TEST_REQUEST_ID = "req-1";
94
115
 
95
116
  function registerPending(overrides: Partial<PendingInteraction> = {}): void {
117
+ // Mirror the production proxy: capture the target's actor principal at
118
+ // registration time so the result-route check compares against a stable
119
+ // value rather than the live hub.
120
+ const targetActorPrincipalId =
121
+ overrides.targetActorPrincipalId ??
122
+ (overrides.targetClientId
123
+ ? clientActors.get(overrides.targetClientId)
124
+ : undefined);
96
125
  pendingStore.set(TEST_REQUEST_ID, {
97
126
  conversationId: "conv-1",
98
127
  kind: "host_transfer",
99
128
  ...overrides,
129
+ targetActorPrincipalId,
100
130
  });
101
131
  }
102
132
 
@@ -107,6 +137,7 @@ describe("handleTransferContentGet — Phase 3 targetClientId guard", () => {
107
137
  pendingStore.clear();
108
138
  stubTargetClientId = null;
109
139
  getTransferContentCalls.length = 0;
140
+ clientActors.clear();
110
141
  });
111
142
 
112
143
  // ── 1. Targeted + correct header → success ────────────────────────────────
@@ -114,9 +145,13 @@ describe("handleTransferContentGet — Phase 3 targetClientId guard", () => {
114
145
  describe("targeted + correct x-vellum-client-id header", () => {
115
146
  test("returns Uint8Array and calls getTransferContent", async () => {
116
147
  stubTargetClientId = "client-A";
148
+ clientActors.set("client-A", "actor-1");
117
149
  const result = await handleTransferContentGet({
118
150
  pathParams: { transferId: TEST_TRANSFER_ID },
119
- headers: { "x-vellum-client-id": "client-A" },
151
+ headers: {
152
+ "x-vellum-client-id": "client-A",
153
+ "x-vellum-actor-principal-id": "actor-1",
154
+ },
120
155
  });
121
156
 
122
157
  expect(result).toBeInstanceOf(Uint8Array);
@@ -125,9 +160,13 @@ describe("handleTransferContentGet — Phase 3 targetClientId guard", () => {
125
160
 
126
161
  test("trims whitespace from header before comparing", async () => {
127
162
  stubTargetClientId = "client-A";
163
+ clientActors.set("client-A", "actor-1");
128
164
  const result = await handleTransferContentGet({
129
165
  pathParams: { transferId: TEST_TRANSFER_ID },
130
- headers: { "x-vellum-client-id": " client-A " },
166
+ headers: {
167
+ "x-vellum-client-id": " client-A ",
168
+ "x-vellum-actor-principal-id": " actor-1 ",
169
+ },
131
170
  });
132
171
 
133
172
  expect(result).toBeInstanceOf(Uint8Array);
@@ -199,6 +238,52 @@ describe("handleTransferContentGet — Phase 3 targetClientId guard", () => {
199
238
  expect(getTransferContentCalls).toContain(TEST_TRANSFER_ID);
200
239
  });
201
240
  });
241
+
242
+ // ── 5. Same-user actor binding (defense-in-depth) ─────────────────────────
243
+
244
+ describe("targeted + actor principal binding", () => {
245
+ test("throws ForbiddenError when submitting actor does not match target client's actor", () => {
246
+ stubTargetClientId = "client-A";
247
+ clientActors.set("client-A", "actor-victim");
248
+ expect(() =>
249
+ handleTransferContentGet({
250
+ pathParams: { transferId: TEST_TRANSFER_ID },
251
+ headers: {
252
+ "x-vellum-client-id": "client-A",
253
+ "x-vellum-actor-principal-id": "actor-attacker",
254
+ },
255
+ }),
256
+ ).toThrow(ForbiddenError);
257
+ expect(getTransferContentCalls).toHaveLength(0);
258
+ });
259
+
260
+ test("throws ForbiddenError when actor principal header is missing", () => {
261
+ stubTargetClientId = "client-A";
262
+ clientActors.set("client-A", "actor-victim");
263
+ expect(() =>
264
+ handleTransferContentGet({
265
+ pathParams: { transferId: TEST_TRANSFER_ID },
266
+ headers: { "x-vellum-client-id": "client-A" },
267
+ }),
268
+ ).toThrow(ForbiddenError);
269
+ expect(getTransferContentCalls).toHaveLength(0);
270
+ });
271
+
272
+ test("throws ForbiddenError when target client has no stored actor", () => {
273
+ stubTargetClientId = "client-A";
274
+ // No entry in clientActors for "client-A"
275
+ expect(() =>
276
+ handleTransferContentGet({
277
+ pathParams: { transferId: TEST_TRANSFER_ID },
278
+ headers: {
279
+ "x-vellum-client-id": "client-A",
280
+ "x-vellum-actor-principal-id": "actor-1",
281
+ },
282
+ }),
283
+ ).toThrow(ForbiddenError);
284
+ expect(getTransferContentCalls).toHaveLength(0);
285
+ });
286
+ });
202
287
  });
203
288
 
204
289
  describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
@@ -206,6 +291,7 @@ describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
206
291
  pendingStore.clear();
207
292
  stubTargetClientId = null;
208
293
  receiveTransferContentCalls.length = 0;
294
+ clientActors.clear();
209
295
  });
210
296
 
211
297
  // ── 1. Targeted + correct header → success ────────────────────────────────
@@ -213,9 +299,14 @@ describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
213
299
  describe("targeted + correct x-vellum-client-id header", () => {
214
300
  test("returns { accepted: true } and calls receiveTransferContent", async () => {
215
301
  stubTargetClientId = "client-A";
302
+ clientActors.set("client-A", "actor-1");
216
303
  const result = await handleTransferContentPut({
217
304
  pathParams: { transferId: TEST_TRANSFER_ID },
218
- headers: { "x-vellum-client-id": "client-A", "x-transfer-sha256": "abc" },
305
+ headers: {
306
+ "x-vellum-client-id": "client-A",
307
+ "x-vellum-actor-principal-id": "actor-1",
308
+ "x-transfer-sha256": "abc",
309
+ },
219
310
  rawBody: new Uint8Array(Buffer.from("data")),
220
311
  });
221
312
 
@@ -225,9 +316,14 @@ describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
225
316
 
226
317
  test("trims whitespace from header before comparing", async () => {
227
318
  stubTargetClientId = "client-A";
319
+ clientActors.set("client-A", "actor-1");
228
320
  const result = await handleTransferContentPut({
229
321
  pathParams: { transferId: TEST_TRANSFER_ID },
230
- headers: { "x-vellum-client-id": " client-A ", "x-transfer-sha256": "abc" },
322
+ headers: {
323
+ "x-vellum-client-id": " client-A ",
324
+ "x-vellum-actor-principal-id": " actor-1 ",
325
+ "x-transfer-sha256": "abc",
326
+ },
231
327
  rawBody: new Uint8Array(Buffer.from("data")),
232
328
  });
233
329
 
@@ -272,7 +368,10 @@ describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
272
368
  await expect(
273
369
  handleTransferContentPut({
274
370
  pathParams: { transferId: TEST_TRANSFER_ID },
275
- headers: { "x-vellum-client-id": "client-B", "x-transfer-sha256": "abc" },
371
+ headers: {
372
+ "x-vellum-client-id": "client-B",
373
+ "x-transfer-sha256": "abc",
374
+ },
276
375
  rawBody: new Uint8Array(Buffer.from("data")),
277
376
  }),
278
377
  ).rejects.toBeInstanceOf(ForbiddenError);
@@ -283,7 +382,10 @@ describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
283
382
  try {
284
383
  await handleTransferContentPut({
285
384
  pathParams: { transferId: TEST_TRANSFER_ID },
286
- headers: { "x-vellum-client-id": "client-B", "x-transfer-sha256": "abc" },
385
+ headers: {
386
+ "x-vellum-client-id": "client-B",
387
+ "x-transfer-sha256": "abc",
388
+ },
287
389
  rawBody: new Uint8Array(Buffer.from("data")),
288
390
  });
289
391
  } catch {
@@ -308,6 +410,60 @@ describe("handleTransferContentPut — Phase 3 targetClientId guard", () => {
308
410
  expect(receiveTransferContentCalls).toContain(TEST_TRANSFER_ID);
309
411
  });
310
412
  });
413
+
414
+ // ── 5. Same-user actor binding (defense-in-depth) ─────────────────────────
415
+
416
+ describe("targeted + actor principal binding", () => {
417
+ test("rejects when submitting actor does not match target client's actor", async () => {
418
+ stubTargetClientId = "client-A";
419
+ clientActors.set("client-A", "actor-victim");
420
+ await expect(
421
+ handleTransferContentPut({
422
+ pathParams: { transferId: TEST_TRANSFER_ID },
423
+ headers: {
424
+ "x-vellum-client-id": "client-A",
425
+ "x-vellum-actor-principal-id": "actor-attacker",
426
+ "x-transfer-sha256": "abc",
427
+ },
428
+ rawBody: new Uint8Array(Buffer.from("data")),
429
+ }),
430
+ ).rejects.toBeInstanceOf(ForbiddenError);
431
+ expect(receiveTransferContentCalls).toHaveLength(0);
432
+ });
433
+
434
+ test("rejects when actor principal header is missing", async () => {
435
+ stubTargetClientId = "client-A";
436
+ clientActors.set("client-A", "actor-victim");
437
+ await expect(
438
+ handleTransferContentPut({
439
+ pathParams: { transferId: TEST_TRANSFER_ID },
440
+ headers: {
441
+ "x-vellum-client-id": "client-A",
442
+ "x-transfer-sha256": "abc",
443
+ },
444
+ rawBody: new Uint8Array(Buffer.from("data")),
445
+ }),
446
+ ).rejects.toBeInstanceOf(ForbiddenError);
447
+ expect(receiveTransferContentCalls).toHaveLength(0);
448
+ });
449
+
450
+ test("rejects when target client has no stored actor", async () => {
451
+ stubTargetClientId = "client-A";
452
+ // No entry in clientActors for "client-A"
453
+ await expect(
454
+ handleTransferContentPut({
455
+ pathParams: { transferId: TEST_TRANSFER_ID },
456
+ headers: {
457
+ "x-vellum-client-id": "client-A",
458
+ "x-vellum-actor-principal-id": "actor-1",
459
+ "x-transfer-sha256": "abc",
460
+ },
461
+ rawBody: new Uint8Array(Buffer.from("data")),
462
+ }),
463
+ ).rejects.toBeInstanceOf(ForbiddenError);
464
+ expect(receiveTransferContentCalls).toHaveLength(0);
465
+ });
466
+ });
311
467
  });
312
468
 
313
469
  describe("handleTransferResult — Phase 3 targetClientId guard", () => {
@@ -315,6 +471,7 @@ describe("handleTransferResult — Phase 3 targetClientId guard", () => {
315
471
  pendingStore.clear();
316
472
  stubTargetClientId = null;
317
473
  resolveTransferResultCalls.length = 0;
474
+ clientActors.clear();
318
475
  });
319
476
 
320
477
  function registerHostTransferPending(targetClientId?: string): void {
@@ -329,10 +486,14 @@ describe("handleTransferResult — Phase 3 targetClientId guard", () => {
329
486
 
330
487
  describe("targeted + correct x-vellum-client-id header", () => {
331
488
  test("returns { accepted: true } and calls resolveTransferResult", async () => {
489
+ clientActors.set("client-A", "actor-1");
332
490
  registerHostTransferPending("client-A");
333
491
  const result = await handleTransferResult({
334
492
  body: resultBody(),
335
- headers: { "x-vellum-client-id": "client-A" },
493
+ headers: {
494
+ "x-vellum-client-id": "client-A",
495
+ "x-vellum-actor-principal-id": "actor-1",
496
+ },
336
497
  });
337
498
 
338
499
  expect(result).toEqual({ accepted: true });
@@ -340,10 +501,14 @@ describe("handleTransferResult — Phase 3 targetClientId guard", () => {
340
501
  });
341
502
 
342
503
  test("trims whitespace from header before comparing", async () => {
504
+ clientActors.set("client-A", "actor-1");
343
505
  registerHostTransferPending("client-A");
344
506
  const result = await handleTransferResult({
345
507
  body: resultBody(),
346
- headers: { "x-vellum-client-id": " client-A " },
508
+ headers: {
509
+ "x-vellum-client-id": " client-A ",
510
+ "x-vellum-actor-principal-id": " actor-1 ",
511
+ },
347
512
  });
348
513
 
349
514
  expect(result).toEqual({ accepted: true });
@@ -355,9 +520,9 @@ describe("handleTransferResult — Phase 3 targetClientId guard", () => {
355
520
  describe("targeted + missing x-vellum-client-id header", () => {
356
521
  test("throws BadRequestError when header is absent", () => {
357
522
  registerHostTransferPending("client-A");
358
- expect(() =>
359
- handleTransferResult({ body: resultBody() }),
360
- ).toThrow(BadRequestError);
523
+ expect(() => handleTransferResult({ body: resultBody() })).toThrow(
524
+ BadRequestError,
525
+ );
361
526
  });
362
527
 
363
528
  test("resolveTransferResult NOT called on 400", () => {
@@ -444,4 +609,54 @@ describe("handleTransferResult — Phase 3 targetClientId guard", () => {
444
609
  expect(result).toEqual({ accepted: true });
445
610
  });
446
611
  });
612
+
613
+ // ── 5. Same-user actor binding (defense-in-depth) ─────────────────────────
614
+
615
+ describe("targeted + actor principal binding", () => {
616
+ test("throws ForbiddenError when submitting actor does not match target client's actor", () => {
617
+ registerHostTransferPending("client-A");
618
+ clientActors.set("client-A", "actor-victim");
619
+ expect(() =>
620
+ handleTransferResult({
621
+ body: resultBody(),
622
+ headers: {
623
+ "x-vellum-client-id": "client-A",
624
+ "x-vellum-actor-principal-id": "actor-attacker",
625
+ },
626
+ }),
627
+ ).toThrow(ForbiddenError);
628
+ expect(resolveTransferResultCalls).toHaveLength(0);
629
+ // Pending interaction should still be present (not consumed on 403).
630
+ expect(pendingStore.has(TEST_REQUEST_ID)).toBe(true);
631
+ });
632
+
633
+ test("throws ForbiddenError when actor principal header is missing", () => {
634
+ registerHostTransferPending("client-A");
635
+ clientActors.set("client-A", "actor-victim");
636
+ expect(() =>
637
+ handleTransferResult({
638
+ body: resultBody(),
639
+ headers: { "x-vellum-client-id": "client-A" },
640
+ }),
641
+ ).toThrow(ForbiddenError);
642
+ expect(resolveTransferResultCalls).toHaveLength(0);
643
+ expect(pendingStore.has(TEST_REQUEST_ID)).toBe(true);
644
+ });
645
+
646
+ test("throws ForbiddenError when target client has no stored actor", () => {
647
+ registerHostTransferPending("client-A");
648
+ // No entry in clientActors for "client-A"
649
+ expect(() =>
650
+ handleTransferResult({
651
+ body: resultBody(),
652
+ headers: {
653
+ "x-vellum-client-id": "client-A",
654
+ "x-vellum-actor-principal-id": "actor-1",
655
+ },
656
+ }),
657
+ ).toThrow(ForbiddenError);
658
+ expect(resolveTransferResultCalls).toHaveLength(0);
659
+ expect(pendingStore.has(TEST_REQUEST_ID)).toBe(true);
660
+ });
661
+ });
447
662
  });
@@ -252,12 +252,24 @@ async function sendMessage(
252
252
  content: string,
253
253
  conversationObj: import("../daemon/conversation.js").Conversation,
254
254
  extra: Record<string, unknown> = {},
255
+ options: {
256
+ onGetOrCreateConversation?: (
257
+ conversationId: string,
258
+ opts?: Record<string, unknown>,
259
+ ) => void;
260
+ } = {},
255
261
  ) {
256
262
  return callHandler(
257
263
  (args) =>
258
264
  handleSendMessage(args, {
259
265
  sendMessageDeps: {
260
- getOrCreateConversation: async () => conversationObj,
266
+ getOrCreateConversation: async (conversationId, opts) => {
267
+ options.onGetOrCreateConversation?.(
268
+ conversationId,
269
+ opts as Record<string, unknown> | undefined,
270
+ );
271
+ return conversationObj;
272
+ },
261
273
  assistantEventHub: { publish: async () => {} } as any,
262
274
  resolveAttachments: () => [],
263
275
  },
@@ -326,3 +338,97 @@ describe("HTTP POST /v1/messages does not intercept recording intents (by design
326
338
  expect(runAgentLoop).toHaveBeenCalledTimes(1);
327
339
  });
328
340
  });
341
+
342
+ // ============================================================================
343
+ // CLIENT TIMEZONE — optional HTTP metadata
344
+ // ============================================================================
345
+ describe("HTTP POST /v1/messages clientTimezone transport metadata", () => {
346
+ beforeEach(() => {
347
+ routeGuardianReplyMock.mockClear();
348
+ listPendingByDestinationMock.mockClear();
349
+ listCanonicalMock.mockClear();
350
+ addMessageMock.mockClear();
351
+ });
352
+
353
+ test("passes canonical clientTimezone through host-proxy transport", async () => {
354
+ const persistUserMessage = mock(async () => "persisted-msg-id");
355
+ const runAgentLoop = mock(async () => undefined);
356
+ const conversation = makeConversation({ persistUserMessage, runAgentLoop });
357
+ let capturedOptions: Record<string, unknown> | undefined;
358
+
359
+ const res = await sendMessage(
360
+ "hello",
361
+ conversation,
362
+ { clientTimezone: "america/new_york" },
363
+ {
364
+ onGetOrCreateConversation: (_conversationId, opts) => {
365
+ capturedOptions = opts;
366
+ },
367
+ },
368
+ );
369
+
370
+ expect(res.status).toBe(202);
371
+ expect(capturedOptions).toEqual({
372
+ transport: {
373
+ channelId: "vellum",
374
+ interfaceId: "macos",
375
+ clientTimezone: "America/New_York",
376
+ },
377
+ });
378
+ });
379
+
380
+ test("passes canonical clientTimezone through non-host-proxy transport", async () => {
381
+ const persistUserMessage = mock(async () => "persisted-msg-id");
382
+ const runAgentLoop = mock(async () => undefined);
383
+ const conversation = makeConversation({ persistUserMessage, runAgentLoop });
384
+ let capturedOptions: Record<string, unknown> | undefined;
385
+
386
+ const res = await sendMessage(
387
+ "hello",
388
+ conversation,
389
+ { interface: "ios", clientTimezone: "europe/london" },
390
+ {
391
+ onGetOrCreateConversation: (_conversationId, opts) => {
392
+ capturedOptions = opts;
393
+ },
394
+ },
395
+ );
396
+
397
+ expect(res.status).toBe(202);
398
+ expect(capturedOptions).toEqual({
399
+ transport: {
400
+ channelId: "vellum",
401
+ interfaceId: "ios",
402
+ clientTimezone: "Europe/London",
403
+ },
404
+ });
405
+ });
406
+
407
+ test("drops invalid clientTimezone without rejecting the message", async () => {
408
+ const persistUserMessage = mock(async () => "persisted-msg-id");
409
+ const runAgentLoop = mock(async () => undefined);
410
+ const conversation = makeConversation({ persistUserMessage, runAgentLoop });
411
+ let capturedOptions: Record<string, unknown> | undefined;
412
+
413
+ const res = await sendMessage(
414
+ "hello",
415
+ conversation,
416
+ { clientTimezone: "not-a-timezone" },
417
+ {
418
+ onGetOrCreateConversation: (_conversationId, opts) => {
419
+ capturedOptions = opts;
420
+ },
421
+ },
422
+ );
423
+
424
+ expect(res.status).toBe(202);
425
+ expect(capturedOptions).toEqual({
426
+ transport: {
427
+ channelId: "vellum",
428
+ interfaceId: "macos",
429
+ },
430
+ });
431
+ expect(persistUserMessage).toHaveBeenCalledTimes(1);
432
+ expect(runAgentLoop).toHaveBeenCalledTimes(1);
433
+ });
434
+ });
@@ -4,10 +4,11 @@
4
4
  *
5
5
  * Covers:
6
6
  *
7
- * 1. The nine default injectors registered by `defaultInjectorsPlugin` come
8
- * back from `getInjectors()` in the documented order (workspace-context →
9
- * unified-turn-contextpkb-context → pkb-reminder → memory-v2-static
10
- * now-mdsubagent-statusslack-messagesthread-focus).
7
+ * 1. The ten default injectors registered by `defaultInjectorsPlugin` come
8
+ * back from `getInjectors()` in the documented order
9
+ * (disk-pressure-warningworkspace-context → unified-turn-context
10
+ * pkb-contextpkb-remindermemory-v2-staticnow-md →
11
+ * subagent-status → slack-messages → thread-focus).
11
12
  * 2. A third-party-registered injector at `order: 25` slots between
12
13
  * `unified-turn-context` (order 20) and `pkb` (order 30), proving the
13
14
  * extensibility contract.
@@ -25,6 +26,7 @@
25
26
 
26
27
  import { beforeEach, describe, expect, test } from "bun:test";
27
28
 
29
+ import { _setOverridesForTesting } from "../config/assistant-feature-flags.js";
28
30
  import {
29
31
  applyRuntimeInjections,
30
32
  composeInjectorChain,
@@ -33,6 +35,11 @@ import {
33
35
  DEFAULT_INJECTOR_ORDER,
34
36
  defaultInjectorsPlugin,
35
37
  } from "../plugins/defaults/injectors.js";
38
+
39
+ // This test exercises v1 PKB injection. The `memory-v2-enabled` flag
40
+ // (registry default `true`) makes the PKB injector go silent — disable it
41
+ // here so the v1 injection chain assertions stay meaningful.
42
+ _setOverridesForTesting({ "memory-v2-enabled": false });
36
43
  import {
37
44
  getInjectors,
38
45
  registerPlugin,
@@ -76,11 +83,12 @@ describe("injector chain", () => {
76
83
  resetPluginRegistryForTests();
77
84
  });
78
85
 
79
- test("defaultInjectorsPlugin registers the nine defaults in the documented order", () => {
86
+ test("defaultInjectorsPlugin registers the ten defaults in the documented order", () => {
80
87
  registerPlugin(defaultInjectorsPlugin);
81
88
 
82
89
  const names = getInjectors().map((i) => i.name);
83
90
  expect(names).toEqual([
91
+ "disk-pressure-warning",
84
92
  "workspace-context",
85
93
  "unified-turn-context",
86
94
  "pkb-context",
@@ -97,6 +105,9 @@ describe("injector chain", () => {
97
105
  registerPlugin(defaultInjectorsPlugin);
98
106
 
99
107
  const byName = new Map(getInjectors().map((i) => [i.name, i.order]));
108
+ expect(byName.get("disk-pressure-warning")).toBe(
109
+ DEFAULT_INJECTOR_ORDER.diskPressureWarning,
110
+ );
100
111
  expect(byName.get("workspace-context")).toBe(
101
112
  DEFAULT_INJECTOR_ORDER.workspaceContext,
102
113
  );
@@ -132,6 +143,7 @@ describe("injector chain", () => {
132
143
 
133
144
  const names = getInjectors().map((i) => i.name);
134
145
  expect(names).toEqual([
146
+ "disk-pressure-warning", // 5
135
147
  "workspace-context", // 10
136
148
  "unified-turn-context", // 20
137
149
  "plugin-25", // 25 — slots in
@@ -146,7 +158,7 @@ describe("injector chain", () => {
146
158
  });
147
159
 
148
160
  test("composeInjectorChain returns empty string when every injector opts out", async () => {
149
- // The default chain is the golden-path: all nine defaults return `null`
161
+ // The default chain is the golden-path: all ten defaults return `null`
150
162
  // on an empty turn context, so the composed block is an empty string.
151
163
  registerPlugin(defaultInjectorsPlugin);
152
164