@vellumai/assistant 0.10.2-dev.202606250318.5e7cfb0 → 0.10.2

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 (430) hide show
  1. package/bun.lock +0 -20
  2. package/docs/workspace-tools.md +33 -42
  3. package/eslint-rules/cli-no-daemon-internals.js +0 -6
  4. package/node_modules/@vellumai/gateway-client/src/__tests__/trust-verdict-contract.test.ts +0 -31
  5. package/node_modules/@vellumai/gateway-client/src/gateway-ipc-contracts.ts +0 -44
  6. package/node_modules/@vellumai/gateway-client/src/index.ts +0 -14
  7. package/node_modules/@vellumai/gateway-client/src/trust-verdict-contract.ts +0 -17
  8. package/node_modules/@vellumai/service-contracts/package.json +0 -1
  9. package/node_modules/@vellumai/service-contracts/src/index.ts +0 -1
  10. package/openapi.yaml +0 -155
  11. package/package.json +1 -4
  12. package/scripts/test.sh +15 -36
  13. package/src/__tests__/actor-token-service.test.ts +14 -36
  14. package/src/__tests__/agent-loop-override-profile.test.ts +0 -1
  15. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +0 -2
  16. package/src/__tests__/agent-wake-override-profile.test.ts +0 -2
  17. package/src/__tests__/annotate-activity-metadata.test.ts +0 -2
  18. package/src/__tests__/annotate-risk-options.test.ts +0 -2
  19. package/src/__tests__/approval-cascade.test.ts +0 -2
  20. package/src/__tests__/assistant-attachments.test.ts +0 -42
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +0 -2
  22. package/src/__tests__/btw-routes.test.ts +0 -2
  23. package/src/__tests__/build-persisted-content.test.ts +0 -2
  24. package/src/__tests__/call-controller.test.ts +0 -19
  25. package/src/__tests__/channel-guardian.test.ts +58 -94
  26. package/src/__tests__/channel-reply-delivery.test.ts +0 -2
  27. package/src/__tests__/compaction-events.test.ts +0 -2
  28. package/src/__tests__/compaction.benchmark.test.ts +0 -2
  29. package/src/__tests__/compactor-call-site-logging.test.ts +0 -2
  30. package/src/__tests__/compactor-low-watermark-cut.test.ts +0 -2
  31. package/src/__tests__/compactor-preserved-tail-count.test.ts +0 -2
  32. package/src/__tests__/compactor-summary-call-truncation.test.ts +0 -2
  33. package/src/__tests__/compactor-web-search-strip.test.ts +0 -2
  34. package/src/__tests__/config-loader-backfill.test.ts +10 -123
  35. package/src/__tests__/config-schema.test.ts +0 -1
  36. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +29 -31
  37. package/src/__tests__/contacts-relay-reads.test.ts +15 -13
  38. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -2
  39. package/src/__tests__/conversation-agent-loop-disk-pressure.test.ts +0 -2
  40. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +0 -2
  41. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -2
  42. package/src/__tests__/conversation-agent-loop.test.ts +0 -134
  43. package/src/__tests__/conversation-analysis-routes.test.ts +0 -2
  44. package/src/__tests__/conversation-app-control-lifecycle.test.ts +0 -2
  45. package/src/__tests__/conversation-confirmation-signals.test.ts +0 -2
  46. package/src/__tests__/conversation-history-web-search.test.ts +0 -2
  47. package/src/__tests__/conversation-load-history-repair.test.ts +0 -2
  48. package/src/__tests__/conversation-load-history-stripped.test.ts +0 -2
  49. package/src/__tests__/conversation-pairing.test.ts +0 -2
  50. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +0 -2
  51. package/src/__tests__/conversation-process-callsite.test.ts +0 -2
  52. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -2
  53. package/src/__tests__/conversation-queue.test.ts +0 -91
  54. package/src/__tests__/conversation-routes-guardian-reply.test.ts +0 -14
  55. package/src/__tests__/conversation-routes-slash-commands.test.ts +0 -14
  56. package/src/__tests__/conversation-slash-queue.test.ts +0 -2
  57. package/src/__tests__/conversation-slash-unknown.test.ts +0 -2
  58. package/src/__tests__/conversation-speed-override.test.ts +0 -2
  59. package/src/__tests__/conversation-surfaces-task-progress.test.ts +0 -29
  60. package/src/__tests__/conversation-title-service.test.ts +0 -2
  61. package/src/__tests__/conversation-tool-setup-attribution.test.ts +0 -47
  62. package/src/__tests__/conversation-usage.test.ts +0 -2
  63. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -2
  64. package/src/__tests__/conversation-workspace-injection.test.ts +0 -2
  65. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -2
  66. package/src/__tests__/credential-security-invariants.test.ts +1 -1
  67. package/src/__tests__/db-migration-rollback.test.ts +171 -205
  68. package/src/__tests__/db-test-helpers.ts +4 -5
  69. package/src/__tests__/deterministic-verification-control-plane.test.ts +2 -4
  70. package/src/__tests__/disk-pressure-guard.test.ts +0 -41
  71. package/src/__tests__/dm-persistence.test.ts +0 -2
  72. package/src/__tests__/emit-signal-routing-intent.test.ts +5 -10
  73. package/src/__tests__/events-dev-bypass-actor.test.ts +1 -7
  74. package/src/__tests__/exploration-drift-hook.test.ts +2 -3
  75. package/src/__tests__/filing-service.test.ts +0 -2
  76. package/src/__tests__/guardian-binding-drift-heal.test.ts +10 -75
  77. package/src/__tests__/guardian-dispatch.test.ts +1 -95
  78. package/src/__tests__/guardian-outbound-http.test.ts +0 -13
  79. package/src/__tests__/heartbeat-disk-pressure.test.ts +0 -2
  80. package/src/__tests__/heartbeat-service.test.ts +0 -2
  81. package/src/__tests__/helpers/channel-test-adapter.ts +7 -1
  82. package/src/__tests__/host-app-control-routes.test.ts +30 -24
  83. package/src/__tests__/host-bash-routes.test.ts +41 -31
  84. package/src/__tests__/host-browser-routes.test.ts +32 -26
  85. package/src/__tests__/host-cu-routes-targeted.test.ts +33 -25
  86. package/src/__tests__/host-file-routes-targeted.test.ts +52 -40
  87. package/src/__tests__/host-transfer-routes-targeted.test.ts +43 -31
  88. package/src/__tests__/http-user-message-parity.test.ts +8 -290
  89. package/src/__tests__/inbound-invite-redemption.test.ts +0 -28
  90. package/src/__tests__/inbound-slack-persistence.test.ts +0 -2
  91. package/src/__tests__/invite-redemption-service.test.ts +0 -198
  92. package/src/__tests__/llm-context-normalization.test.ts +0 -105
  93. package/src/__tests__/llm-request-log-error-payload.test.ts +9 -71
  94. package/src/__tests__/llm-usage-store.test.ts +0 -25
  95. package/src/__tests__/mcp-health-check.test.ts +1 -2
  96. package/src/__tests__/media-stream-server-integration.test.ts +0 -127
  97. package/src/__tests__/memory-retrieval-hook.test.ts +0 -2
  98. package/src/__tests__/messaging-send-tool.test.ts +0 -2
  99. package/src/__tests__/migration-import-from-url.test.ts +2 -2
  100. package/src/__tests__/mtime-cache.test.ts +5 -146
  101. package/src/__tests__/native-web-search.test.ts +0 -2
  102. package/src/__tests__/non-member-access-request.test.ts +17 -189
  103. package/src/__tests__/notification-broadcaster.test.ts +0 -4
  104. package/src/__tests__/notification-decision-recipient-context.test.ts +32 -33
  105. package/src/__tests__/notification-deep-link.test.ts +0 -6
  106. package/src/__tests__/notification-guardian-path.test.ts +0 -19
  107. package/src/__tests__/openai-provider.test.ts +12 -22
  108. package/src/__tests__/openai-responses-provider.test.ts +2 -12
  109. package/src/__tests__/outbound-slack-persistence.test.ts +0 -2
  110. package/src/__tests__/pending-interactions-resolved-event.test.ts +4 -7
  111. package/src/__tests__/persistence-secret-redaction.test.ts +0 -2
  112. package/src/__tests__/plugin-bootstrap.test.ts +73 -3
  113. package/src/__tests__/plugin-route-contribution.test.ts +17 -4
  114. package/src/__tests__/plugin-tool-contribution.test.ts +18 -3
  115. package/src/__tests__/plugin-types.test.ts +2 -0
  116. package/src/__tests__/process-message-background-slack.test.ts +0 -2
  117. package/src/__tests__/process-message-display-content.test.ts +0 -2
  118. package/src/__tests__/provider-error-scenarios.test.ts +4 -5
  119. package/src/__tests__/provider-usage-tracking.test.ts +0 -39
  120. package/src/__tests__/regenerate-fire-and-forget-trace.test.ts +0 -2
  121. package/src/__tests__/registry.test.ts +1 -4
  122. package/src/__tests__/relay-server.test.ts +25 -694
  123. package/src/__tests__/runtime-attachment-metadata.test.ts +1 -0
  124. package/src/__tests__/secret-ingress-http.test.ts +0 -14
  125. package/src/__tests__/send-endpoint-busy.test.ts +8 -30
  126. package/src/__tests__/skills.test.ts +0 -44
  127. package/src/__tests__/slack-inbound-verification.test.ts +2 -47
  128. package/src/__tests__/stt-hints.test.ts +13 -44
  129. package/src/__tests__/subagent-detail.test.ts +0 -27
  130. package/src/__tests__/subagent-disposal.test.ts +0 -65
  131. package/src/__tests__/subagent-notify-parent.test.ts +0 -2
  132. package/src/__tests__/subagent-role-registry.test.ts +2 -7
  133. package/src/__tests__/subagent-spawn-tool-fork.test.ts +0 -2
  134. package/src/__tests__/subagent-tools.test.ts +0 -2
  135. package/src/__tests__/suggestion-routes.test.ts +0 -2
  136. package/src/__tests__/title-generate-hook.test.ts +0 -2
  137. package/src/__tests__/tool-executor-lifecycle-events.test.ts +0 -2
  138. package/src/__tests__/tool-executor.test.ts +11 -16
  139. package/src/__tests__/tool-preview-lifecycle.test.ts +0 -2
  140. package/src/__tests__/tool-result-metadata-plumbing.test.ts +0 -2
  141. package/src/__tests__/tool-start-timestamp.test.ts +0 -2
  142. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +10 -10
  143. package/src/__tests__/twilio-routes.test.ts +0 -96
  144. package/src/__tests__/ui-file-upload-surface.test.ts +0 -86
  145. package/src/__tests__/verification-control-plane-policy.test.ts +0 -2
  146. package/src/__tests__/voice-invite-redemption.test.ts +0 -33
  147. package/src/__tests__/web-search-backend-failure.test.ts +0 -2
  148. package/src/__tests__/workspace-migration-remove-hooks.test.ts +35 -14
  149. package/src/__tests__/workspace-tool-loader.test.ts +2 -195
  150. package/src/__tests__/workspace-tools-watcher-flag.test.ts +70 -0
  151. package/src/agent/loop.ts +0 -56
  152. package/src/api/index.ts +1 -19
  153. package/src/api/responses/llm-request-log-entry.ts +0 -29
  154. package/src/api/responses/subagent-detail.ts +0 -17
  155. package/src/api/surfaces.ts +3 -39
  156. package/src/approvals/guardian-request-resolvers.ts +11 -1
  157. package/src/calls/__tests__/relay-setup-router.test.ts +4 -262
  158. package/src/calls/call-domain.ts +3 -3
  159. package/src/calls/guardian-dispatch.ts +8 -10
  160. package/src/calls/inbound-trust-reader.ts +1 -17
  161. package/src/calls/media-stream-server.ts +0 -21
  162. package/src/calls/relay-server.ts +50 -167
  163. package/src/calls/relay-setup-router.ts +7 -37
  164. package/src/calls/relay-verification.ts +4 -4
  165. package/src/calls/stt-hints.ts +12 -9
  166. package/src/calls/twilio-routes.ts +4 -14
  167. package/src/channels/types.ts +20 -10
  168. package/src/cli/commands/__tests__/cache.test.ts +1 -8
  169. package/src/cli/commands/cache.ts +181 -194
  170. package/src/cli/commands/db/__tests__/repair.test.ts +5 -6
  171. package/src/cli/commands/db/status.ts +1 -37
  172. package/src/cli/commands/mcp.ts +218 -252
  173. package/src/cli/commands/memory/index.ts +0 -2
  174. package/src/cli/commands/plugins.ts +3 -75
  175. package/src/cli/lib/__tests__/install-from-github.test.ts +0 -102
  176. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +1 -160
  177. package/src/cli/lib/list-installed-plugins.ts +1 -179
  178. package/src/config/__tests__/sync-gated-profiles.test.ts +3 -11
  179. package/src/config/bundled-skills/contacts/tools/contact-merge.ts +17 -27
  180. package/src/config/bundled-skills/contacts/tools/contact-search.ts +3 -13
  181. package/src/config/bundled-skills/subagent/SKILL.md +1 -1
  182. package/src/config/bundled-skills/subagent/TOOLS.json +1 -1
  183. package/src/config/feature-flag-registry.json +13 -5
  184. package/src/config/loader.ts +5 -38
  185. package/src/config/schemas/__tests__/memory-v3.test.ts +0 -1
  186. package/src/config/schemas/memory-lifecycle.ts +0 -12
  187. package/src/config/schemas/memory-v3.ts +0 -7
  188. package/src/config/schemas/memory.ts +0 -4
  189. package/src/config/schemas/timeouts.ts +0 -8
  190. package/src/config/seed-inference-profiles.ts +11 -21
  191. package/src/config/skills.ts +5 -27
  192. package/src/config/sync-gated-profiles.ts +13 -12
  193. package/src/contacts/contacts-write.ts +0 -3
  194. package/src/daemon/assistant-attachments.ts +4 -27
  195. package/src/daemon/conversation-agent-loop.ts +0 -28
  196. package/src/daemon/conversation-process.ts +16 -35
  197. package/src/daemon/conversation-surfaces.ts +38 -111
  198. package/src/daemon/conversation-tool-setup.ts +16 -50
  199. package/src/daemon/conversation.ts +1 -13
  200. package/src/daemon/disk-pressure-guard.ts +2 -12
  201. package/src/daemon/event-loop-watchdog.ts +1 -28
  202. package/src/daemon/external-plugins-bootstrap.ts +34 -4
  203. package/src/daemon/handlers/__tests__/config-a2a-redeem.test.ts +0 -25
  204. package/src/daemon/handlers/config-a2a.ts +14 -6
  205. package/src/daemon/handlers/config-channels.ts +22 -78
  206. package/src/daemon/handlers/conversations.ts +0 -77
  207. package/src/daemon/lifecycle.ts +0 -4
  208. package/src/daemon/mcp-reload-service.ts +0 -10
  209. package/src/daemon/memory-v2-startup.test.ts +0 -72
  210. package/src/daemon/memory-v2-startup.ts +19 -87
  211. package/src/daemon/message-types/conversations.ts +0 -2
  212. package/src/daemon/message-types/surfaces.ts +12 -12
  213. package/src/daemon/server.ts +4 -0
  214. package/src/daemon/shutdown-handlers.ts +0 -20
  215. package/src/daemon/tool-setup-types.ts +0 -9
  216. package/src/daemon/workspace-tools-watcher.ts +328 -0
  217. package/src/ipc/__tests__/clients-list-ipc.test.ts +1 -1
  218. package/src/ipc/assistant-server.ts +2 -2
  219. package/src/mcp/__tests__/mcp-auth-orchestrator.test.ts +0 -1
  220. package/src/mcp/client.ts +1 -15
  221. package/src/mcp/mcp-auth-orchestrator.ts +1 -6
  222. package/src/mcp/mcp-oauth-provider.ts +8 -19
  223. package/src/memory/__tests__/memory-retrospective-job.test.ts +0 -8
  224. package/src/memory/conversation-crud.ts +0 -38
  225. package/src/memory/db-connection.ts +3 -22
  226. package/src/memory/db-init.ts +502 -36
  227. package/src/memory/db-singleton.ts +4 -6
  228. package/src/memory/jobs-worker.ts +0 -58
  229. package/src/memory/llm-request-log-store.ts +1 -26
  230. package/src/memory/llm-usage-store.ts +20 -48
  231. package/src/memory/memory-retrospective-job.ts +8 -9
  232. package/src/memory/migrations/209-strip-thinking-from-consolidated.ts +56 -130
  233. package/src/memory/migrations/__tests__/run-migrations.test.ts +2 -2
  234. package/src/memory/migrations/registry.ts +573 -0
  235. package/src/memory/migrations/run-migrations.ts +6 -90
  236. package/src/memory/migrations/validate-migration-state.ts +66 -101
  237. package/src/memory/schema/conversations.ts +0 -9
  238. package/src/memory/schema/infrastructure.ts +0 -20
  239. package/src/memory/v2/__tests__/cli-command-store.test.ts +0 -25
  240. package/src/memory/v2/__tests__/skill-store.test.ts +0 -80
  241. package/src/memory/v2/cli-command-store.ts +38 -75
  242. package/src/memory/v2/prompts/consolidation.ts +82 -13
  243. package/src/memory/v2/prompts/router.ts +93 -21
  244. package/src/memory/v2/skill-store.ts +31 -68
  245. package/src/notifications/__tests__/broadcaster.test.ts +8 -16
  246. package/src/notifications/__tests__/decision-engine.test.ts +9 -78
  247. package/src/notifications/broadcaster.ts +1 -8
  248. package/src/notifications/decision-engine.ts +7 -15
  249. package/src/notifications/destination-resolver.ts +24 -68
  250. package/src/notifications/emit-signal.ts +14 -39
  251. package/src/permissions/question-prompter.test.ts +1 -1
  252. package/src/permissions/question-prompter.ts +4 -7
  253. package/src/plugin-api/index.ts +6 -6
  254. package/src/plugin-api/types.ts +5 -3
  255. package/src/plugin-api/vision-support.test.ts +4 -28
  256. package/src/plugin-api/vision-support.ts +31 -66
  257. package/src/plugins/defaults/advisor/__tests__/consult.test.ts +0 -161
  258. package/src/plugins/defaults/advisor/consult.ts +6 -110
  259. package/src/plugins/defaults/advisor/steering.ts +2 -14
  260. package/src/plugins/defaults/advisor/tools/advisor.ts +5 -32
  261. package/src/plugins/defaults/exploration-drift/hooks/post-tool-use.ts +1 -2
  262. package/src/plugins/defaults/image-fallback/__tests__/image-fallback.test.ts +7 -47
  263. package/src/plugins/defaults/image-fallback/hooks/post-tool-use.ts +11 -10
  264. package/src/plugins/defaults/image-fallback/hooks/user-prompt-submit.ts +20 -12
  265. package/src/plugins/defaults/image-fallback/src/caption-blocks.ts +11 -42
  266. package/src/plugins/defaults/memory-v3-shadow/__tests__/injection.test.ts +3 -33
  267. package/src/plugins/defaults/memory-v3-shadow/__tests__/pool-select.test.ts +4 -48
  268. package/src/plugins/defaults/memory-v3-shadow/__tests__/shadow-plugin.test.ts +8 -4
  269. package/src/plugins/defaults/memory-v3-shadow/injector.ts +15 -43
  270. package/src/plugins/defaults/memory-v3-shadow/orchestrate.ts +2 -11
  271. package/src/plugins/defaults/memory-v3-shadow/pool-select.ts +13 -77
  272. package/src/plugins/defaults/memory-v3-shadow/shadow-plugin.ts +11 -12
  273. package/src/plugins/mtime-cache.ts +291 -76
  274. package/src/plugins/pipeline.ts +13 -111
  275. package/src/plugins/types.ts +2 -0
  276. package/src/providers/anthropic/client.ts +0 -5
  277. package/src/providers/call-site-routing.ts +0 -4
  278. package/src/providers/model-catalog.ts +0 -16
  279. package/src/providers/openai/__tests__/api-error-detail.test.ts +120 -0
  280. package/src/providers/openai/chat-completions-provider.ts +83 -37
  281. package/src/providers/openai/responses-provider.ts +46 -50
  282. package/src/providers/openrouter/client.ts +0 -5
  283. package/src/providers/provider-send-message.ts +0 -4
  284. package/src/providers/ratelimit.ts +0 -4
  285. package/src/providers/retry.ts +0 -4
  286. package/src/providers/types.ts +0 -9
  287. package/src/providers/usage-tracking.ts +0 -4
  288. package/src/runtime/__tests__/trust-verdict-consumer.test.ts +3 -335
  289. package/src/runtime/access-request-helper.ts +39 -19
  290. package/src/runtime/actor-trust-resolver.ts +2 -2
  291. package/src/runtime/assistant-event-hub.ts +1 -1
  292. package/src/runtime/assistant-stream-state.ts +2 -9
  293. package/src/runtime/auth/require-bound-guardian.ts +11 -21
  294. package/src/runtime/channel-verification-service.ts +31 -56
  295. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -3
  296. package/src/runtime/guardian-vellum-migration.ts +7 -66
  297. package/src/runtime/invite-redemption-service.ts +187 -198
  298. package/src/runtime/local-actor-identity.ts +11 -76
  299. package/src/runtime/pending-interactions.ts +1 -11
  300. package/src/runtime/routes/__tests__/channel-verification-revoke.test.ts +5 -56
  301. package/src/runtime/routes/__tests__/channel-verification-routes.test.ts +1 -1
  302. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +0 -187
  303. package/src/runtime/routes/browser-routes.ts +1 -1
  304. package/src/runtime/routes/canonical-guardian-expiry-sweep.ts +5 -13
  305. package/src/runtime/routes/channel-verification-routes.ts +3 -3
  306. package/src/runtime/routes/contact-routes.ts +32 -8
  307. package/src/runtime/routes/conversation-cli-routes.ts +5 -4
  308. package/src/runtime/routes/conversation-list-routes.ts +7 -4
  309. package/src/runtime/routes/conversation-query-routes.ts +0 -72
  310. package/src/runtime/routes/conversation-routes.ts +85 -84
  311. package/src/runtime/routes/events-routes.ts +2 -2
  312. package/src/runtime/routes/global-search-routes.ts +1 -3
  313. package/src/runtime/routes/guardian-action-routes.ts +5 -4
  314. package/src/runtime/routes/host-app-control-routes.ts +4 -5
  315. package/src/runtime/routes/host-bash-routes.ts +4 -5
  316. package/src/runtime/routes/host-browser-routes.ts +11 -9
  317. package/src/runtime/routes/host-cu-routes.ts +4 -5
  318. package/src/runtime/routes/host-file-routes.ts +4 -5
  319. package/src/runtime/routes/host-transfer-routes.ts +6 -6
  320. package/src/runtime/routes/http-adapter.ts +1 -1
  321. package/src/runtime/routes/identity-routes.ts +2 -3
  322. package/src/runtime/routes/inbound-message-handler.ts +5 -5
  323. package/src/runtime/routes/inbound-stages/acl-enforcement.test.ts +5 -97
  324. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +49 -61
  325. package/src/runtime/routes/inbound-stages/background-dispatch.ts +4 -16
  326. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +7 -7
  327. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.test.ts +8 -21
  328. package/src/runtime/routes/inbound-stages/guardian-activation-intercept.ts +3 -14
  329. package/src/runtime/routes/index.ts +0 -2
  330. package/src/runtime/routes/llm-context-normalization.ts +0 -83
  331. package/src/runtime/routes/mcp-auth-routes.ts +19 -171
  332. package/src/runtime/routes/migration-rollback-routes.ts +3 -4
  333. package/src/runtime/routes/migration-routes.ts +1 -4
  334. package/src/runtime/routes/subagents-routes.ts +0 -5
  335. package/src/runtime/routes/surface-action-routes.ts +56 -42
  336. package/src/runtime/services/__tests__/conversation-serializer.test.ts +0 -1
  337. package/src/runtime/services/conversation-serializer.ts +9 -7
  338. package/src/runtime/tool-grant-request-helper.ts +3 -3
  339. package/src/runtime/trust-verdict-consumer.ts +9 -85
  340. package/src/runtime/verification-outbound-actions.ts +18 -18
  341. package/src/signals/user-message.ts +0 -16
  342. package/src/subagent/manager.ts +0 -9
  343. package/src/subagent/types.ts +3 -3
  344. package/src/telemetry/types.ts +1 -34
  345. package/src/telemetry/usage-telemetry-reporter.test.ts +2 -3
  346. package/src/telemetry/usage-telemetry-reporter.ts +3 -87
  347. package/src/tools/ask-question/ask-question-tool.test.ts +0 -29
  348. package/src/tools/ask-question/ask-question-tool.ts +0 -13
  349. package/src/tools/executor.ts +4 -4
  350. package/src/tools/registry.ts +0 -18
  351. package/src/tools/shared/filesystem/path-policy.ts +5 -12
  352. package/src/tools/tool-approval-handler.ts +1 -1
  353. package/src/tools/tool-defaults.ts +2 -9
  354. package/src/tools/tool-manifest.ts +0 -3
  355. package/src/tools/types.ts +2 -17
  356. package/src/tools/workspace-tools/loader.ts +244 -348
  357. package/src/util/errors.ts +1 -26
  358. package/src/util/platform.ts +0 -5
  359. package/src/workflows/library.test.ts +0 -140
  360. package/src/workflows/library.ts +28 -82
  361. package/src/workspace/migrations/017-seed-persona-dirs.ts +34 -3
  362. package/src/workspace/migrations/019-scope-journal-to-guardian.ts +24 -3
  363. package/src/workspace/migrations/048-remove-workspace-hooks.ts +66 -14
  364. package/src/workspace/migrations/registry.ts +0 -2
  365. package/node_modules/@vellumai/gateway-client/src/__tests__/guardian-delivery-contract.test.ts +0 -91
  366. package/node_modules/@vellumai/gateway-client/src/guardian-delivery-contract.ts +0 -48
  367. package/node_modules/@vellumai/service-contracts/src/__tests__/channels.test.ts +0 -28
  368. package/node_modules/@vellumai/service-contracts/src/channels.ts +0 -41
  369. package/src/__tests__/code-search-tool.test.ts +0 -585
  370. package/src/__tests__/guardian-expiry-notifier.test.ts +0 -282
  371. package/src/__tests__/mcp-config-secret-boundary.test.ts +0 -390
  372. package/src/__tests__/plugin-pipeline.test.ts +0 -96
  373. package/src/__tests__/sse-actor-principal-guardian-source.test.ts +0 -102
  374. package/src/__tests__/steer-on-enqueue-question.test.ts +0 -181
  375. package/src/__tests__/workspace-migration-111-prune-seeded-callsite-defaults.test.ts +0 -208
  376. package/src/agent/loop-exclusive-tool.test.ts +0 -150
  377. package/src/api/constants/sse-replay.ts +0 -41
  378. package/src/api/events/conversation-notice.ts +0 -26
  379. package/src/approvals/guardian-channel-delivery.ts +0 -30
  380. package/src/approvals/guardian-expiry-notifier.ts +0 -148
  381. package/src/cli/commands/memory/__tests__/worker.test.ts +0 -302
  382. package/src/cli/commands/memory/worker.ts +0 -175
  383. package/src/config/__tests__/loader-callsite-strip-fallback.test.ts +0 -143
  384. package/src/config/prune-seeded-callsite-defaults.ts +0 -110
  385. package/src/contacts/__tests__/contacts-write-revoke-relay.test.ts +0 -129
  386. package/src/contacts/__tests__/guardian-delivery-reader.test.ts +0 -312
  387. package/src/contacts/__tests__/member-write-relay.test.ts +0 -202
  388. package/src/contacts/guardian-delivery-reader.ts +0 -223
  389. package/src/contacts/member-write-relay.ts +0 -189
  390. package/src/daemon/conversation-notices.ts +0 -60
  391. package/src/daemon/handlers/__tests__/config-channels.test.ts +0 -225
  392. package/src/hooks/hook-loader.ts +0 -341
  393. package/src/mcp/mcp-header-store.ts +0 -134
  394. package/src/memory/__tests__/301-create-watchdog-events.test.ts +0 -110
  395. package/src/memory/__tests__/prompt-override.test.ts +0 -192
  396. package/src/memory/__tests__/watchdog-events-store.test.ts +0 -161
  397. package/src/memory/migrations/300-add-processing-started-at.ts +0 -30
  398. package/src/memory/migrations/301-create-watchdog-events.ts +0 -45
  399. package/src/memory/migrations/__tests__/209-strip-thinking-from-consolidated.test.ts +0 -224
  400. package/src/memory/prompt-override.ts +0 -129
  401. package/src/memory/steps.ts +0 -573
  402. package/src/memory/watchdog-events-store.ts +0 -87
  403. package/src/memory/worker-control.ts +0 -118
  404. package/src/memory/worker-process.ts +0 -72
  405. package/src/notifications/__tests__/connected-channels.test.ts +0 -114
  406. package/src/notifications/__tests__/destination-resolver.test.ts +0 -256
  407. package/src/onboarding/checkin-event.test.ts +0 -222
  408. package/src/onboarding/checkin-event.ts +0 -321
  409. package/src/onboarding/schedule-checkin.ts +0 -190
  410. package/src/plugins/defaults/advisor/__tests__/context-pack-gating.test.ts +0 -106
  411. package/src/plugins/defaults/advisor/__tests__/context-pack.test.ts +0 -60
  412. package/src/plugins/defaults/advisor/context-pack.ts +0 -288
  413. package/src/plugins/defaults/memory-v3-shadow/pool-select.test.ts +0 -146
  414. package/src/plugins/surface-import.ts +0 -121
  415. package/src/providers/openai/__tests__/api-error-normalization.test.ts +0 -321
  416. package/src/providers/openai/api-error-normalization.ts +0 -270
  417. package/src/runtime/__tests__/channel-verification-service.test.ts +0 -133
  418. package/src/runtime/__tests__/guardian-vellum-migration.test.ts +0 -181
  419. package/src/runtime/__tests__/is-guardian-bound-for-channel.test.ts +0 -66
  420. package/src/runtime/__tests__/local-principal-trust.test.ts +0 -164
  421. package/src/runtime/anchored-guardian.test.ts +0 -156
  422. package/src/runtime/anchored-guardian.ts +0 -135
  423. package/src/runtime/auth/__tests__/require-bound-guardian.test.ts +0 -99
  424. package/src/runtime/local-principal-trust.ts +0 -52
  425. package/src/runtime/routes/__tests__/contact-routes.test.ts +0 -212
  426. package/src/runtime/routes/__tests__/global-search-routes.test.ts +0 -93
  427. package/src/runtime/routes/onboarding-checkin-routes.ts +0 -86
  428. package/src/tools/filesystem/search.ts +0 -543
  429. package/src/util/telemetry-db-path.ts +0 -24
  430. package/src/workspace/migrations/111-prune-seeded-callsite-defaults.ts +0 -134
