@vellumai/assistant 0.5.13 → 0.5.14

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 (425) hide show
  1. package/.env.example +1 -6
  2. package/AGENTS.md +4 -0
  3. package/ARCHITECTURE.md +0 -1
  4. package/bunfig.toml +1 -0
  5. package/docs/architecture/memory.md +3 -3
  6. package/openapi.yaml +127 -22
  7. package/package.json +1 -1
  8. package/src/__tests__/access-request-decision.test.ts +2 -32
  9. package/src/__tests__/actor-token-service.test.ts +1 -31
  10. package/src/__tests__/anthropic-provider.test.ts +53 -40
  11. package/src/__tests__/app-git-history.test.ts +9 -17
  12. package/src/__tests__/app-git-service.test.ts +14 -20
  13. package/src/__tests__/app-store-dir-names.test.ts +10 -20
  14. package/src/__tests__/approval-cascade.test.ts +2 -19
  15. package/src/__tests__/approval-primitive.test.ts +2 -27
  16. package/src/__tests__/approval-routes-http.test.ts +2 -30
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -28
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -45
  19. package/src/__tests__/attachments-store.test.ts +5 -32
  20. package/src/__tests__/audit-log-rotation.test.ts +5 -36
  21. package/src/__tests__/avatar-e2e.test.ts +1 -9
  22. package/src/__tests__/avatar-generator.test.ts +1 -7
  23. package/src/__tests__/browser-fill-credential.test.ts +0 -4
  24. package/src/__tests__/browser-manager.test.ts +0 -6
  25. package/src/__tests__/call-controller.test.ts +1 -22
  26. package/src/__tests__/call-conversation-messages.test.ts +0 -21
  27. package/src/__tests__/call-domain.test.ts +0 -25
  28. package/src/__tests__/call-pointer-messages.test.ts +0 -21
  29. package/src/__tests__/call-recovery.test.ts +0 -22
  30. package/src/__tests__/call-routes-http.test.ts +0 -24
  31. package/src/__tests__/call-store.test.ts +0 -21
  32. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -24
  33. package/src/__tests__/canonical-guardian-store.test.ts +48 -21
  34. package/src/__tests__/channel-approval-routes.test.ts +6 -26
  35. package/src/__tests__/channel-approvals.test.ts +1 -38
  36. package/src/__tests__/channel-delivery-store.test.ts +0 -21
  37. package/src/__tests__/channel-guardian.test.ts +0 -26
  38. package/src/__tests__/channel-reply-delivery.test.ts +5 -0
  39. package/src/__tests__/channel-retry-sweep.test.ts +0 -21
  40. package/src/__tests__/checker.test.ts +26 -61
  41. package/src/__tests__/clawhub.test.ts +9 -25
  42. package/src/__tests__/cli-command-risk-guard.test.ts +0 -18
  43. package/src/__tests__/config-loader-backfill.test.ts +9 -28
  44. package/src/__tests__/config-schema-cmd.test.ts +5 -25
  45. package/src/__tests__/config-schema.test.ts +21 -40
  46. package/src/__tests__/config-watcher.test.ts +4 -91
  47. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -21
  48. package/src/__tests__/contacts-tools.test.ts +0 -21
  49. package/src/__tests__/context-memory-e2e.test.ts +0 -21
  50. package/src/__tests__/context-window-manager.test.ts +130 -3
  51. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -4
  52. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -4
  53. package/src/__tests__/conversation-agent-loop.test.ts +0 -4
  54. package/src/__tests__/conversation-attachments.test.ts +1 -24
  55. package/src/__tests__/conversation-attention-store.test.ts +0 -21
  56. package/src/__tests__/conversation-attention-telegram.test.ts +0 -22
  57. package/src/__tests__/conversation-clear-safety.test.ts +0 -22
  58. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -21
  59. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -24
  60. package/src/__tests__/conversation-disk-view-integration.test.ts +1 -23
  61. package/src/__tests__/conversation-disk-view.test.ts +5 -27
  62. package/src/__tests__/conversation-error.test.ts +1 -1
  63. package/src/__tests__/conversation-fork-crud.test.ts +1 -33
  64. package/src/__tests__/conversation-fork-route.test.ts +0 -27
  65. package/src/__tests__/conversation-history-web-search.test.ts +23 -16
  66. package/src/__tests__/conversation-init.benchmark.test.ts +22 -43
  67. package/src/__tests__/conversation-key-store-disk-view.test.ts +8 -34
  68. package/src/__tests__/conversation-load-history-repair.test.ts +0 -4
  69. package/src/__tests__/conversation-pre-run-repair.test.ts +0 -4
  70. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -4
  71. package/src/__tests__/conversation-queue.test.ts +8 -8
  72. package/src/__tests__/conversation-routes-disk-view.test.ts +13 -51
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +64 -38
  74. package/src/__tests__/conversation-slash-commands.test.ts +5 -0
  75. package/src/__tests__/conversation-slash-queue.test.ts +0 -4
  76. package/src/__tests__/conversation-slash-unknown.test.ts +0 -4
  77. package/src/__tests__/conversation-speed-override.test.ts +326 -0
  78. package/src/__tests__/conversation-starter-routes.test.ts +0 -23
  79. package/src/__tests__/conversation-store.test.ts +0 -21
  80. package/src/__tests__/conversation-unread-route.test.ts +0 -24
  81. package/src/__tests__/conversation-usage.test.ts +56 -21
  82. package/src/__tests__/conversation-wipe.test.ts +0 -21
  83. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  84. package/src/__tests__/conversation-workspace-injection.test.ts +0 -4
  85. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -4
  86. package/src/__tests__/credential-execution-shell-lockdown.test.ts +8 -5
  87. package/src/__tests__/credential-vault-unit.test.ts +9 -428
  88. package/src/__tests__/credentials-cli.test.ts +10 -10
  89. package/src/__tests__/daemon-assistant-events.test.ts +0 -19
  90. package/src/__tests__/date-context.test.ts +77 -97
  91. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +7 -24
  92. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +29 -42
  93. package/src/__tests__/delete-managed-skill-tool.test.ts +2 -10
  94. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -26
  95. package/src/__tests__/docker-signing-key-bootstrap.test.ts +61 -15
  96. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -36
  97. package/src/__tests__/email-cli.test.ts +6 -6
  98. package/src/__tests__/ephemeral-permissions.test.ts +5 -17
  99. package/src/__tests__/first-greeting.test.ts +4 -32
  100. package/src/__tests__/followup-tools.test.ts +0 -21
  101. package/src/__tests__/gateway-only-enforcement.test.ts +0 -20
  102. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -23
  103. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -23
  104. package/src/__tests__/guardian-action-followup-store.test.ts +0 -21
  105. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -21
  106. package/src/__tests__/guardian-action-late-reply.test.ts +0 -21
  107. package/src/__tests__/guardian-action-store.test.ts +0 -21
  108. package/src/__tests__/guardian-action-sweep.test.ts +0 -21
  109. package/src/__tests__/guardian-binding-drift-heal.test.ts +0 -23
  110. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +172 -22
  111. package/src/__tests__/guardian-dispatch.test.ts +0 -21
  112. package/src/__tests__/guardian-grant-minting.test.ts +0 -22
  113. package/src/__tests__/guardian-outbound-http.test.ts +0 -22
  114. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -23
  115. package/src/__tests__/guardian-routing-invariants.test.ts +0 -22
  116. package/src/__tests__/guardian-routing-state.test.ts +0 -22
  117. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -24
  118. package/src/__tests__/headless-browser-interactions.test.ts +0 -4
  119. package/src/__tests__/headless-browser-navigate.test.ts +0 -4
  120. package/src/__tests__/headless-browser-read-tools.test.ts +0 -4
  121. package/src/__tests__/headless-browser-snapshot.test.ts +0 -4
  122. package/src/__tests__/heartbeat-service.test.ts +99 -26
  123. package/src/__tests__/hooks-blocking.test.ts +3 -3
  124. package/src/__tests__/hooks-config.test.ts +7 -7
  125. package/src/__tests__/hooks-discovery.test.ts +3 -3
  126. package/src/__tests__/hooks-integration.test.ts +5 -5
  127. package/src/__tests__/hooks-manager.test.ts +3 -3
  128. package/src/__tests__/hooks-runner.test.ts +5 -23
  129. package/src/__tests__/hooks-settings.test.ts +3 -3
  130. package/src/__tests__/hooks-templates.test.ts +3 -3
  131. package/src/__tests__/http-conversation-lineage.test.ts +0 -27
  132. package/src/__tests__/identity-intro-cache.test.ts +0 -4
  133. package/src/__tests__/inbound-invite-redemption.test.ts +0 -22
  134. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -16
  135. package/src/__tests__/intent-routing.test.ts +2 -55
  136. package/src/__tests__/invite-redemption-service.test.ts +0 -21
  137. package/src/__tests__/invite-routes-http.test.ts +0 -21
  138. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +0 -17
  139. package/src/__tests__/journal-context.test.ts +8 -75
  140. package/src/__tests__/list-messages-attachments.test.ts +0 -22
  141. package/src/__tests__/llm-context-route-provider.test.ts +0 -21
  142. package/src/__tests__/llm-request-log-turn-query.test.ts +46 -28
  143. package/src/__tests__/llm-usage-store.test.ts +0 -21
  144. package/src/__tests__/log-export-workspace.test.ts +1 -1
  145. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
  146. package/src/__tests__/managed-store.test.ts +1 -1
  147. package/src/__tests__/mcp-cli.test.ts +7 -10
  148. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -21
  149. package/src/__tests__/memory-jobs-worker-backoff.test.ts +0 -11
  150. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -21
  151. package/src/__tests__/memory-recall-log-store.test.ts +0 -27
  152. package/src/__tests__/memory-recall-quality.test.ts +0 -21
  153. package/src/__tests__/memory-regressions.experimental.test.ts +31 -30
  154. package/src/__tests__/memory-regressions.test.ts +282 -70
  155. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -21
  156. package/src/__tests__/memory-upsert-concurrency.test.ts +0 -21
  157. package/src/__tests__/messaging-send-tool.test.ts +201 -0
  158. package/src/__tests__/migration-cross-version-compatibility.test.ts +18 -13
  159. package/src/__tests__/migration-export-http.test.ts +7 -1
  160. package/src/__tests__/migration-import-commit-http.test.ts +16 -14
  161. package/src/__tests__/migration-import-preflight-http.test.ts +27 -44
  162. package/src/__tests__/migration-validate-http.test.ts +1 -28
  163. package/src/__tests__/native-web-search.test.ts +25 -22
  164. package/src/__tests__/non-member-access-request.test.ts +0 -22
  165. package/src/__tests__/notification-guardian-path.test.ts +0 -21
  166. package/src/__tests__/notification-schedule-dedup.test.ts +1 -25
  167. package/src/__tests__/oauth-apps-routes.test.ts +103 -2
  168. package/src/__tests__/oauth-cli.test.ts +52 -0
  169. package/src/__tests__/oauth-provider-profiles.test.ts +0 -16
  170. package/src/__tests__/oauth-provider-serializer.test.ts +232 -0
  171. package/src/__tests__/oauth-providers-routes.test.ts +257 -0
  172. package/src/__tests__/oauth-store.test.ts +0 -21
  173. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  174. package/src/__tests__/openai-provider.test.ts +261 -0
  175. package/src/__tests__/pairing-concurrent.test.ts +6 -6
  176. package/src/__tests__/pairing-routes.test.ts +7 -1
  177. package/src/__tests__/path-policy.test.ts +1 -1
  178. package/src/__tests__/platform.test.ts +64 -88
  179. package/src/__tests__/playbook-execution.test.ts +0 -21
  180. package/src/__tests__/playbook-tools.test.ts +0 -21
  181. package/src/__tests__/pricing.test.ts +100 -0
  182. package/src/__tests__/relay-server.test.ts +1 -25
  183. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -24
  184. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -24
  185. package/src/__tests__/runtime-events-sse.test.ts +0 -24
  186. package/src/__tests__/sandbox-diagnostics.test.ts +2 -1
  187. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
  188. package/src/__tests__/schedule-store.test.ts +0 -21
  189. package/src/__tests__/schedule-tools.test.ts +0 -21
  190. package/src/__tests__/scheduler-recurrence.test.ts +0 -21
  191. package/src/__tests__/scoped-approval-grants.test.ts +0 -21
  192. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -21
  193. package/src/__tests__/secret-allowlist.test.ts +1 -1
  194. package/src/__tests__/secret-ingress-channel.test.ts +0 -5
  195. package/src/__tests__/secret-ingress-cli.test.ts +0 -6
  196. package/src/__tests__/secret-ingress-http.test.ts +0 -5
  197. package/src/__tests__/secret-ingress.test.ts +0 -5
  198. package/src/__tests__/send-endpoint-busy.test.ts +0 -24
  199. package/src/__tests__/sequence-store.test.ts +0 -21
  200. package/src/__tests__/server-history-render.test.ts +0 -24
  201. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -4
  202. package/src/__tests__/skill-load-inline-command.test.ts +9 -0
  203. package/src/__tests__/skill-load-inline-includes.test.ts +9 -0
  204. package/src/__tests__/skill-load-tool.test.ts +11 -0
  205. package/src/__tests__/skills-uninstall.test.ts +10 -8
  206. package/src/__tests__/skills.test.ts +1 -1
  207. package/src/__tests__/slack-channel-config.test.ts +1 -1
  208. package/src/__tests__/slack-inbound-verification.test.ts +0 -22
  209. package/src/__tests__/starter-bundle.test.ts +4 -1
  210. package/src/__tests__/suggestion-routes.test.ts +2 -0
  211. package/src/__tests__/system-prompt.test.ts +1 -1
  212. package/src/__tests__/terminal-tools.test.ts +1 -1
  213. package/src/__tests__/test-preload.ts +31 -0
  214. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
  215. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  216. package/src/__tests__/tool-executor.test.ts +0 -20
  217. package/src/__tests__/tool-input-summary.test.ts +124 -0
  218. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -1
  219. package/src/__tests__/trust-store.test.ts +7 -1
  220. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -1
  221. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -1
  222. package/src/__tests__/trusted-contact-multichannel.test.ts +1 -1
  223. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  224. package/src/__tests__/turn-boundary-resolution.test.ts +1 -1
  225. package/src/__tests__/twilio-routes.test.ts +1 -1
  226. package/src/__tests__/update-bulletin.test.ts +1 -1
  227. package/src/__tests__/vbundle-pax-and-symlink.test.ts +1 -1
  228. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -0
  229. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
  230. package/src/__tests__/voice-session-bridge.test.ts +1 -1
  231. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
  232. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
  233. package/src/__tests__/workspace-migration-down-functions.test.ts +15 -3
  234. package/src/__tests__/workspace-migration-seed-device-id.test.ts +40 -4
  235. package/src/agent/loop.ts +6 -9
  236. package/src/approvals/guardian-decision-primitive.ts +46 -18
  237. package/src/approvals/guardian-request-resolvers.ts +19 -2
  238. package/src/calls/active-call-lease.ts +2 -2
  239. package/src/cli/AGENTS.md +1 -1
  240. package/src/cli/commands/doctor.ts +9 -9
  241. package/src/cli/commands/memory.ts +142 -0
  242. package/src/cli/commands/oauth/__tests__/connect.test.ts +13 -11
  243. package/src/cli/commands/oauth/__tests__/ping.test.ts +1 -1
  244. package/src/cli/commands/oauth/connect.ts +13 -12
  245. package/src/cli/commands/oauth/index.ts +1 -1
  246. package/src/cli/commands/oauth/providers.ts +47 -62
  247. package/src/cli/commands/platform/__tests__/connect.test.ts +72 -46
  248. package/src/cli/commands/platform/__tests__/disconnect.test.ts +54 -1
  249. package/src/cli/commands/platform/__tests__/status.test.ts +36 -0
  250. package/src/cli/commands/platform/connect.ts +17 -7
  251. package/src/cli/commands/platform/disconnect.ts +28 -3
  252. package/src/cli/commands/platform/index.ts +3 -3
  253. package/src/cli.ts +1 -299
  254. package/src/config/assistant-feature-flags.ts +23 -15
  255. package/src/config/bundled-skills/app-builder/TOOLS.json +16 -0
  256. package/src/config/bundled-skills/app-builder/tools/app-create.ts +4 -0
  257. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +5 -1
  258. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +9 -1
  259. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +5 -1
  260. package/src/config/bundled-skills/contacts/TOOLS.json +8 -0
  261. package/src/config/bundled-skills/contacts/tools/contact-search.ts +10 -1
  262. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +16 -2
  263. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +1 -0
  264. package/src/config/bundled-skills/messaging/SKILL.md +7 -7
  265. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +37 -0
  266. package/src/config/bundled-skills/slack/SKILL.md +18 -0
  267. package/src/config/env-registry.ts +15 -11
  268. package/src/config/env.ts +1 -11
  269. package/src/config/feature-flag-registry.json +16 -0
  270. package/src/config/schema.ts +4 -0
  271. package/src/config/schemas/heartbeat.ts +6 -1
  272. package/src/config/schemas/inference.ts +14 -3
  273. package/src/config/schemas/memory-processing.ts +16 -8
  274. package/src/config/schemas/memory-retrieval.ts +3 -3
  275. package/src/config/skills.ts +1 -1
  276. package/src/context/window-manager.ts +174 -51
  277. package/src/credential-execution/executable-discovery.ts +2 -2
  278. package/src/daemon/approved-devices-store.ts +2 -2
  279. package/src/daemon/assistant-attachments.ts +2 -0
  280. package/src/daemon/config-watcher.ts +4 -50
  281. package/src/daemon/conversation-agent-loop-handlers.ts +9 -1
  282. package/src/daemon/conversation-agent-loop.ts +12 -0
  283. package/src/daemon/conversation-error.ts +3 -5
  284. package/src/daemon/conversation-history.ts +7 -3
  285. package/src/daemon/conversation-lifecycle.ts +16 -0
  286. package/src/daemon/conversation-messaging.ts +1 -0
  287. package/src/daemon/conversation-notifiers.ts +67 -30
  288. package/src/daemon/conversation-process.ts +161 -2
  289. package/src/daemon/conversation-queue-manager.ts +2 -0
  290. package/src/daemon/conversation-runtime-assembly.ts +33 -11
  291. package/src/daemon/conversation-slash.ts +14 -3
  292. package/src/daemon/conversation-tool-setup.ts +2 -0
  293. package/src/daemon/conversation-usage.ts +32 -4
  294. package/src/daemon/conversation.ts +33 -1
  295. package/src/daemon/daemon-control.ts +32 -16
  296. package/src/daemon/date-context.ts +47 -45
  297. package/src/daemon/dictation-profile-store.ts +2 -2
  298. package/src/daemon/handlers/conversations.ts +19 -0
  299. package/src/daemon/handlers/shared.ts +14 -21
  300. package/src/daemon/lifecycle.ts +5 -7
  301. package/src/daemon/message-types/conversations.ts +2 -0
  302. package/src/daemon/message-types/guardian-actions.ts +3 -17
  303. package/src/daemon/message-types/integrations.ts +11 -1
  304. package/src/daemon/message-types/messages.ts +1 -0
  305. package/src/daemon/pairing-store.ts +2 -79
  306. package/src/daemon/server.ts +154 -8
  307. package/src/daemon/watch-handler.ts +65 -21
  308. package/src/email/guardrails.ts +3 -3
  309. package/src/heartbeat/heartbeat-service.ts +14 -7
  310. package/src/hooks/cli.ts +2 -2
  311. package/src/hooks/config.ts +2 -2
  312. package/src/hooks/discovery.ts +2 -2
  313. package/src/hooks/manager.ts +2 -2
  314. package/src/hooks/runner.ts +5 -2
  315. package/src/hooks/templates.ts +2 -2
  316. package/src/memory/admin.ts +181 -2
  317. package/src/memory/app-git-service.ts +61 -4
  318. package/src/memory/attachments-store.ts +2 -0
  319. package/src/memory/canonical-guardian-store.ts +16 -0
  320. package/src/memory/db-init.ts +8 -0
  321. package/src/memory/embedding-local.ts +5 -2
  322. package/src/memory/indexer.ts +44 -26
  323. package/src/memory/items-extractor.ts +34 -82
  324. package/src/memory/job-handlers/batch-extraction.ts +741 -0
  325. package/src/memory/job-handlers/journal-carry-forward.test.ts +383 -0
  326. package/src/memory/job-handlers/journal-carry-forward.ts +255 -0
  327. package/src/memory/jobs-store.ts +28 -0
  328. package/src/memory/jobs-worker.ts +56 -9
  329. package/src/memory/lifecycle-events-store.ts +4 -2
  330. package/src/memory/llm-request-log-store.ts +40 -2
  331. package/src/memory/llm-usage-store.ts +4 -3
  332. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +71 -0
  333. package/src/memory/migrations/200-usage-llm-call-count.ts +20 -0
  334. package/src/memory/migrations/index.ts +2 -0
  335. package/src/memory/query-expansion.ts +83 -0
  336. package/src/memory/retriever.test.ts +119 -0
  337. package/src/memory/retriever.ts +513 -105
  338. package/src/memory/schema/guardian.ts +4 -0
  339. package/src/memory/schema/infrastructure.ts +1 -0
  340. package/src/memory/search/formatting.test.ts +140 -0
  341. package/src/memory/search/formatting.ts +143 -198
  342. package/src/memory/search/mmr.ts +136 -0
  343. package/src/memory/search/staleness.ts +0 -15
  344. package/src/memory/search/tier-classifier.ts +10 -21
  345. package/src/memory/search/types.ts +17 -0
  346. package/src/messaging/providers/slack/adapter.ts +51 -5
  347. package/src/notifications/broadcaster.ts +13 -0
  348. package/src/notifications/copy-composer.ts +8 -0
  349. package/src/oauth/connect-orchestrator.ts +1 -1
  350. package/src/oauth/connection-resolver.ts +2 -2
  351. package/src/oauth/provider-serializer.ts +116 -0
  352. package/src/permissions/trust-store.ts +24 -7
  353. package/src/prompts/__tests__/build-cli-reference-section.test.ts +5 -0
  354. package/src/prompts/journal-context.ts +50 -35
  355. package/src/prompts/persona-resolver.ts +1 -1
  356. package/src/prompts/system-prompt.ts +27 -28
  357. package/src/prompts/templates/BOOTSTRAP.md +14 -1
  358. package/src/prompts/templates/HEARTBEAT.md +10 -0
  359. package/src/prompts/templates/NOW.md +19 -25
  360. package/src/prompts/templates/SOUL.md +13 -1
  361. package/src/prompts/templates/UPDATES.md +12 -0
  362. package/src/prompts/update-bulletin.ts +1 -1
  363. package/src/providers/anthropic/client.ts +89 -18
  364. package/src/providers/model-catalog.ts +22 -2
  365. package/src/providers/model-intents.ts +2 -2
  366. package/src/providers/openai/client.ts +40 -1
  367. package/src/providers/retry.ts +23 -4
  368. package/src/providers/types.ts +2 -0
  369. package/src/runtime/assistant-scope.ts +1 -1
  370. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -0
  371. package/src/runtime/auth/route-policy.ts +1 -0
  372. package/src/runtime/auth/token-service.ts +51 -29
  373. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -1
  374. package/src/runtime/guardian-decision-types.ts +16 -10
  375. package/src/runtime/http-server.ts +3 -14
  376. package/src/runtime/http-types.ts +1 -0
  377. package/src/runtime/migrations/vbundle-builder.ts +7 -4
  378. package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -4
  379. package/src/runtime/migrations/vbundle-importer.ts +1 -1
  380. package/src/runtime/routes/conversation-query-routes.ts +40 -8
  381. package/src/runtime/routes/conversation-routes.ts +125 -3
  382. package/src/runtime/routes/guardian-action-routes.ts +9 -3
  383. package/src/runtime/routes/identity-routes.ts +25 -4
  384. package/src/runtime/routes/llm-context-normalization.ts +1 -0
  385. package/src/runtime/routes/log-export-routes.ts +34 -12
  386. package/src/runtime/routes/migration-routes.ts +6 -10
  387. package/src/runtime/routes/oauth-apps.ts +2 -9
  388. package/src/runtime/routes/oauth-providers.ts +60 -0
  389. package/src/runtime/routes/pairing-routes.ts +0 -8
  390. package/src/runtime/routes/settings-routes.ts +0 -1
  391. package/src/runtime/routes/telemetry-routes.ts +16 -4
  392. package/src/security/encrypted-store.ts +2 -2
  393. package/src/security/secret-allowlist.ts +3 -3
  394. package/src/signals/emit-event.ts +42 -0
  395. package/src/signals/user-message.ts +37 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +83 -19
  397. package/src/telemetry/usage-telemetry-reporter.ts +23 -17
  398. package/src/tools/browser/runtime-check.ts +2 -2
  399. package/src/tools/credentials/vault.ts +2 -249
  400. package/src/tools/memory/definitions.ts +1 -1
  401. package/src/tools/memory/handlers.test.ts +50 -8
  402. package/src/tools/memory/handlers.ts +3 -1
  403. package/src/tools/side-effects.ts +1 -6
  404. package/src/tools/terminal/safe-env.ts +3 -2
  405. package/src/tools/terminal/shell.ts +11 -14
  406. package/src/tools/tool-approval-handler.ts +20 -1
  407. package/src/tools/tool-input-summary.ts +66 -0
  408. package/src/tools/types.ts +4 -0
  409. package/src/usage/types.ts +4 -0
  410. package/src/util/device-id.ts +10 -10
  411. package/src/util/platform.ts +71 -33
  412. package/src/util/pricing.ts +19 -6
  413. package/src/util/strip-comment-lines.ts +28 -0
  414. package/src/workspace/git-service.ts +8 -18
  415. package/src/workspace/migrations/003-seed-device-id.ts +6 -4
  416. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +7 -1
  417. package/src/workspace/migrations/017-seed-persona-dirs.ts +2 -4
  418. package/src/workspace/migrations/021-move-signals-to-workspace.ts +84 -0
  419. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +94 -0
  420. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +86 -0
  421. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +126 -0
  422. package/src/workspace/migrations/migrate-to-workspace-volume.ts +3 -6
  423. package/src/workspace/migrations/registry.ts +8 -0
  424. package/src/signals/confirm.ts +0 -82
  425. package/src/signals/trust-rule.ts +0 -174
@@ -2,7 +2,6 @@ import { execFile } from "node:child_process";
2
2
  import {
3
3
  existsSync,
4
4
  readFileSync,
5
- statSync,
6
5
  unlinkSync,
7
6
  writeFileSync,
8
7
  } from "node:fs";
@@ -258,30 +257,21 @@ export class WorkspaceGitService {
258
257
  );
259
258
  }
260
259
 
261
- /** Age threshold (ms) beyond which an index.lock is considered stale. */
262
- private static readonly LOCK_STALE_THRESHOLD_MS = 30_000;
263
-
264
260
  /**
265
- * Remove `.git/index.lock` only if it is stale — older than
266
- * {@link LOCK_STALE_THRESHOLD_MS}. A recently-created lock may belong to a
267
- * concurrent git process outside our mutex (e.g. a user-initiated CLI
268
- * command), so we leave it alone.
261
+ * Remove `.git/index.lock` if it exists.
262
+ *
263
+ * This method is always called inside the mutex, so no git operation from
264
+ * our code can be concurrently holding the lock. Any lock file present is
265
+ * stale — left behind by a crashed process or an external command that
266
+ * has already exited.
269
267
  */
270
268
  private cleanStaleLockFile(): void {
271
269
  const lockPath = join(this.workspaceDir, ".git", "index.lock");
272
270
  try {
273
- const stat = statSync(lockPath);
274
- const ageMs = Date.now() - stat.mtimeMs;
275
- if (ageMs < WorkspaceGitService.LOCK_STALE_THRESHOLD_MS) {
276
- log.debug(
277
- `index.lock exists but is only ${Math.round(ageMs / 1000)}s old — leaving it`,
278
- );
279
- return;
280
- }
281
271
  unlinkSync(lockPath);
282
- log.debug(`Removed stale index.lock (${Math.round(ageMs / 1000)}s old)`);
272
+ log.debug("Removed stale index.lock");
283
273
  } catch {
284
- // File doesn't exist or can't be stat'd/removed — move on.
274
+ // File doesn't exist or can't be removed — move on.
285
275
  }
286
276
  }