@@ -1,341 +0,0 @@
1
- /**
2
- * Hook surface loader — the first-class home for user-land lifecycle/event
3
- * hooks.
4
- *
5
- * A "hook" is a named lifecycle event (`init`, `shutdown`, `user-prompt-submit`,
6
- * `post-tool-use`, `stop`, ...) handled by a default export. Hooks come from
7
- * two surfaces, both cached here keyed by their source file's mtime:
8
- *
9
- * - **Plugin hooks** — `<workspace>/plugins/<name>/hooks/<event>.{ts,js}`,
10
- * discovered alongside the owning plugin's tools.
11
- * - **Workspace hooks** — `<workspace>/hooks/<event>.{ts,js}`, standalone
12
- * files not tied to any plugin (no `package.json`, no tools — just hooks).
13
- *
14
- * This module owns the hook cache and every hook operation (collect, init,
15
- * shutdown, eviction). Plugin *discovery* (which plugin directories exist, in
16
- * what order) lives in `../plugins/mtime-cache.ts`; the orchestrator there
17
- * passes the discovered directories into {@link collectUserHooks} and drives
18
- * pre-import / init / shutdown at boot. Keeping discovery out of this module
19
- * lets it sit below the plugin cache with no import cycle.
20
- */
21
-
22
- import { mkdirSync } from "node:fs";
23
- import { join } from "node:path";
24
-
25
- import { getConfig } from "../config/loader.js";
26
- import { HOOKS } from "../plugin-api/constants.js";
27
- import type {
28
- PluginHookFn,
29
- PluginInitContext,
30
- PluginShutdownContext,
31
- } from "../plugin-api/types.js";
32
- import { listSurfaceDir } from "../plugins/external-plugin-loader.js";
33
- import { getMtime, importWithTimeout } from "../plugins/surface-import.js";
34
- import { getLogger } from "../util/logger.js";
35
- import { getWorkspaceDir, getWorkspaceHooksDir } from "../util/platform.js";
36
- import { APP_VERSION } from "../version.js";
37
-
38
- const log = getLogger("hook-loader");
39
-
40
- /**
41
- * Synthetic owner name for standalone hooks that live directly under
42
- * `<workspace>/hooks/` rather than inside a plugin's `hooks/` directory.
43
- *
44
- * Used as the cache-key prefix (`__workspace__/<hookName>`) so workspace
45
- * hooks never collide with a plugin's hooks. The leading/trailing double
46
- * underscores keep it disjoint from any scope-stripped npm package name a
47
- * real plugin could carry.
48
- */
49
- export const WORKSPACE_HOOKS_OWNER = "__workspace__";
50
-
51
- /**
52
- * A cached hook function plus the mtime of its source file. When the on-disk
53
- * mtime changes, the hook is re-imported and the entry is replaced.
54
- */
55
- interface CachedHook {
56
- readonly hook: PluginHookFn;
57
- /** mtimeMs of the source file this hook was imported from. */
58
- readonly sourceMtime: number;
59
- }
60
-
61
- /**
62
- * Cached hooks keyed by `${ownerName}/${hookName}`. The key includes the
63
- * owner (plugin name, or {@link WORKSPACE_HOOKS_OWNER}) so hooks from
64
- * different owners don't collide.
65
- */
66
- const hookCache = new Map<string, CachedHook>();
67
-
68
- /** Cache key for a hook: `${ownerName}/${hookName}`. */
69
- function hookKey(ownerName: string, hookName: string): string {
70
- return `${ownerName}/${hookName}`;
71
- }
72
-
73
- /**
74
- * Resolve a single hook file through the mtime cache: return the cached hook
75
- * when its source mtime is unchanged, otherwise re-import and refresh the
76
- * entry. Returns `undefined` when the file was deleted (evicting any stale
77
- * entry) or the import failed / produced a non-function default export.
78
- *
79
- * `ownerName` is the cache-key prefix and the attribution label in logs (a
80
- * plugin name, or {@link WORKSPACE_HOOKS_OWNER}).
81
- */
82
- async function resolveCachedHook<TCtx>(
83
- ownerName: string,
84
- hookName: string,
85
- filePath: string,
86
- ): Promise<PluginHookFn<TCtx> | undefined> {
87
- const key = hookKey(ownerName, hookName);
88
- const currentMtime = getMtime(filePath);
89
-
90
- // Cache hit — same mtime.
91
- const cached = hookCache.get(key);
92
- if (
93
- cached !== undefined &&
94
- cached.sourceMtime === currentMtime &&
95
- currentMtime > 0
96
- ) {
97
- return cached.hook as PluginHookFn<TCtx>;
98
- }
99
-
100
- // Cache miss — re-import.
101
- if (currentMtime === 0) {
102
- // File was deleted between listing and stat — evict the cache entry.
103
- hookCache.delete(key);
104
- return undefined;
105
- }
106
-
107
- try {
108
- const hook = await importWithTimeout<PluginHookFn>(filePath);
109
- if (hook === undefined || typeof hook !== "function") {
110
- log.error(
111
- { plugin: ownerName, hook: hookName, path: filePath },
112
- `hook ${hookName} default export must be a function (got ${typeof hook}) — skipping`,
113
- );
114
- return undefined;
115
- }
116
- hookCache.set(key, { hook, sourceMtime: currentMtime });
117
- return hook as PluginHookFn<TCtx>;
118
- } catch (err) {
119
- log.error(
120
- { err, plugin: ownerName, hook: hookName, path: filePath },
121
- `Failed to import hook ${hookName} from ${filePath}`,
122
- );
123
- return undefined;
124
- }
125
- }
126
-
127
- /**
128
- * Collect every hook for a given event name across all surfaces, re-importing
129
- * any whose source file's mtime changed since the cache was populated.
130
- *
131
- * `pluginDirs` is the orchestrator's discovered `[dir, ownerName]` set (in
132
- * install-date order). Each plugin's hook runs first, then the standalone
133
- * workspace hook under `<workspace>/hooks/<hookName>.{ts,js}` runs last — so
134
- * a plugin can shape the threaded context before a workspace-wide hook
135
- * observes or finalizes it.
136
- *
137
- * Added and removed hook files are picked up live (discovery is by directory
138
- * listing). A content edit to an existing file is only reflected after a
139
- * process restart, since Bun caches dynamic imports by resolved path.
140
- */
141
- export async function collectUserHooks<TCtx = unknown>(
142
- hookName: string,
143
- pluginDirs: Iterable<readonly [string, string]>,
144
- ): Promise<PluginHookFn<TCtx>[]> {
145
- const out: PluginHookFn<TCtx>[] = [];
146
-
147
- for (const [pluginDir, pluginName] of pluginDirs) {
148
- const hookFile = listSurfaceDir(join(pluginDir, "hooks")).find(
149
- (f) => f.name === hookName,
150
- );
151
- if (hookFile === undefined) continue;
152
-
153
- const hook = await resolveCachedHook<TCtx>(
154
- pluginName,
155
- hookName,
156
- hookFile.path,
157
- );
158
- if (hook !== undefined) out.push(hook);
159
- }
160
-
161
- // Standalone workspace hooks: files directly under `<workspace>/hooks/`
162
- // that are not part of any plugin (no package.json, no tools — just hooks).
163
- const wsHookFile = listSurfaceDir(getWorkspaceHooksDir()).find(
164
- (f) => f.name === hookName,
165
- );
166
- if (wsHookFile !== undefined) {
167
- const hook = await resolveCachedHook<TCtx>(
168
- WORKSPACE_HOOKS_OWNER,
169
- hookName,
170
- wsHookFile.path,
171
- );
172
- if (hook !== undefined) out.push(hook);
173
- }
174
-
175
- return out;
176
- }
177
-
178
- /**
179
- * Pre-import every hook file under `hooksDir` and cache it keyed by
180
- * `${ownerName}/${hookName}`, so the first turn doesn't pay the import cost.
181
- * Best-effort per file: a failing import is logged and skipped. A missing
182
- * directory yields no files (handled by {@link listSurfaceDir}).
183
- */
184
- export async function preImportHooksDir(
185
- hooksDir: string,
186
- ownerName: string,
187
- ): Promise<void> {
188
- for (const file of listSurfaceDir(hooksDir)) {
189
- const key = hookKey(ownerName, file.name);
190
- const currentMtime = getMtime(file.path);
191
- if (currentMtime === 0) continue;
192
-
193
- try {
194
- const hook = await importWithTimeout<PluginHookFn>(file.path);
195
- if (hook !== undefined && typeof hook === "function") {
196
- hookCache.set(key, { hook, sourceMtime: currentMtime });
197
- }
198
- } catch (err) {
199
- log.error(
200
- { err, plugin: ownerName, hook: file.name, path: file.path },
201
- `Failed to pre-import hook ${file.name}`,
202
- );
203
- }
204
- }
205
- }
206
-
207
- /**
208
- * Whether the standalone workspace hooks directory currently holds any hook
209
- * files. Used by the boot orchestrator to skip activating (and registering
210
- * teardown for) an empty/absent directory.
211
- */
212
- export function hasWorkspaceHooks(): boolean {
213
- return listSurfaceDir(getWorkspaceHooksDir()).length > 0;
214
- }
215
-
216
- /**
217
- * Pre-import the standalone workspace hooks under {@link WORKSPACE_HOOKS_OWNER}.
218
- * Convenience wrapper over {@link preImportHooksDir} that keeps the workspace
219
- * hooks directory path inside this module.
220
- */
221
- export async function preImportWorkspaceHooks(): Promise<void> {
222
- await preImportHooksDir(getWorkspaceHooksDir(), WORKSPACE_HOOKS_OWNER);
223
- }
224
-
225
- /**
226
- * Run the `init` hook for `ownerName` if one was pre-imported into the cache.
227
- * Shared by user plugins and standalone workspace hooks so both get the same
228
- * init-context shape and per-owner isolation (a thrown `init` is logged and
229
- * swallowed, never blocking boot).
230
- */
231
- export async function runInitHook(ownerName: string): Promise<void> {
232
- const initHookEntry = hookCache.get(hookKey(ownerName, HOOKS.INIT));
233
- if (initHookEntry === undefined) return;
234
-
235
- try {
236
- const initContext: PluginInitContext = {
237
- config: getConfig().plugins?.[ownerName],
238
- logger: log.child({ plugin: ownerName }),
239
- pluginStorageDir: ensureHookStorageDir(ownerName),
240
- assistantVersion: APP_VERSION,
241
- };
242
- await initHookEntry.hook(initContext);
243
- log.info({ plugin: ownerName }, "user hooks initialized");
244
- } catch (err) {
245
- log.error(
246
- { err, plugin: ownerName },
247
- `User hooks for ${ownerName} init() failed — continuing`,
248
- );
249
- }
250
- }
251
-
252
- /**
253
- * Run the `shutdown` hook for `ownerName` if one is cached. Best-effort: a
254
- * thrown shutdown is logged and swallowed. `reason` is threaded into the log
255
- * for attribution only.
256
- */
257
- export async function runShutdownHook(
258
- ownerName: string,
259
- context: PluginShutdownContext,
260
- reason: string,
261
- ): Promise<void> {
262
- const shutdownHookEntry = hookCache.get(hookKey(ownerName, HOOKS.SHUTDOWN));
263
- if (shutdownHookEntry === undefined) return;
264
-
265
- try {
266
- await shutdownHookEntry.hook(context);
267
- } catch (err) {
268
- log.warn(
269
- { err, plugin: ownerName, reason },
270
- "user hooks shutdown failed (continuing)",
271
- );
272
- }
273
- }
274
-
275
- /**
276
- * Evict every cached hook owned by `ownerName` (e.g. when a plugin directory
277
- * is removed). No-op when the owner has no cached hooks.
278
- */
279
- export function evictHooksForOwner(ownerName: string): void {
280
- const prefix = `${ownerName}/`;
281
- for (const key of hookCache.keys()) {
282
- if (key.startsWith(prefix)) {
283
- hookCache.delete(key);
284
- }
285
- }
286
- }
287
-
288
- /**
289
- * Evict all plugin-owned hooks while preserving standalone workspace hooks.
290
- * Called when the plugins directory is gone entirely: workspace hooks live
291
- * outside it, so the absence of any plugin must not evict them.
292
- */
293
- export function clearPluginHooks(): void {
294
- for (const key of hookCache.keys()) {
295
- if (!key.startsWith(`${WORKSPACE_HOOKS_OWNER}/`)) {
296
- hookCache.delete(key);
297
- }
298
- }
299
- }
300
-
301
- /**
302
- * Ensure `<workspaceDir>/plugins-data/<name>/` exists and return its path.
303
- * Used as the per-owner storage directory in the hook init context.
304
- */
305
- function ensureHookStorageDir(ownerName: string): string {
306
- const dir = join(getWorkspaceDir(), "plugins-data", ownerName);
307
- mkdirSync(dir, { recursive: true });
308
- return dir;
309
- }
310
-
311
- // ─── Test hooks ──────────────────────────────────────────────────────────────
312
-
313
- /** Clear the hook cache. Test-only. */
314
- export function resetHookCacheForTests(): void {
315
- const isTest =
316
- process.env.BUN_TEST === "1" || process.env.NODE_ENV === "test";
317
- if (!isTest) {
318
- throw new Error(
319
- "resetHookCacheForTests may only be called in test environments",
320
- );
321
- }
322
- hookCache.clear();
323
- }
324
-
325
- /** Test-only: inspect the hook cache. */
326
- export function _inspectHookCacheForTests(): Array<{
327
- key: string;
328
- sourceMtime: number;
329
- }> {
330
- const isTest =
331
- process.env.BUN_TEST === "1" || process.env.NODE_ENV === "test";
332
- if (!isTest) {
333
- throw new Error(
334
- "_inspectHookCacheForTests may only be called in test environments",
335
- );
336
- }
337
- return Array.from(hookCache.entries()).map(([key, c]) => ({
338
- key,
339
- sourceMtime: c.sourceMtime,
340
- }));
341
- }
@@ -1,134 +0,0 @@
1
- /**
2
- * Credential-store-backed persistence for MCP server static auth headers.
3
- *
4
- * Follows the same pattern as mcp-oauth-provider.ts: headers are stored in
5
- * the secure credential store (CES or encrypted file fallback) rather than
6
- * in plaintext config.json, keeping secrets out of workspace config files.
7
- *
8
- * Key format: mcp:{serverId}:headers — stores JSON-serialized Record<string, string>.
9
- */
10
-
11
- import { loadRawConfig, saveRawConfig } from "../config/loader.js";
12
- import {
13
- deleteSecureKeyAsync,
14
- getSecureKeyAsync,
15
- setSecureKeyAsync,
16
- } from "../security/secure-keys.js";
17
- import { getLogger } from "../util/logger.js";
18
-
19
- const log = getLogger("mcp-header-store");
20
-
21
- function headersKey(serverId: string): string {
22
- return `mcp:${serverId}:headers`;
23
- }
24
-
25
- /**
26
- * Retrieve stored static auth headers for an MCP server.
27
- * Returns undefined if none are stored or if the credential store is unreachable.
28
- */
29
- export async function getMcpHeaders(
30
- serverId: string,
31
- ): Promise<Record<string, string> | undefined> {
32
- const raw = await getSecureKeyAsync(headersKey(serverId));
33
- if (!raw) return undefined;
34
- try {
35
- return JSON.parse(raw) as Record<string, string>;
36
- } catch {
37
- log.warn({ serverId }, "Failed to parse stored MCP headers");
38
- return undefined;
39
- }
40
- }
41
-
42
- /**
43
- * Store static auth headers for an MCP server in the credential store.
44
- */
45
- export async function setMcpHeaders(
46
- serverId: string,
47
- headers: Record<string, string>,
48
- ): Promise<boolean> {
49
- const ok = await setSecureKeyAsync(
50
- headersKey(serverId),
51
- JSON.stringify(headers),
52
- );
53
- if (!ok) {
54
- log.warn({ serverId }, "Failed to persist MCP headers to secure storage");
55
- return false;
56
- }
57
- log.info({ serverId }, "MCP static auth headers saved to credential store");
58
- return true;
59
- }
60
-
61
- /**
62
- * Delete stored static auth headers for an MCP server.
63
- */
64
- export async function deleteMcpHeaders(serverId: string): Promise<boolean> {
65
- const result = await deleteSecureKeyAsync(headersKey(serverId));
66
- if (result === "error") {
67
- log.warn({ serverId }, "Failed to delete MCP headers from secure storage");
68
- return false;
69
- }
70
- return true;
71
- }
72
-
73
- /**
74
- * One-time lazy migration: move any plaintext headers from config.json
75
- * transport entries into the credential store and strip them from config.
76
- * Safe to call on every MCP reload — no-ops when no legacy headers remain.
77
- */
78
- export async function migrateLegacyMcpHeaders(): Promise<void> {
79
- const raw = loadRawConfig();
80
- const mcpConfig = raw.mcp as
81
- | { servers?: Record<string, Record<string, unknown>> }
82
- | undefined;
83
- const servers = mcpConfig?.servers;
84
- if (!servers) {
85
- return;
86
- }
87
-
88
- let configDirty = false;
89
- for (const [id, server] of Object.entries(servers)) {
90
- const transport = server?.transport as Record<string, unknown> | undefined;
91
- if (
92
- !transport ||
93
- (transport.type !== "sse" && transport.type !== "streamable-http")
94
- ) {
95
- continue;
96
- }
97
- const legacyHeaders = transport.headers as
98
- | Record<string, string>
99
- | undefined;
100
- if (!legacyHeaders || Object.keys(legacyHeaders).length === 0) {
101
- continue;
102
- }
103
-
104
- // Only migrate if credential store doesn't already have headers for
105
- // this server (idempotent — safe to re-run after partial failure).
106
- const existing = await getMcpHeaders(id);
107
- if (existing) {
108
- // Credential store already has headers; just strip the config copy.
109
- delete transport.headers;
110
- configDirty = true;
111
- continue;
112
- }
113
-
114
- const ok = await setMcpHeaders(id, legacyHeaders);
115
- if (ok) {
116
- delete transport.headers;
117
- configDirty = true;
118
- log.info(
119
- { serverId: id },
120
- "Migrated legacy MCP headers to credential store",
121
- );
122
- } else {
123
- log.warn(
124
- { serverId: id },
125
- "Skipping legacy header migration — credential store write failed; will retry on next reload",
126
- );
127
- }
128
- }
129
-
130
- if (configDirty) {
131
- saveRawConfig(raw);
132
- log.info("Config updated: legacy MCP headers removed after migration");
133
- }
134
- }
@@ -1,110 +0,0 @@
1
- import { mkdtempSync } from "node:fs";
2
- import { tmpdir } from "node:os";
3
- import { join } from "node:path";
4
- import { Database } from "bun:sqlite";
5
- import { describe, expect, mock, test } from "bun:test";
6
-
7
- import { drizzle } from "drizzle-orm/bun-sqlite";
8
-
9
- // The migration opens the telemetry connection via getTelemetrySqlite(), which
10
- // routes through the singleton. Mock the path helper so the connection opens a
11
- // temp file we control, then mock the db-connection getter so it returns that
12
- // same file's Database.
13
- const tmpDir = mkdtempSync(join(tmpdir(), "wd-migration-"));
14
- const telemetryPath = join(tmpDir, "assistant-telemetry.db");
15
- let openedRaw: Database | null = null;
16
-
17
- mock.module("../../util/telemetry-db-path.js", () => ({
18
- getTelemetryDbPath: () => telemetryPath,
19
- }));
20
-
21
- mock.module("../db-connection.js", () => ({
22
- // The migration calls getTelemetrySqlite(); return our temp Database so the
23
- // DDL runs against it. getSqliteFrom is used in other contexts but not by
24
- // this migration when the mock is active.
25
- getTelemetrySqlite: () => openedRaw,
26
- getSqliteFrom: (db: unknown) =>
27
- (db as unknown as { $client: Database }).$client,
28
- }));
29
-
30
- import { createWatchdogEventsTable } from "../migrations/301-create-watchdog-events.js";
31
- import * as schema from "../schema.js";
32
-
33
- function createTestDb() {
34
- const sqlite = new Database(":memory:");
35
- return { sqlite, db: drizzle(sqlite, { schema }) };
36
- }
37
-
38
- function openTelemetryRaw(): Database {
39
- openedRaw = new Database(telemetryPath);
40
- return openedRaw;
41
- }
42
-
43
- function columnNames(raw: Database): string[] {
44
- return (
45
- raw.query("PRAGMA table_info(watchdog_events)").all() as Array<{
46
- name: string;
47
- }>
48
- ).map((c) => c.name);
49
- }
50
-
51
- function indexNames(raw: Database): string[] {
52
- return (
53
- raw.query("PRAGMA index_list(watchdog_events)").all() as Array<{
54
- name: string;
55
- }>
56
- ).map((i) => i.name);
57
- }
58
-
59
- describe("migration 300: watchdog_events table on telemetry DB", () => {
60
- test("creates the table with the expected columns", () => {
61
- const raw = openTelemetryRaw();
62
- const { db } = createTestDb();
63
-
64
- createWatchdogEventsTable(db);
65
-
66
- expect(columnNames(raw)).toEqual([
67
- "id",
68
- "created_at",
69
- "check_name",
70
- "value",
71
- "detail",
72
- ]);
73
- });
74
-
75
- test("creates the (created_at, id) cursor index", () => {
76
- const raw = openTelemetryRaw();
77
- const { db } = createTestDb();
78
-
79
- createWatchdogEventsTable(db);
80
-
81
- expect(indexNames(raw)).toContain("idx_watchdog_events_created_at_id");
82
- const columns = (
83
- raw
84
- .query("PRAGMA index_info(idx_watchdog_events_created_at_id)")
85
- .all() as Array<{ name: string }>
86
- ).map((c) => c.name);
87
- expect(columns).toEqual(["created_at", "id"]);
88
- });
89
-
90
- test("is idempotent — re-run is a no-op and preserves existing rows", () => {
91
- const raw = openTelemetryRaw();
92
- const { db } = createTestDb();
93
-
94
- createWatchdogEventsTable(db);
95
- raw.exec(/*sql*/ `
96
- INSERT INTO watchdog_events (id, created_at, check_name, value)
97
- VALUES ('wd-1', 1000, 'event_loop_blocked', 60000)
98
- `);
99
-
100
- expect(() => createWatchdogEventsTable(db)).not.toThrow();
101
-
102
- const rows = raw.query("SELECT id FROM watchdog_events").all();
103
- expect(rows).toEqual([{ id: "wd-1" }]);
104
- expect(
105
- indexNames(raw).filter(
106
- (name) => name === "idx_watchdog_events_created_at_id",
107
- ),
108
- ).toHaveLength(1);
109
- });
110
- });