287
277
 
@@ -5,6 +5,7 @@ import {
5
5
  unlinkSync,
6
6
  writeFileSync,
7
7
  } from "node:fs";
8
+ import { homedir } from "node:os";
8
9
  import { join } from "node:path";
9
10
 
10
11
  import { getDeviceIdBaseDir } from "../../util/device-id.js";
@@ -37,11 +38,12 @@ export const seedDeviceIdMigration: WorkspaceMigration = {
37
38
  }
38
39
 
39
40
  // b. Read the lockfile to find an existing installationId.
40
- // Check both the current and legacy lockfile paths to support installs
41
- // that haven't migrated the filename yet.
41
+ // The lockfile is always under the user's home directory, never under
42
+ // BASE_DATA_DIR. Check both the current and legacy filenames.
43
+ const home = homedir();
42
44
  const lockCandidates = [
43
- join(base, ".vellum.lock.json"),
44
- join(base, ".vellum.lockfile.json"),
45
+ join(home, ".vellum.lock.json"),
46
+ join(home, ".vellum.lockfile.json"),
45
47
  ];
46
48
 
47
49
  let lockData: Record<string, unknown> | undefined;
@@ -7,11 +7,17 @@ import {
7
7
  unlinkSync,
8
8
  writeFileSync,
9
9
  } from "node:fs";
10
+ import { homedir } from "node:os";
10
11
  import { join } from "node:path";
11
12
 
12
- import { getRootDir } from "../../util/platform.js";
13
13
  import type { WorkspaceMigration } from "./types.js";
14
14
 
15
+ /** Inlined from platform.ts to satisfy migration self-containment rule (AGENTS.md). */
16
+ function getRootDir(): string {
17
+ const base = process.env.BASE_DATA_DIR?.trim() || homedir();
18
+ return join(base, ".vellum");
19
+ }
20
+
15
21
  export const extractFeatureFlagsToProtectedMigration: WorkspaceMigration = {
16
22
  id: "016-extract-feature-flags-to-protected",
17
23
  description:
@@ -13,10 +13,8 @@ import { desc, eq } from "drizzle-orm";
13
13
  import { generateUserFileSlug } from "../../contacts/contact-store.js";
14
14
  import { getDb } from "../../memory/db.js";
15
15
  import { contacts } from "../../memory/schema/contacts.js";
16
- import {
17
- isTemplateContent,
18
- stripCommentLines,
19
- } from "../../prompts/system-prompt.js";
16
+ import { isTemplateContent } from "../../prompts/system-prompt.js";
17
+ import { stripCommentLines } from "../../util/strip-comment-lines.js";
20
18
  import type { WorkspaceMigration } from "./types.js";
21
19
 
22
20
  export const seedPersonaDirsMigration: WorkspaceMigration = {
@@ -0,0 +1,84 @@
1
+ /**
2
+ * Workspace migration 021: Move signals directory from root to workspace.
3
+ *
4
+ * Previously, `~/.vellum/signals/` lived directly under getRootDir(). This
5
+ * migration moves any existing signal files into `~/.vellum/workspace/signals/`
6
+ * so that getSignalsDir() resolves correctly under the workspace.
7
+ *
8
+ * Signal files are ephemeral IPC artifacts (written, read once, then stale),
9
+ * so the migration simply ensures the workspace signals directory exists and
10
+ * copies over any files that may still be pending. The old root-level
11
+ * directory is left in place (but empty) to avoid breaking concurrent
12
+ * watchers during the transition.
13
+ */
14
+
15
+ import { existsSync, mkdirSync, readdirSync, renameSync } from "node:fs";
16
+ import { homedir } from "node:os";
17
+ import { join } from "node:path";
18
+
19
+ import type { WorkspaceMigration } from "./types.js";
20
+
21
+ /** Inlined from platform.ts to satisfy migration self-containment rule (AGENTS.md). */
22
+ function getRootDir(): string {
23
+ const base = process.env.BASE_DATA_DIR?.trim() || homedir();
24
+ return join(base, ".vellum");
25
+ }
26
+
27
+ export const moveSignalsToWorkspaceMigration: WorkspaceMigration = {
28
+ id: "021-move-signals-to-workspace",
29
+ description: "Move signals directory from root to workspace",
30
+
31
+ run(workspaceDir: string): void {
32
+ const oldSignalsDir = join(getRootDir(), "signals");
33
+ const newSignalsDir = join(workspaceDir, "signals");
34
+
35
+ mkdirSync(newSignalsDir, { recursive: true });
36
+
37
+ if (!existsSync(oldSignalsDir)) return;
38
+
39
+ // Move any pending signal files to the new location
40
+ try {
41
+ const entries = readdirSync(oldSignalsDir);
42
+ for (const entry of entries) {
43
+ const oldPath = join(oldSignalsDir, entry);
44
+ const newPath = join(newSignalsDir, entry);
45
+ if (!existsSync(newPath)) {
46
+ try {
47
+ renameSync(oldPath, newPath);
48
+ } catch {
49
+ // Best-effort: file may have been consumed between readdir and rename
50
+ }
51
+ }
52
+ }
53
+ } catch {
54
+ // Best-effort: old directory may not be readable
55
+ }
56
+ },
57
+
58
+ down(workspaceDir: string): void {
59
+ const oldSignalsDir = join(getRootDir(), "signals");
60
+ const newSignalsDir = join(workspaceDir, "signals");
61
+
62
+ mkdirSync(oldSignalsDir, { recursive: true });
63
+
64
+ if (!existsSync(newSignalsDir)) return;
65
+
66
+ // Move signal files back to the root-level directory
67
+ try {
68
+ const entries = readdirSync(newSignalsDir);
69
+ for (const entry of entries) {
70
+ const newPath = join(newSignalsDir, entry);
71
+ const oldPath = join(oldSignalsDir, entry);
72
+ if (!existsSync(oldPath)) {
73
+ try {
74
+ renameSync(newPath, oldPath);
75
+ } catch {
76
+ // Best-effort
77
+ }
78
+ }
79
+ }
80
+ } catch {
81
+ // Best-effort
82
+ }
83
+ },
84
+ };
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Workspace migration 022: Move hooks directory from root to workspace.
3
+ *
4
+ * Previously, `~/.vellum/hooks/` lived directly under getRootDir(). This
5
+ * migration moves existing hook directories and files into
6
+ * `~/.vellum/workspace/hooks/` so that getWorkspaceHooksDir() resolves
7
+ * correctly under the workspace.
8
+ *
9
+ * Hooks are persistent user-installed scripts (manifests, config, executables),
10
+ * so the migration recursively moves all entries from the old directory to the
11
+ * new one. The old root-level directory is left in place (but empty) to avoid
12
+ * breaking any external references during the transition.
13
+ */
14
+
15
+ import {
16
+ existsSync,
17
+ mkdirSync,
18
+ readdirSync,
19
+ renameSync,
20
+ rmSync,
21
+ } from "node:fs";
22
+ import { homedir } from "node:os";
23
+ import { join } from "node:path";
24
+
25
+ import type { WorkspaceMigration } from "./types.js";
26
+
27
+ /** Inlined from platform.ts to satisfy migration self-containment rule (AGENTS.md). */
28
+ function getRootDir(): string {
29
+ const base = process.env.BASE_DATA_DIR?.trim() || homedir();
30
+ return join(base, ".vellum");
31
+ }
32
+
33
+ export const moveHooksToWorkspaceMigration: WorkspaceMigration = {
34
+ id: "022-move-hooks-to-workspace",
35
+ description: "Move hooks directory from root to workspace",
36
+
37
+ run(workspaceDir: string): void {
38
+ const oldHooksDir = join(getRootDir(), "hooks");
39
+ const newHooksDir = join(workspaceDir, "hooks");
40
+
41
+ mkdirSync(newHooksDir, { recursive: true });
42
+
43
+ if (!existsSync(oldHooksDir)) return;
44
+
45
+ // Move hook entries from root to workspace. The old (user) entries take
46
+ // precedence over anything already at the destination (e.g. template
47
+ // files written by installTemplates(), which runs before migrations).
48
+ // We remove the destination first so renameSync succeeds atomically.
49
+ try {
50
+ const entries = readdirSync(oldHooksDir);
51
+ for (const entry of entries) {
52
+ const oldPath = join(oldHooksDir, entry);
53
+ const newPath = join(newHooksDir, entry);
54
+ try {
55
+ if (existsSync(newPath)) {
56
+ rmSync(newPath, { recursive: true, force: true });
57
+ }
58
+ renameSync(oldPath, newPath);
59
+ } catch {
60
+ // Best-effort: entry may have been modified concurrently
61
+ }
62
+ }
63
+ } catch {
64
+ // Best-effort: old directory may not be readable
65
+ }
66
+ },
67
+
68
+ down(workspaceDir: string): void {
69
+ const oldHooksDir = join(getRootDir(), "hooks");
70
+ const newHooksDir = join(workspaceDir, "hooks");
71
+
72
+ mkdirSync(oldHooksDir, { recursive: true });
73
+
74
+ if (!existsSync(newHooksDir)) return;
75
+
76
+ // Move hook entries back to the root-level directory
77
+ try {
78
+ const entries = readdirSync(newHooksDir);
79
+ for (const entry of entries) {
80
+ const newPath = join(newHooksDir, entry);
81
+ const oldPath = join(oldHooksDir, entry);
82
+ if (!existsSync(oldPath)) {
83
+ try {
84
+ renameSync(newPath, oldPath);
85
+ } catch {
86
+ // Best-effort
87
+ }
88
+ }
89
+ }
90
+ } catch {
91
+ // Best-effort
92
+ }
93
+ },
94
+ };
@@ -0,0 +1,86 @@
1
+ /**
2
+ * Workspace migration 023: Move config/state JSON files from root to workspace.
3
+ *
4
+ * Previously, dictation-profiles.json, email-guardrails.json, and
5
+ * active-call-leases.json lived directly under getRootDir() (~/.vellum/).
6
+ * This migration moves them into the workspace directory so they are
7
+ * included in diagnostic exports and follow the workspace convention.
8
+ */
9
+
10
+ import { existsSync, renameSync, unlinkSync } from "node:fs";
11
+ import { homedir } from "node:os";
12
+ import { join } from "node:path";
13
+
14
+ import type { WorkspaceMigration } from "./types.js";
15
+
16
+ /** Inlined from platform.ts to satisfy migration self-containment rule (AGENTS.md). */
17
+ function getRootDir(): string {
18
+ const base = process.env.BASE_DATA_DIR?.trim() || homedir();
19
+ return join(base, ".vellum");
20
+ }
21
+
22
+ /** Files to move from root → workspace. */
23
+ const CONFIG_FILES = [
24
+ "dictation-profiles.json",
25
+ "email-guardrails.json",
26
+ "active-call-leases.json",
27
+ ] as const;
28
+
29
+ export const moveConfigFilesToWorkspaceMigration: WorkspaceMigration = {
30
+ id: "023-move-config-files-to-workspace",
31
+ description:
32
+ "Move dictation-profiles, email-guardrails, and active-call-leases from root to workspace",
33
+
34
+ run(workspaceDir: string): void {
35
+ const rootDir = getRootDir();
36
+
37
+ for (const file of CONFIG_FILES) {
38
+ const oldPath = join(rootDir, file);
39
+ const newPath = join(workspaceDir, file);
40
+
41
+ if (!existsSync(oldPath)) continue;
42
+ // Don't overwrite if the destination already exists (e.g. partial
43
+ // previous run or user-created file).
44
+ if (existsSync(newPath)) {
45
+ // Clean up the old file since workspace already has one.
46
+ try {
47
+ unlinkSync(oldPath);
48
+ } catch {
49
+ // Best-effort cleanup
50
+ }
51
+ continue;
52
+ }
53
+
54
+ try {
55
+ renameSync(oldPath, newPath);
56
+ } catch {
57
+ // Best-effort: cross-device rename or permission issue
58
+ }
59
+ }
60
+ },
61
+
62
+ down(workspaceDir: string): void {
63
+ const rootDir = getRootDir();
64
+
65
+ for (const file of CONFIG_FILES) {
66
+ const newPath = join(workspaceDir, file);
67
+ const oldPath = join(rootDir, file);
68
+
69
+ if (!existsSync(newPath)) continue;
70
+ if (existsSync(oldPath)) {
71
+ try {
72
+ unlinkSync(newPath);
73
+ } catch {
74
+ // Best-effort cleanup
75
+ }
76
+ continue;
77
+ }
78
+
79
+ try {
80
+ renameSync(newPath, oldPath);
81
+ } catch {
82
+ // Best-effort
83
+ }
84
+ }
85
+ },
86
+ };
@@ -0,0 +1,126 @@
1
+ /**
2
+ * Workspace migration 024: Move remaining root-level runtime files/dirs to workspace.
3
+ *
4
+ * Previously, several runtime files and directories lived directly under
5
+ * ~/.vellum/ (the root dir). This migration moves them into the workspace
6
+ * directory so that the root dir can eventually be cleaned up.
7
+ *
8
+ * Files moved:
9
+ * - daemon-stderr.log -> workspace/logs/daemon-stderr.log
10
+ * - daemon-startup.lock -> workspace/daemon-startup.lock
11
+ * - embed-worker.pid -> workspace/embed-worker.pid
12
+ *
13
+ * NOT moved:
14
+ * - .env (stays at root because it contains secrets)
15
+ *
16
+ * Directories moved:
17
+ * - external/ -> workspace/external/
18
+ * - bin/ -> workspace/bin/
19
+ */
20
+
21
+ import {
22
+ existsSync,
23
+ mkdirSync,
24
+ readdirSync,
25
+ renameSync,
26
+ unlinkSync,
27
+ } from "node:fs";
28
+ import { homedir } from "node:os";
29
+ import { join } from "node:path";
30
+
31
+ import type { WorkspaceMigration } from "./types.js";
32
+
33
+ /** Inlined from platform.ts to satisfy migration self-containment rule (AGENTS.md). */
34
+ function getRootDir(): string {
35
+ const base = process.env.BASE_DATA_DIR?.trim() || homedir();
36
+ return join(base, ".vellum");
37
+ }
38
+
39
+ /** Individual files to move from root → workspace (with optional subdirectory). */
40
+ const FILE_MOVES: Array<{ name: string; subdir?: string }> = [
41
+ { name: "daemon-stderr.log", subdir: "logs" },
42
+ { name: "daemon-startup.lock" },
43
+ // .env stays at root — it contains secrets (API keys) and the entire
44
+ // workspace directory is included in diagnostic log exports.
45
+ { name: "embed-worker.pid" },
46
+ ];
47
+
48
+ /** Directories to move from root → workspace. */
49
+ const DIR_MOVES = ["external", "bin"] as const;
50
+
51
+ /**
52
+ * Move a single file from oldPath to newPath. If the destination already
53
+ * exists, remove the old file instead of overwriting.
54
+ */
55
+ function moveFile(oldPath: string, newPath: string): void {
56
+ if (!existsSync(oldPath)) return;
57
+ if (existsSync(newPath)) {
58
+ try {
59
+ unlinkSync(oldPath);
60
+ } catch {
61
+ // Best-effort cleanup
62
+ }
63
+ return;
64
+ }
65
+ try {
66
+ renameSync(oldPath, newPath);
67
+ } catch {
68
+ // Best-effort: cross-device rename or permission issue
69
+ }
70
+ }
71
+
72
+ /**
73
+ * Move all entries from one directory to another. If the destination already
74
+ * has an entry with the same name, the source entry is removed.
75
+ */
76
+ function moveDirContents(oldDir: string, newDir: string): void {
77
+ if (!existsSync(oldDir)) return;
78
+ mkdirSync(newDir, { recursive: true });
79
+
80
+ try {
81
+ const entries = readdirSync(oldDir);
82
+ for (const entry of entries) {
83
+ moveFile(join(oldDir, entry), join(newDir, entry));
84
+ }
85
+ } catch {
86
+ // Best-effort: old directory may not be readable
87
+ }
88
+ }
89
+
90
+ export const moveRuntimeFilesToWorkspaceMigration: WorkspaceMigration = {
91
+ id: "024-move-runtime-files-to-workspace",
92
+ description:
93
+ "Move daemon-stderr.log, daemon-startup.lock, embed-worker.pid, external/, and bin/ from root to workspace",
94
+
95
+ run(workspaceDir: string): void {
96
+ const rootDir = getRootDir();
97
+
98
+ // Move individual files
99
+ for (const { name, subdir } of FILE_MOVES) {
100
+ const oldPath = join(rootDir, name);
101
+ const destDir = subdir ? join(workspaceDir, subdir) : workspaceDir;
102
+ mkdirSync(destDir, { recursive: true });
103
+ moveFile(oldPath, join(destDir, name));
104
+ }
105
+
106
+ // Move directories
107
+ for (const dir of DIR_MOVES) {
108
+ moveDirContents(join(rootDir, dir), join(workspaceDir, dir));
109
+ }
110
+ },
111
+
112
+ down(workspaceDir: string): void {
113
+ const rootDir = getRootDir();
114
+
115
+ // Move individual files back
116
+ for (const { name, subdir } of FILE_MOVES) {
117
+ const srcDir = subdir ? join(workspaceDir, subdir) : workspaceDir;
118
+ moveFile(join(srcDir, name), join(rootDir, name));
119
+ }
120
+
121
+ // Move directories back
122
+ for (const dir of DIR_MOVES) {
123
+ moveDirContents(join(workspaceDir, dir), join(rootDir, dir));
124
+ }
125
+ },
126
+ };
@@ -23,10 +23,6 @@ import {
23
23
  } from "node:fs";
24
24
  import { join } from "node:path";
25
25
 
26
- import {
27
- getBaseDataDir,
28
- getWorkspaceDirOverride,
29
- } from "../../config/env-registry.js";
30
26
  import type { WorkspaceMigration } from "./types.js";
31
27
 
32
28
  const SENTINEL_FILENAME = ".workspace-volume-migrated";
@@ -53,7 +49,8 @@ export const migrateToWorkspaceVolumeMigration: WorkspaceMigration = {
53
49
  },
54
50
 
55
51
  run(workspaceDir: string): void {
56
- const workspaceDirOverride = getWorkspaceDirOverride();
52
+ const workspaceDirOverride =
53
+ process.env.VELLUM_WORKSPACE_DIR?.trim() || undefined;
57
54
 
58
55
  // Only relevant when VELLUM_WORKSPACE_DIR is explicitly set (Docker with separate volume)
59
56
  if (!workspaceDirOverride) return;
@@ -72,7 +69,7 @@ export const migrateToWorkspaceVolumeMigration: WorkspaceMigration = {
72
69
  }
73
70
 
74
71
  // Resolve the old workspace location: $BASE_DATA_DIR/.vellum/workspace
75
- const baseDataDir = getBaseDataDir();
72
+ const baseDataDir = process.env.BASE_DATA_DIR?.trim() || undefined;
76
73
  if (!baseDataDir) {
77
74
  // No BASE_DATA_DIR means there's no old location to migrate from
78
75
  writeSentinel(sentinelPath);
@@ -17,6 +17,10 @@ import { seedPersonaDirsMigration } from "./017-seed-persona-dirs.js";
17
17
  import { rekeyCompoundCredentialKeysMigration } from "./018-rekey-compound-credential-keys.js";
18
18
  import { scopeJournalToGuardianMigration } from "./019-scope-journal-to-guardian.js";
19
19
  import { renameOauthSkillDirsMigration } from "./020-rename-oauth-skill-dirs.js";
20
+ import { moveSignalsToWorkspaceMigration } from "./021-move-signals-to-workspace.js";
21
+ import { moveHooksToWorkspaceMigration } from "./022-move-hooks-to-workspace.js";
22
+ import { moveConfigFilesToWorkspaceMigration } from "./023-move-config-files-to-workspace.js";
23
+ import { moveRuntimeFilesToWorkspaceMigration } from "./024-move-runtime-files-to-workspace.js";
20
24
  import { migrateToWorkspaceVolumeMigration } from "./migrate-to-workspace-volume.js";
21
25
  import type { WorkspaceMigration } from "./types.js";
22
26
 
@@ -45,4 +49,8 @@ export const WORKSPACE_MIGRATIONS: WorkspaceMigration[] = [
45
49
  rekeyCompoundCredentialKeysMigration,
46
50
  scopeJournalToGuardianMigration,
47
51
  renameOauthSkillDirsMigration,
52
+ moveSignalsToWorkspaceMigration,
53
+ moveHooksToWorkspaceMigration,
54
+ moveConfigFilesToWorkspaceMigration,
55
+ moveRuntimeFilesToWorkspaceMigration,
48
56
  ];
@@ -1,82 +0,0 @@
1
- /**
2
- * Handle confirmation decisions delivered via signal files from the CLI.
3
- *
4
- * The built-in CLI writes JSON to `signals/confirm` instead of making an
5
- * HTTP POST to `/v1/confirm`. The daemon's ConfigWatcher detects the file
6
- * change and invokes {@link handleConfirmationSignal}, which reads the
7
- * payload and resolves the pending interaction in-process.
8
- */
9
-
10
- import { readFileSync } from "node:fs";
11
- import { join } from "node:path";
12
-
13
- import { getIsContainerized } from "../config/env-registry.js";
14
- import type { UserDecision } from "../permissions/types.js";
15
- import * as pendingInteractions from "../runtime/pending-interactions.js";
16
- import { getLogger } from "../util/logger.js";
17
- import { getSignalsDir } from "../util/platform.js";
18
-
19
- const log = getLogger("signal:confirm");
20
-
21
- const VALID_DECISIONS: ReadonlySet<string> = new Set<string>([
22
- "allow",
23
- "allow_10m",
24
- "allow_conversation",
25
- "always_allow",
26
- "always_allow_high_risk",
27
- "deny",
28
- "always_deny",
29
- "temporary_override",
30
- ]);
31
-
32
- function isUserDecision(value: string): value is UserDecision {
33
- return VALID_DECISIONS.has(value);
34
- }
35
-
36
- /**
37
- * Read the `signals/confirm` file and resolve the pending interaction.
38
- * Called by ConfigWatcher when the signal file is written or modified.
39
- */
40
- export function handleConfirmationSignal(): void {
41
- if (getIsContainerized()) return;
42
-
43
- try {
44
- const content = readFileSync(join(getSignalsDir(), "confirm"), "utf-8");
45
- const parsed = JSON.parse(content) as {
46
- requestId?: string;
47
- decision?: string;
48
- };
49
- const { requestId, decision } = parsed;
50
-
51
- if (!requestId || typeof requestId !== "string") {
52
- log.warn("Confirmation signal missing requestId");
53
- return;
54
- }
55
- if (!decision || !isUserDecision(decision)) {
56
- log.warn({ decision }, "Confirmation signal has invalid decision");
57
- return;
58
- }
59
-
60
- const interaction = pendingInteractions.resolve(requestId);
61
- if (!interaction) {
62
- log.warn({ requestId }, "No pending interaction for confirmation signal");
63
- return;
64
- }
65
-
66
- if (interaction.directResolve) {
67
- interaction.directResolve(decision);
68
- } else {
69
- interaction.conversation!.handleConfirmationResponse(
70
- requestId,
71
- decision,
72
- undefined,
73
- undefined,
74
- undefined,
75
- { source: "button" },
76
- );
77
- }
78
- log.info({ requestId, decision }, "Confirmation resolved via signal file");
79
- } catch (err) {
80
- log.error({ err }, "Failed to handle confirmation signal");
81
- }
82
- }