@vellumai/assistant 0.4.41 → 0.4.43

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 (843) hide show
  1. package/.env.example +1 -6
  2. package/.prettierignore +3 -0
  3. package/ARCHITECTURE.md +131 -393
  4. package/Dockerfile +0 -1
  5. package/README.md +73 -83
  6. package/bun.lock +8 -2
  7. package/docs/architecture/integrations.md +16 -21
  8. package/docs/architecture/memory.md +1 -1
  9. package/docs/architecture/scheduling.md +63 -63
  10. package/docs/architecture/security.md +3 -3
  11. package/docs/runbook-trusted-contacts.md +11 -12
  12. package/docs/trusted-contact-access.md +39 -39
  13. package/package.json +5 -8
  14. package/src/__tests__/access-request-decision.test.ts +4 -4
  15. package/src/__tests__/active-skill-tools.test.ts +49 -34
  16. package/src/__tests__/actor-token-service.test.ts +55 -85
  17. package/src/__tests__/amazon-cdp-integration.test.ts +14 -26
  18. package/src/__tests__/app-bundler.test.ts +14 -368
  19. package/src/__tests__/app-compiler.test.ts +0 -1
  20. package/src/__tests__/app-executors.test.ts +10 -1
  21. package/src/__tests__/approval-hardcoded-copy-guard.test.ts +1 -1
  22. package/src/__tests__/approval-primitive.test.ts +2 -4
  23. package/src/__tests__/approval-routes-http.test.ts +1 -1
  24. package/src/__tests__/asset-materialize-tool.test.ts +1 -4
  25. package/src/__tests__/asset-search-tool.test.ts +1 -4
  26. package/src/__tests__/assistant-attachments.test.ts +23 -0
  27. package/src/__tests__/assistant-feature-flags-integration.test.ts +4 -8
  28. package/src/__tests__/assistant-id-boundary-guard.test.ts +5 -5
  29. package/src/__tests__/attachments-store.test.ts +1 -4
  30. package/src/__tests__/avatar-e2e.test.ts +43 -23
  31. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  32. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +2 -9
  33. package/src/__tests__/call-controller.test.ts +4 -8
  34. package/src/__tests__/call-conversation-messages.test.ts +1 -1
  35. package/src/__tests__/call-domain.test.ts +250 -8
  36. package/src/__tests__/call-pointer-message-composer.test.ts +14 -14
  37. package/src/__tests__/call-pointer-messages.test.ts +7 -11
  38. package/src/__tests__/call-recovery.test.ts +47 -0
  39. package/src/__tests__/call-routes-http.test.ts +13 -0
  40. package/src/__tests__/call-start-guardian-guard.test.ts +1 -1
  41. package/src/__tests__/callback-handoff-copy.test.ts +5 -5
  42. package/src/__tests__/canonical-guardian-store.test.ts +3 -3
  43. package/src/__tests__/channel-approval-routes.test.ts +101 -134
  44. package/src/__tests__/channel-approval.test.ts +0 -201
  45. package/src/__tests__/channel-approvals.test.ts +2 -2
  46. package/src/__tests__/channel-delivery-store.test.ts +16 -24
  47. package/src/__tests__/channel-guardian.test.ts +641 -740
  48. package/src/__tests__/channel-invite-transport.test.ts +1 -2
  49. package/src/__tests__/channel-policy.test.ts +9 -12
  50. package/src/__tests__/channel-readiness-service.test.ts +156 -45
  51. package/src/__tests__/channel-reply-delivery.test.ts +3 -3
  52. package/src/__tests__/channel-retry-sweep.test.ts +7 -7
  53. package/src/__tests__/checker.test.ts +10 -7
  54. package/src/__tests__/chrome-cdp.test.ts +57 -17
  55. package/src/__tests__/cli-help-reference-sync.test.ts +26 -0
  56. package/src/__tests__/compaction.benchmark.test.ts +25 -5
  57. package/src/__tests__/computer-use-session-lifecycle.test.ts +1 -1
  58. package/src/__tests__/computer-use-session-working-dir.test.ts +2 -6
  59. package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
  60. package/src/__tests__/config-loader-backfill.test.ts +310 -0
  61. package/src/__tests__/config-watcher.test.ts +1 -5
  62. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +3 -5
  63. package/src/__tests__/connection-policy.test.ts +3 -62
  64. package/src/__tests__/contacts-tools.test.ts +0 -2
  65. package/src/__tests__/context-memory-e2e.test.ts +11 -7
  66. package/src/__tests__/context-overflow-policy.test.ts +2 -2
  67. package/src/__tests__/context-window-manager.test.ts +220 -61
  68. package/src/__tests__/conversation-attention-store.test.ts +178 -2
  69. package/src/__tests__/conversation-attention-telegram.test.ts +8 -11
  70. package/src/__tests__/conversation-pairing.test.ts +14 -14
  71. package/src/__tests__/conversation-routes-guardian-reply.test.ts +1 -1
  72. package/src/__tests__/conversation-store.test.ts +2 -2
  73. package/src/__tests__/conversation-unread-route.test.ts +155 -0
  74. package/src/__tests__/credential-metadata-store.test.ts +0 -2
  75. package/src/__tests__/credential-security-invariants.test.ts +9 -16
  76. package/src/__tests__/credentials-cli.test.ts +49 -5
  77. package/src/__tests__/daemon-assistant-events.test.ts +4 -22
  78. package/src/__tests__/db-migration-rollback.test.ts +2 -2
  79. package/src/__tests__/deterministic-verification-control-plane.test.ts +19 -19
  80. package/src/__tests__/dictation-mode-detection.test.ts +1 -1
  81. package/src/__tests__/dynamic-page-surface.test.ts +2 -2
  82. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -6
  83. package/src/__tests__/email-cli.test.ts +12 -12
  84. package/src/__tests__/email-service-config-fallback.test.ts +1 -1
  85. package/src/__tests__/emit-signal-routing-intent.test.ts +3 -18
  86. package/src/__tests__/event-bus.test.ts +0 -1
  87. package/src/__tests__/followup-tools.test.ts +0 -2
  88. package/src/__tests__/gateway-client-managed-outbound.test.ts +6 -6
  89. package/src/__tests__/gateway-only-enforcement.test.ts +13 -77
  90. package/src/__tests__/gateway-only-guard.test.ts +5 -0
  91. package/src/__tests__/guardian-action-conversation-turn.test.ts +3 -3
  92. package/src/__tests__/guardian-action-followup-executor.test.ts +29 -94
  93. package/src/__tests__/guardian-action-followup-store.test.ts +2 -12
  94. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +48 -194
  95. package/src/__tests__/guardian-action-late-reply.test.ts +12 -12
  96. package/src/__tests__/guardian-action-store.test.ts +2 -2
  97. package/src/__tests__/guardian-action-sweep.test.ts +5 -5
  98. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +1 -3
  99. package/src/__tests__/guardian-dispatch.test.ts +5 -46
  100. package/src/__tests__/guardian-grant-minting.test.ts +5 -44
  101. package/src/__tests__/guardian-outbound-http.test.ts +95 -114
  102. package/src/__tests__/guardian-question-mode.test.ts +1 -4
  103. package/src/__tests__/guardian-routing-invariants.test.ts +5 -13
  104. package/src/__tests__/guardian-routing-state.test.ts +3 -3
  105. package/src/__tests__/guardian-verification-voice-binding.test.ts +64 -7
  106. package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +2 -2
  107. package/src/__tests__/handle-user-message-secret-resume.test.ts +3 -5
  108. package/src/__tests__/handlers-user-message-approval-consumption.test.ts +16 -34
  109. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  110. package/src/__tests__/headless-browser-navigate.test.ts +1 -1
  111. package/src/__tests__/headless-browser-read-tools.test.ts +1 -1
  112. package/src/__tests__/headless-browser-snapshot.test.ts +1 -1
  113. package/src/__tests__/heartbeat-service.test.ts +1 -1
  114. package/src/__tests__/home-base-bootstrap.test.ts +0 -2
  115. package/src/__tests__/host-shell-tool.test.ts +3 -12
  116. package/src/__tests__/inbound-invite-redemption.test.ts +2 -2
  117. package/src/__tests__/ingress-url-consistency.test.ts +0 -64
  118. package/src/__tests__/integration-status.test.ts +8 -8
  119. package/src/__tests__/intent-routing.test.ts +9 -13
  120. package/src/__tests__/invite-redemption-service.test.ts +4 -4
  121. package/src/__tests__/invite-routes-http.test.ts +10 -10
  122. package/src/__tests__/llm-usage-store.test.ts +45 -9
  123. package/src/__tests__/local-gateway-health.test.ts +209 -0
  124. package/src/__tests__/managed-avatar-client.test.ts +23 -12
  125. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -2
  126. package/src/__tests__/managed-store.test.ts +29 -12
  127. package/src/__tests__/managed-twitter-guardrails.test.ts +353 -0
  128. package/src/__tests__/mcp-cli.test.ts +1 -1
  129. package/src/__tests__/mcp-health-check.test.ts +1 -1
  130. package/src/__tests__/media-generate-image.test.ts +1 -1
  131. package/src/__tests__/media-reuse-story.e2e.test.ts +1 -4
  132. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +9 -6
  133. package/src/__tests__/memory-regressions.test.ts +1 -166
  134. package/src/__tests__/messaging-send-tool.test.ts +8 -4
  135. package/src/__tests__/migration-export-http.test.ts +2 -2
  136. package/src/__tests__/migration-transport.test.ts +44 -0
  137. package/src/__tests__/non-member-access-request.test.ts +49 -36
  138. package/src/__tests__/notification-broadcaster.test.ts +15 -15
  139. package/src/__tests__/notification-decision-fallback.test.ts +2 -2
  140. package/src/__tests__/notification-decision-strategy.test.ts +4 -4
  141. package/src/__tests__/notification-deep-link.test.ts +3 -3
  142. package/src/__tests__/notification-guardian-path.test.ts +6 -44
  143. package/src/__tests__/notification-routing-intent.test.ts +11 -7
  144. package/src/__tests__/oauth-cli.test.ts +1 -1
  145. package/src/__tests__/onboarding-starter-tasks.test.ts +2 -6
  146. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  147. package/src/__tests__/platform.test.ts +168 -5
  148. package/src/__tests__/playbook-execution.test.ts +0 -2
  149. package/src/__tests__/playbook-tools.test.ts +0 -2
  150. package/src/__tests__/pricing.test.ts +125 -0
  151. package/src/__tests__/provider-error-scenarios.test.ts +9 -3
  152. package/src/__tests__/recording-handler.test.ts +46 -80
  153. package/src/__tests__/recording-state-machine.test.ts +112 -183
  154. package/src/__tests__/registry.test.ts +1 -1
  155. package/src/__tests__/relay-server.test.ts +69 -71
  156. package/src/__tests__/reminder-store.test.ts +3 -3
  157. package/src/__tests__/request-file-tool.test.ts +2 -2
  158. package/src/__tests__/ride-shotgun-handler.test.ts +2 -33
  159. package/src/__tests__/runtime-attachment-metadata.test.ts +3 -3
  160. package/src/__tests__/runtime-events-sse-parity.test.ts +1 -1
  161. package/src/__tests__/scaffold-managed-skill-tool.test.ts +4 -4
  162. package/src/__tests__/schedule-store.test.ts +13 -4
  163. package/src/__tests__/schedule-tools.test.ts +0 -2
  164. package/src/__tests__/scheduler-recurrence.test.ts +3 -4
  165. package/src/__tests__/scoped-approval-grants.test.ts +3 -5
  166. package/src/__tests__/scoped-grant-security-matrix.test.ts +6 -8
  167. package/src/__tests__/secret-prompt-log-hygiene.test.ts +1 -1
  168. package/src/__tests__/secret-response-routing.test.ts +1 -1
  169. package/src/__tests__/send-endpoint-busy.test.ts +1 -1
  170. package/src/__tests__/sequence-store.test.ts +0 -2
  171. package/src/__tests__/server-history-render.test.ts +2 -199
  172. package/src/__tests__/session-abort-tool-results.test.ts +9 -3
  173. package/src/__tests__/session-agent-loop.test.ts +107 -3
  174. package/src/__tests__/session-confirmation-signals.test.ts +10 -4
  175. package/src/__tests__/session-conflict-gate.test.ts +9 -3
  176. package/src/__tests__/session-init.benchmark.test.ts +22 -13
  177. package/src/__tests__/session-load-history-repair.test.ts +6 -3
  178. package/src/__tests__/session-pre-run-repair.test.ts +9 -3
  179. package/src/__tests__/session-profile-injection.test.ts +9 -3
  180. package/src/__tests__/session-provider-retry-repair.test.ts +10 -4
  181. package/src/__tests__/session-queue.test.ts +10 -4
  182. package/src/__tests__/session-runtime-assembly.test.ts +28 -18
  183. package/src/__tests__/session-skill-tools.test.ts +2 -3
  184. package/src/__tests__/session-slash-known.test.ts +11 -4
  185. package/src/__tests__/session-slash-queue.test.ts +11 -4
  186. package/src/__tests__/session-slash-unknown.test.ts +12 -4
  187. package/src/__tests__/session-surfaces-deselection.test.ts +2 -2
  188. package/src/__tests__/session-surfaces-task-progress.test.ts +3 -3
  189. package/src/__tests__/session-tool-setup-app-refresh.test.ts +1 -1
  190. package/src/__tests__/session-tool-setup-memory-scope.test.ts +1 -1
  191. package/src/__tests__/session-tool-setup-side-effect-flag.test.ts +1 -1
  192. package/src/__tests__/session-usage.test.ts +180 -0
  193. package/src/__tests__/session-workspace-cache-state.test.ts +8 -2
  194. package/src/__tests__/session-workspace-injection.test.ts +8 -2
  195. package/src/__tests__/session-workspace-tool-tracking.test.ts +8 -2
  196. package/src/__tests__/skill-feature-flags-integration.test.ts +5 -11
  197. package/src/__tests__/skill-feature-flags.test.ts +1 -0
  198. package/src/__tests__/skill-include-graph.test.ts +1 -0
  199. package/src/__tests__/skill-load-feature-flag.test.ts +3 -9
  200. package/src/__tests__/skill-load-tool.test.ts +90 -12
  201. package/src/__tests__/skill-projection-feature-flag.test.ts +14 -15
  202. package/src/__tests__/skills-uninstall.test.ts +131 -0
  203. package/src/__tests__/skills.test.ts +32 -16
  204. package/src/__tests__/slack-block-formatting.test.ts +1 -1
  205. package/src/__tests__/slack-channel-config.test.ts +71 -12
  206. package/src/__tests__/slack-inbound-verification.test.ts +7 -7
  207. package/src/__tests__/slack-share-routes.test.ts +1 -1
  208. package/src/__tests__/slack-skill.test.ts +2 -2
  209. package/src/__tests__/slash-commands-catalog.test.ts +1 -0
  210. package/src/__tests__/slash-commands-resolver.test.ts +1 -0
  211. package/src/__tests__/starter-task-flow.test.ts +1 -1
  212. package/src/__tests__/subagent-manager-notify.test.ts +1 -1
  213. package/src/__tests__/subagent-tools.test.ts +2 -2
  214. package/src/__tests__/system-prompt.test.ts +4 -8
  215. package/src/__tests__/task-compiler.test.ts +0 -2
  216. package/src/__tests__/task-management-tools.test.ts +0 -2
  217. package/src/__tests__/task-runner.test.ts +0 -2
  218. package/src/__tests__/task-scheduler.test.ts +2 -2
  219. package/src/__tests__/telegram-bot-username-resolution.test.ts +46 -44
  220. package/src/__tests__/terminal-tools.test.ts +1 -11
  221. package/src/__tests__/thread-seed-composer.test.ts +3 -1
  222. package/src/__tests__/tool-approval-handler.test.ts +5 -7
  223. package/src/__tests__/tool-executor.test.ts +2 -2
  224. package/src/__tests__/tool-grant-request-escalation.test.ts +3 -5
  225. package/src/__tests__/tool-notification-listener.test.ts +1 -1
  226. package/src/__tests__/tool-profiling-listener.test.ts +1 -1
  227. package/src/__tests__/tool-trace-listener.test.ts +1 -2
  228. package/src/__tests__/trace-emitter.test.ts +1 -1
  229. package/src/__tests__/trust-context-guards.test.ts +1 -1
  230. package/src/__tests__/trust-store.test.ts +44 -395
  231. package/src/__tests__/trusted-contact-approval-notifier.test.ts +6 -8
  232. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +5 -7
  233. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +6 -6
  234. package/src/__tests__/trusted-contact-multichannel.test.ts +54 -47
  235. package/src/__tests__/trusted-contact-verification.test.ts +12 -12
  236. package/src/__tests__/twilio-config.test.ts +11 -2
  237. package/src/__tests__/twilio-provider.test.ts +6 -4
  238. package/src/__tests__/twilio-routes.test.ts +408 -86
  239. package/src/__tests__/twitter-platform-proxy-client.test.ts +450 -0
  240. package/src/__tests__/update-bulletin-format.test.ts +1 -1
  241. package/src/__tests__/update-bulletin-state.test.ts +1 -1
  242. package/src/__tests__/update-bulletin.test.ts +4 -8
  243. package/src/__tests__/update-template-contract.test.ts +1 -1
  244. package/src/__tests__/usage-cache-backfill-migration.test.ts +406 -0
  245. package/src/__tests__/usage-routes.test.ts +23 -5
  246. package/src/__tests__/user-reference.test.ts +1 -1
  247. package/src/__tests__/{guardian-control-plane-policy.test.ts → verification-control-plane-policy.test.ts} +142 -170
  248. package/src/__tests__/{guardian-verification-intent-routing.test.ts → verification-session-intent-routing.test.ts} +16 -16
  249. package/src/__tests__/view-image-tool.test.ts +0 -2
  250. package/src/__tests__/voice-ingress-preflight.test.ts +36 -0
  251. package/src/__tests__/voice-invite-redemption.test.ts +18 -18
  252. package/src/__tests__/voice-scoped-grant-consumer.test.ts +7 -7
  253. package/src/__tests__/voice-session-bridge.test.ts +14 -16
  254. package/src/__tests__/workspace-policy.test.ts +1 -1
  255. package/src/approvals/AGENTS.md +4 -4
  256. package/src/approvals/approval-primitive.ts +2 -2
  257. package/src/approvals/guardian-decision-primitive.ts +1 -1
  258. package/src/approvals/guardian-request-resolvers.ts +3 -4
  259. package/src/bundler/app-bundler.ts +29 -217
  260. package/src/bundler/app-compiler.ts +131 -103
  261. package/src/bundler/compiler-tools.ts +248 -0
  262. package/src/calls/active-call-lease.ts +207 -0
  263. package/src/calls/call-constants.ts +0 -7
  264. package/src/calls/call-controller.ts +1 -1
  265. package/src/calls/call-conversation-messages.ts +6 -6
  266. package/src/calls/call-domain.ts +73 -38
  267. package/src/calls/call-pointer-message-composer.ts +6 -6
  268. package/src/calls/call-pointer-messages.ts +14 -13
  269. package/src/calls/call-recovery.ts +2 -0
  270. package/src/calls/call-store.ts +21 -28
  271. package/src/calls/guardian-action-sweep.ts +6 -8
  272. package/src/calls/guardian-dispatch.ts +2 -6
  273. package/src/calls/relay-access-wait.ts +4 -4
  274. package/src/calls/relay-server.ts +69 -80
  275. package/src/calls/relay-setup-router.ts +16 -21
  276. package/src/calls/relay-verification.ts +27 -28
  277. package/src/calls/twilio-config.ts +28 -3
  278. package/src/calls/twilio-provider.ts +5 -5
  279. package/src/calls/twilio-rest.ts +26 -27
  280. package/src/calls/twilio-routes.ts +67 -54
  281. package/src/calls/types.ts +8 -8
  282. package/src/calls/voice-ingress-preflight.ts +110 -0
  283. package/src/calls/voice-session-bridge.ts +7 -7
  284. package/src/channels/config.ts +1 -10
  285. package/src/{config/channel-permission-profiles.ts → channels/permission-profiles.ts} +1 -1
  286. package/src/channels/types.ts +2 -13
  287. package/src/cli/__tests__/notifications.test.ts +1 -1
  288. package/src/{amazon → cli/commands/amazon}/client.ts +99 -42
  289. package/src/cli/{amazon.ts → commands/amazon/index.ts} +12 -17
  290. package/src/{amazon → cli/commands/amazon}/request-extractor.ts +39 -3
  291. package/src/cli/commands/amazon/session.ts +116 -0
  292. package/src/cli/{audit.ts → commands/audit.ts} +2 -4
  293. package/src/cli/{autonomy.ts → commands/autonomy.ts} +1 -3
  294. package/src/cli/commands/browser-relay.ts +520 -0
  295. package/src/cli/commands/channel-verification-sessions.ts +442 -0
  296. package/src/cli/{completions.ts → commands/completions.ts} +1 -3
  297. package/src/cli/{config.ts → commands/config.ts} +3 -5
  298. package/src/cli/{contacts.ts → commands/contacts.ts} +263 -16
  299. package/src/cli/{credentials.ts → commands/credentials.ts} +9 -10
  300. package/src/cli/{default-action.ts → commands/default-action.ts} +3 -3
  301. package/src/cli/{dev.ts → commands/dev.ts} +4 -6
  302. package/src/cli/{doctor.ts → commands/doctor.ts} +36 -60
  303. package/src/cli/{email.ts → commands/email.ts} +2 -2
  304. package/src/cli/{keys.ts → commands/keys.ts} +6 -6
  305. package/src/cli/{map.ts → commands/map.ts} +85 -93
  306. package/src/cli/{mcp.ts → commands/mcp.ts} +5 -7
  307. package/src/cli/{memory.ts → commands/memory.ts} +6 -7
  308. package/src/cli/{notifications.ts → commands/notifications.ts} +8 -10
  309. package/src/cli/{oauth.ts → commands/oauth.ts} +2 -2
  310. package/src/cli/commands/platform.ts +176 -0
  311. package/src/cli/{sequence.ts → commands/sequence.ts} +3 -3
  312. package/src/cli/{sessions.ts → commands/sessions.ts} +32 -52
  313. package/src/cli/commands/skills.ts +498 -0
  314. package/src/cli/{trust.ts → commands/trust.ts} +2 -4
  315. package/src/{__tests__/twitter-cli-error-shaping.test.ts → cli/commands/twitter/__tests__/cli-error-shaping.test.ts} +43 -2
  316. package/src/cli/commands/twitter/__tests__/cli-read-routing.test.ts +483 -0
  317. package/src/{__tests__/twitter-cli-routing.test.ts → cli/commands/twitter/__tests__/cli-routing.test.ts} +130 -4
  318. package/src/{__tests__/twitter-oauth-client.test.ts → cli/commands/twitter/__tests__/oauth-client.test.ts} +2 -2
  319. package/src/{twitter → cli/commands/twitter}/client.ts +17 -7
  320. package/src/cli/{twitter.ts → commands/twitter/index.ts} +322 -273
  321. package/src/cli/commands/twitter/router.ts +396 -0
  322. package/src/cli/commands/twitter/session.ts +121 -0
  323. package/src/cli/db.ts +1 -0
  324. package/src/cli/http-client.ts +87 -0
  325. package/src/cli/logger.ts +6 -0
  326. package/src/cli/main-screen.tsx +4 -3
  327. package/src/cli/output.ts +19 -0
  328. package/src/cli/program.ts +29 -27
  329. package/src/cli/reference.ts +27 -37
  330. package/src/cli.ts +452 -240
  331. package/src/config/assistant-feature-flags.ts +3 -15
  332. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +3 -6
  333. package/src/config/bundled-skills/agentmail/SKILL.md +4 -4
  334. package/src/config/bundled-skills/amazon/SKILL.md +15 -5
  335. package/src/config/bundled-skills/api-mapping/SKILL.md +4 -4
  336. package/src/config/bundled-skills/app-builder/SKILL.md +21 -6
  337. package/src/config/bundled-skills/browser/SKILL.md +4 -5
  338. package/src/config/bundled-skills/chatgpt-import/SKILL.md +4 -4
  339. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +1 -1
  340. package/src/config/bundled-skills/claude-code/SKILL.md +4 -4
  341. package/src/config/bundled-skills/cli-discover/SKILL.md +4 -4
  342. package/src/config/bundled-skills/computer-use/SKILL.md +4 -4
  343. package/src/config/bundled-skills/contacts/SKILL.md +87 -229
  344. package/src/config/bundled-skills/deploy-fullstack-vercel/SKILL.md +4 -4
  345. package/src/config/bundled-skills/document/SKILL.md +4 -3
  346. package/src/config/bundled-skills/document-writer/SKILL.md +4 -4
  347. package/src/config/bundled-skills/doordash/SKILL.md +4 -11
  348. package/src/config/bundled-skills/doordash/__tests__/doordash-session.test.ts +8 -16
  349. package/src/config/bundled-skills/doordash/doordash-cli.ts +120 -86
  350. package/src/config/bundled-skills/doordash/lib/session.ts +1 -2
  351. package/src/config/bundled-skills/doordash/lib/shared/platform.ts +26 -9
  352. package/src/config/bundled-skills/elevenlabs-voice/SKILL.md +140 -0
  353. package/src/config/bundled-skills/email-setup/SKILL.md +4 -4
  354. package/src/config/bundled-skills/followups/SKILL.md +4 -3
  355. package/src/config/bundled-skills/frontend-design/SKILL.md +2 -0
  356. package/src/config/bundled-skills/google-calendar/SKILL.md +4 -4
  357. package/src/config/bundled-skills/google-oauth-setup/SKILL.md +4 -6
  358. package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +26 -41
  359. package/src/config/bundled-skills/image-studio/SKILL.md +4 -5
  360. package/src/config/bundled-skills/image-studio/tools/media-generate-image.ts +1 -1
  361. package/src/config/bundled-skills/influencer/SKILL.md +19 -19
  362. package/src/{influencer → config/bundled-skills/influencer/scripts}/client.ts +73 -56
  363. package/src/config/bundled-skills/influencer/scripts/influencer.ts +267 -0
  364. package/src/config/bundled-skills/knowledge-graph/SKILL.md +4 -2
  365. package/src/config/bundled-skills/macos-automation/SKILL.md +4 -5
  366. package/src/config/bundled-skills/mcp-setup/SKILL.md +4 -4
  367. package/src/config/bundled-skills/media-processing/SKILL.md +3 -2
  368. package/src/config/bundled-skills/messaging/SKILL.md +6 -33
  369. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -5
  370. package/src/config/bundled-skills/notifications/SKILL.md +4 -4
  371. package/src/config/bundled-skills/notion/SKILL.md +4 -4
  372. package/src/config/bundled-skills/notion-oauth-setup/SKILL.md +4 -5
  373. package/src/config/bundled-skills/oauth-setup/SKILL.md +4 -5
  374. package/src/config/bundled-skills/phone-calls/SKILL.md +24 -458
  375. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +83 -0
  376. package/src/config/bundled-skills/phone-calls/references/TRANSCRIPTS.md +57 -0
  377. package/src/config/bundled-skills/phone-calls/references/TROUBLESHOOTING.md +67 -0
  378. package/src/config/bundled-skills/playbooks/SKILL.md +4 -3
  379. package/src/config/bundled-skills/public-ingress/SKILL.md +65 -14
  380. package/src/config/bundled-skills/reminder/SKILL.md +4 -3
  381. package/src/config/bundled-skills/restaurant-reservation/SKILL.md +4 -6
  382. package/src/config/bundled-skills/schedule/SKILL.md +4 -3
  383. package/src/config/bundled-skills/screen-recording/SKILL.md +4 -3
  384. package/src/config/bundled-skills/self-upgrade/SKILL.md +4 -4
  385. package/src/config/bundled-skills/skills-catalog/SKILL.md +4 -4
  386. package/src/config/bundled-skills/slack/SKILL.md +4 -8
  387. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +1 -1
  388. package/src/config/bundled-skills/slack-app-setup/SKILL.md +66 -88
  389. package/src/config/bundled-skills/slack-digest-setup/SKILL.md +4 -5
  390. package/src/config/bundled-skills/slack-oauth-setup/SKILL.md +4 -5
  391. package/src/config/bundled-skills/start-the-day/SKILL.md +4 -4
  392. package/src/config/bundled-skills/subagent/SKILL.md +4 -3
  393. package/src/config/bundled-skills/tasks/SKILL.md +4 -3
  394. package/src/config/bundled-skills/telegram-setup/SKILL.md +63 -112
  395. package/src/config/bundled-skills/time-based-actions/SKILL.md +4 -3
  396. package/src/config/bundled-skills/transcribe/SKILL.md +4 -3
  397. package/src/config/bundled-skills/twilio-setup/SKILL.md +23 -50
  398. package/src/config/bundled-skills/twitter/SKILL.md +56 -14
  399. package/src/config/bundled-skills/typescript-eval/SKILL.md +4 -4
  400. package/src/config/bundled-skills/vercel-token-setup/SKILL.md +4 -5
  401. package/src/config/bundled-skills/voice-setup/SKILL.md +19 -45
  402. package/src/config/bundled-skills/watcher/SKILL.md +4 -3
  403. package/src/config/env-registry.ts +1 -10
  404. package/src/config/feature-flag-registry.json +0 -16
  405. package/src/config/loader.ts +78 -38
  406. package/src/config/schema.ts +143 -106
  407. package/src/config/schemas/channels.ts +80 -0
  408. package/src/config/schemas/heartbeat.ts +51 -0
  409. package/src/config/schemas/inference.ts +136 -0
  410. package/src/config/schemas/ingress.ts +81 -0
  411. package/src/config/schemas/logging.ts +21 -0
  412. package/src/config/schemas/memory-lifecycle.ts +67 -0
  413. package/src/config/schemas/memory-processing.ts +215 -0
  414. package/src/config/schemas/memory-retrieval.ts +222 -0
  415. package/src/config/schemas/memory-storage.ts +83 -0
  416. package/src/config/schemas/memory.ts +58 -0
  417. package/src/config/schemas/platform.ts +64 -0
  418. package/src/config/schemas/security.ts +54 -0
  419. package/src/config/schemas/swarm.ts +50 -0
  420. package/src/config/schemas/timeouts.ts +47 -0
  421. package/src/config/{agent-schema.ts → schemas/workspace-git.ts} +0 -97
  422. package/src/config/skill-state.ts +3 -13
  423. package/src/config/skills.ts +233 -75
  424. package/src/config/types.ts +1 -20
  425. package/src/contacts/contact-store.ts +12 -49
  426. package/src/contacts/contacts-write.ts +1 -5
  427. package/src/contacts/index.ts +0 -2
  428. package/src/contacts/types.ts +0 -8
  429. package/src/context/window-manager.ts +73 -14
  430. package/src/daemon/assistant-attachments.ts +9 -0
  431. package/src/daemon/computer-use-session.ts +3 -3
  432. package/src/daemon/connection-policy.ts +6 -21
  433. package/src/daemon/context-overflow-policy.ts +1 -1
  434. package/src/daemon/daemon-control.ts +46 -54
  435. package/src/daemon/doordash-steps.ts +1 -1
  436. package/src/daemon/handlers/config-channels.ts +407 -71
  437. package/src/daemon/handlers/config-ingress.ts +17 -85
  438. package/src/daemon/handlers/config-model.ts +145 -123
  439. package/src/daemon/handlers/config-slack-channel.ts +43 -29
  440. package/src/daemon/handlers/config-telegram.ts +32 -27
  441. package/src/daemon/handlers/config-voice.ts +1 -4
  442. package/src/daemon/handlers/dictation.ts +11 -16
  443. package/src/daemon/handlers/identity.ts +5 -6
  444. package/src/daemon/handlers/pairing.ts +5 -13
  445. package/src/daemon/handlers/recording.ts +97 -199
  446. package/src/daemon/handlers/session-history.ts +110 -96
  447. package/src/daemon/handlers/session-user-message.ts +29 -57
  448. package/src/daemon/handlers/sessions.ts +240 -137
  449. package/src/daemon/handlers/shared.ts +62 -95
  450. package/src/daemon/handlers/skills.ts +492 -543
  451. package/src/daemon/lifecycle.ts +168 -55
  452. package/src/daemon/main.ts +1 -0
  453. package/src/daemon/{ipc-contract.ts → message-protocol.ts} +49 -49
  454. package/src/daemon/{ipc-contract → message-types}/computer-use.ts +0 -3
  455. package/src/daemon/{ipc-contract → message-types}/diagnostics.ts +0 -16
  456. package/src/daemon/{ipc-contract → message-types}/integrations.ts +29 -13
  457. package/src/daemon/{ipc-contract → message-types}/memory.ts +8 -0
  458. package/src/daemon/{ipc-contract → message-types}/notifications.ts +15 -1
  459. package/src/daemon/{ipc-contract → message-types}/sessions.ts +1 -0
  460. package/src/daemon/{ipc-contract → message-types}/shared.ts +0 -8
  461. package/src/daemon/{ipc-contract → message-types}/workspace.ts +2 -2
  462. package/src/daemon/providers-setup.ts +0 -5
  463. package/src/daemon/recording-executor.ts +0 -7
  464. package/src/daemon/ride-shotgun-handler.ts +9 -13
  465. package/src/daemon/server.ts +136 -510
  466. package/src/daemon/session-agent-loop-handlers.ts +22 -7
  467. package/src/daemon/session-agent-loop.ts +86 -24
  468. package/src/daemon/session-attachments.ts +1 -1
  469. package/src/daemon/session-error.ts +1 -1
  470. package/src/daemon/session-history.ts +20 -15
  471. package/src/daemon/session-lifecycle.ts +9 -7
  472. package/src/daemon/session-memory.ts +15 -1
  473. package/src/daemon/session-messaging.ts +10 -6
  474. package/src/daemon/session-notifiers.ts +10 -8
  475. package/src/daemon/session-process.ts +34 -25
  476. package/src/daemon/session-queue-manager.ts +1 -1
  477. package/src/daemon/session-runtime-assembly.ts +6 -25
  478. package/src/daemon/session-surfaces.ts +2 -2
  479. package/src/daemon/session-tool-setup.ts +1 -1
  480. package/src/daemon/session-usage.ts +119 -18
  481. package/src/daemon/session.ts +13 -9
  482. package/src/daemon/tool-side-effects.ts +6 -5
  483. package/src/daemon/trace-emitter.ts +1 -1
  484. package/src/daemon/{guardian-verification-intent.ts → verification-session-intent.ts} +16 -16
  485. package/src/daemon/watch-handler.ts +2 -5
  486. package/src/email/service.ts +8 -8
  487. package/src/events/domain-events.ts +0 -1
  488. package/src/events/tool-notification-listener.ts +1 -1
  489. package/src/followups/followup-store.ts +1 -2
  490. package/src/followups/types.ts +0 -6
  491. package/src/heartbeat/heartbeat-service.ts +1 -1
  492. package/src/inbound/platform-callback-registration.ts +1 -1
  493. package/src/inbound/public-ingress-urls.ts +0 -8
  494. package/src/index.ts +12 -0
  495. package/src/mcp/client.ts +1 -1
  496. package/src/mcp/manager.ts +1 -1
  497. package/src/memory/app-store.ts +1 -42
  498. package/src/memory/{guardian-verification.ts → channel-verification-sessions.ts} +110 -93
  499. package/src/memory/conversation-attention-store.ts +154 -0
  500. package/src/memory/conversation-bootstrap.ts +1 -1
  501. package/src/memory/conversation-crud.ts +53 -1
  502. package/src/memory/conversation-display-order-migration.ts +2 -3
  503. package/src/memory/conversation-queries.ts +1 -29
  504. package/src/memory/conversation-title-service.ts +26 -21
  505. package/src/memory/db-connection.ts +1 -8
  506. package/src/memory/db-init.ts +20 -0
  507. package/src/memory/delivery-crud.ts +4 -34
  508. package/src/memory/external-conversation-store.ts +1 -1
  509. package/src/memory/format-recall.ts +47 -0
  510. package/src/memory/guardian-action-store.ts +4 -5
  511. package/src/memory/guardian-rate-limits.ts +0 -3
  512. package/src/memory/invite-store.ts +1 -1
  513. package/src/memory/job-handlers/backfill.ts +9 -2
  514. package/src/memory/job-handlers/extraction.ts +2 -7
  515. package/src/memory/job-handlers/summarization.ts +1 -1
  516. package/src/memory/llm-usage-store.ts +11 -0
  517. package/src/memory/migrations/114-notifications.ts +12 -40
  518. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +357 -0
  519. package/src/memory/migrations/141-rename-verification-table.ts +55 -0
  520. package/src/memory/migrations/142-rename-verification-session-id-column.ts +32 -0
  521. package/src/memory/migrations/143-rename-guardian-verification-values.ts +48 -0
  522. package/src/memory/migrations/144-rename-voice-to-phone.ts +147 -0
  523. package/src/memory/migrations/index.ts +5 -0
  524. package/src/memory/migrations/registry.ts +30 -0
  525. package/src/memory/qdrant-circuit-breaker.ts +5 -0
  526. package/src/memory/retriever.test.ts +707 -0
  527. package/src/memory/retriever.ts +120 -116
  528. package/src/memory/schema/calls.ts +3 -7
  529. package/src/memory/schema/guardian.ts +2 -2
  530. package/src/memory/search/lexical.ts +4 -1
  531. package/src/memory/search/query-expansion.test.ts +70 -0
  532. package/src/memory/search/query-expansion.ts +118 -0
  533. package/src/memory/search/types.ts +18 -17
  534. package/src/messaging/providers/telegram-bot/adapter.ts +1 -1
  535. package/src/messaging/providers/whatsapp/adapter.ts +1 -4
  536. package/src/messaging/registry.ts +0 -1
  537. package/src/notifications/README.md +13 -22
  538. package/src/notifications/adapters/macos.ts +1 -1
  539. package/src/notifications/conversation-pairing.ts +2 -2
  540. package/src/notifications/copy-composer.ts +2 -2
  541. package/src/notifications/decision-engine.ts +1 -10
  542. package/src/notifications/destination-resolver.ts +2 -3
  543. package/src/notifications/emit-signal.ts +2 -8
  544. package/src/notifications/guardian-question-mode.ts +5 -8
  545. package/src/notifications/signal.ts +1 -2
  546. package/src/notifications/types.ts +1 -1
  547. package/src/oauth/token-persistence.ts +25 -1
  548. package/src/permissions/checker.ts +4 -29
  549. package/src/permissions/defaults.ts +6 -6
  550. package/src/permissions/prompter.ts +1 -1
  551. package/src/permissions/secret-prompter.ts +1 -1
  552. package/src/permissions/shell-identity.ts +1 -1
  553. package/src/permissions/trust-store.ts +13 -76
  554. package/src/permissions/workspace-policy.ts +1 -1
  555. package/src/{config → prompts}/computer-use-prompt.ts +1 -1
  556. package/src/{config → prompts}/system-prompt.ts +40 -21
  557. package/src/runtime/AGENTS.md +6 -8
  558. package/src/runtime/access-request-helper.ts +36 -55
  559. package/src/runtime/actor-trust-resolver.ts +1 -24
  560. package/src/runtime/approval-message-composer.ts +6 -2
  561. package/src/runtime/assistant-event.ts +1 -1
  562. package/src/runtime/auth/__tests__/ipc-auth-context.test.ts +1 -1
  563. package/src/runtime/auth/__tests__/subject.test.ts +32 -0
  564. package/src/runtime/auth/route-policy.ts +140 -24
  565. package/src/runtime/auth/subject.ts +9 -0
  566. package/src/runtime/auth/token-service.ts +11 -0
  567. package/src/runtime/auth/types.ts +1 -1
  568. package/src/runtime/channel-approval-types.ts +1 -1
  569. package/src/runtime/channel-approvals.ts +1 -1
  570. package/src/runtime/channel-invite-transport.ts +0 -2
  571. package/src/runtime/channel-invite-transports/slack.ts +5 -19
  572. package/src/runtime/channel-invite-transports/telegram.ts +17 -34
  573. package/src/runtime/channel-invite-transports/voice.ts +1 -1
  574. package/src/runtime/channel-readiness-service.ts +24 -159
  575. package/src/runtime/channel-readiness-types.ts +5 -1
  576. package/src/runtime/channel-reply-delivery.ts +43 -3
  577. package/src/runtime/channel-retry-sweep.ts +14 -22
  578. package/src/runtime/{channel-guardian-service.ts → channel-verification-service.ts} +50 -53
  579. package/src/runtime/confirmation-request-guardian-bridge.ts +2 -3
  580. package/src/runtime/gateway-client.ts +12 -15
  581. package/src/runtime/guardian-action-followup-executor.ts +8 -73
  582. package/src/runtime/guardian-action-grant-minter.ts +45 -61
  583. package/src/runtime/guardian-action-message-composer.ts +4 -4
  584. package/src/runtime/guardian-reply-router.ts +3 -3
  585. package/src/runtime/http-server.ts +133 -24
  586. package/src/runtime/http-types.ts +34 -1
  587. package/src/runtime/invite-instruction-generator.ts +1 -3
  588. package/src/runtime/invite-redemption-service.ts +5 -5
  589. package/src/runtime/invite-service.ts +7 -7
  590. package/src/runtime/local-actor-identity.ts +28 -2
  591. package/src/runtime/local-gateway-health.ts +275 -0
  592. package/src/runtime/middleware/twilio-validation.ts +3 -3
  593. package/src/runtime/migrations/migration-transport.ts +18 -3
  594. package/src/runtime/migrations/rebind-secrets-screen.ts +2 -2
  595. package/src/runtime/nl-approval-parser.ts +2 -3
  596. package/src/runtime/routes/access-request-decision.ts +2 -2
  597. package/src/runtime/routes/app-management-routes.ts +921 -0
  598. package/src/runtime/routes/approval-routes.ts +76 -7
  599. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +38 -203
  600. package/src/runtime/routes/channel-delivery-routes.ts +5 -4
  601. package/src/runtime/routes/channel-route-shared.ts +1 -3
  602. package/src/runtime/routes/channel-routes.ts +1 -4
  603. package/src/runtime/routes/channel-verification-routes.ts +257 -0
  604. package/src/runtime/routes/computer-use-routes.ts +595 -0
  605. package/src/runtime/routes/contact-routes.ts +1 -317
  606. package/src/runtime/routes/conversation-attention-routes.ts +6 -5
  607. package/src/runtime/routes/conversation-routes.ts +11 -18
  608. package/src/runtime/routes/debug-routes.ts +1 -1
  609. package/src/runtime/routes/diagnostics-routes.ts +813 -0
  610. package/src/runtime/routes/documents-routes.ts +227 -0
  611. package/src/runtime/routes/guardian-approval-interception.ts +25 -48
  612. package/src/runtime/routes/guardian-bootstrap-routes.ts +3 -3
  613. package/src/runtime/routes/guardian-expiry-sweep.ts +2 -2
  614. package/src/runtime/routes/guardian-refresh-routes.ts +11 -6
  615. package/src/runtime/routes/inbound-conversation.ts +3 -10
  616. package/src/runtime/routes/inbound-message-handler.ts +7 -6
  617. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +22 -22
  618. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +44 -0
  619. package/src/runtime/routes/inbound-stages/background-dispatch.ts +140 -22
  620. package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +4 -4
  621. package/src/runtime/routes/inbound-stages/edit-intercept.ts +5 -5
  622. package/src/runtime/routes/inbound-stages/escalation-intercept.ts +3 -3
  623. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +4 -4
  624. package/src/runtime/routes/inbound-stages/verification-intercept.ts +13 -14
  625. package/src/runtime/routes/integrations/slack/channel.ts +72 -0
  626. package/src/runtime/routes/{slack-share-routes.ts → integrations/slack/share.ts} +9 -9
  627. package/src/runtime/routes/integrations/telegram.ts +111 -0
  628. package/src/runtime/routes/integrations/twilio.ts +451 -0
  629. package/src/runtime/routes/invite-routes.ts +2 -2
  630. package/src/runtime/routes/pairing-routes.ts +1 -1
  631. package/src/runtime/routes/recording-routes.ts +332 -0
  632. package/src/{daemon/handlers/config-scheduling.ts → runtime/routes/schedule-routes.ts} +91 -106
  633. package/src/runtime/routes/session-management-routes.ts +167 -0
  634. package/src/runtime/routes/session-query-routes.ts +204 -0
  635. package/src/runtime/routes/settings-routes.ts +977 -0
  636. package/src/runtime/routes/skills-routes.ts +266 -0
  637. package/src/runtime/routes/subagents-routes.ts +246 -0
  638. package/src/runtime/routes/surface-action-routes.ts +100 -10
  639. package/src/runtime/routes/surface-content-routes.ts +1 -1
  640. package/src/runtime/routes/work-items-routes.ts +809 -0
  641. package/src/runtime/routes/workspace-routes.test.ts +778 -0
  642. package/src/runtime/routes/workspace-routes.ts +410 -0
  643. package/src/runtime/routes/workspace-utils.ts +88 -0
  644. package/src/runtime/telegram-streaming-delivery.test.ts +597 -0
  645. package/src/runtime/telegram-streaming-delivery.ts +380 -0
  646. package/src/runtime/tool-grant-request-helper.ts +1 -2
  647. package/src/runtime/trust-context-resolver.ts +0 -1
  648. package/src/runtime/{guardian-outbound-actions.ts → verification-outbound-actions.ts} +23 -188
  649. package/src/runtime/verification-rate-limiter.ts +2 -2
  650. package/src/runtime/{guardian-verification-templates.ts → verification-templates.ts} +2 -28
  651. package/src/schedule/integration-status.ts +2 -2
  652. package/src/schedule/schedule-store.ts +7 -9
  653. package/src/sequence/engine.ts +1 -1
  654. package/src/skills/active-skill-tools.ts +0 -8
  655. package/src/skills/clawhub.ts +1 -10
  656. package/src/skills/managed-store.ts +14 -4
  657. package/src/skills/slash-commands.ts +1 -1
  658. package/src/subagent/manager.ts +1 -1
  659. package/src/subagent/types.ts +1 -1
  660. package/src/tasks/SPEC.md +10 -10
  661. package/src/tasks/task-scheduler.ts +1 -1
  662. package/src/telegram/bot-username.ts +13 -0
  663. package/src/tools/assets/materialize.ts +1 -1
  664. package/src/tools/assets/search.ts +1 -1
  665. package/src/tools/browser/browser-execution.ts +2 -2
  666. package/src/tools/browser/browser-manager.ts +88 -11
  667. package/src/tools/browser/browser-screencast.ts +1 -1
  668. package/src/tools/browser/headless-browser.ts +0 -17
  669. package/src/tools/browser/jit-auth.ts +1 -1
  670. package/src/tools/browser/recording-store.ts +19 -1
  671. package/src/tools/browser/runtime-check.ts +4 -2
  672. package/src/tools/calls/call-start.ts +3 -3
  673. package/src/tools/credentials/metadata-store.ts +0 -13
  674. package/src/tools/credentials/vault.ts +7 -31
  675. package/src/tools/followups/followup_create.ts +0 -8
  676. package/src/tools/mcp/mcp-tool-factory.ts +1 -1
  677. package/src/tools/memory/definitions.ts +32 -10
  678. package/src/tools/memory/handlers.test.ts +573 -0
  679. package/src/tools/memory/handlers.ts +222 -65
  680. package/src/tools/memory/register.ts +53 -24
  681. package/src/tools/network/script-proxy/session-manager.ts +1 -12
  682. package/src/tools/schedule/update.ts +0 -8
  683. package/src/tools/skills/load.ts +3 -3
  684. package/src/tools/subagent/read.ts +1 -1
  685. package/src/tools/system/voice-config.ts +2 -14
  686. package/src/tools/terminal/safe-env.ts +5 -18
  687. package/src/tools/tool-approval-handler.ts +4 -4
  688. package/src/tools/tool-manifest.ts +4 -2
  689. package/src/tools/types.ts +1 -1
  690. package/src/tools/{guardian-control-plane-policy.ts → verification-control-plane-policy.ts} +37 -39
  691. package/src/twitter/platform-proxy-client.ts +405 -0
  692. package/src/usage/types.ts +21 -0
  693. package/src/util/canonicalize-identity.ts +2 -6
  694. package/src/util/cookie-session.ts +35 -51
  695. package/src/util/platform.ts +93 -86
  696. package/src/util/pricing.ts +180 -43
  697. package/src/work-items/work-item-runner.ts +1 -1
  698. package/scripts/ipc/check-contract-inventory.ts +0 -107
  699. package/scripts/ipc/check-swift-decoder-drift.ts +0 -184
  700. package/scripts/ipc/generate-swift.ts +0 -528
  701. package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -3043
  702. package/src/__tests__/app-migration.test.ts +0 -148
  703. package/src/__tests__/config-loader-migration.test.ts +0 -85
  704. package/src/__tests__/daemon-lifecycle.test.ts +0 -715
  705. package/src/__tests__/daemon-server-session-init.test.ts +0 -864
  706. package/src/__tests__/guardian-actions-endpoint.test.ts +0 -1452
  707. package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +0 -228
  708. package/src/__tests__/handlers-cu-observation-blob.test.ts +0 -397
  709. package/src/__tests__/handlers-ipc-blob-probe.test.ts +0 -218
  710. package/src/__tests__/handlers-slack-config.test.ts +0 -140
  711. package/src/__tests__/handlers-telegram-config.test.ts +0 -1317
  712. package/src/__tests__/handlers-twitter-config.test.ts +0 -1145
  713. package/src/__tests__/ingress-reconcile.test.ts +0 -606
  714. package/src/__tests__/integrations-cli.test.ts +0 -232
  715. package/src/__tests__/ipc-blob-store.test.ts +0 -329
  716. package/src/__tests__/ipc-contract-inventory.test.ts +0 -69
  717. package/src/__tests__/ipc-contract.test.ts +0 -76
  718. package/src/__tests__/ipc-protocol.test.ts +0 -120
  719. package/src/__tests__/ipc-roundtrip.benchmark.test.ts +0 -250
  720. package/src/__tests__/ipc-snapshot.test.ts +0 -2197
  721. package/src/__tests__/ipc-validate.test.ts +0 -471
  722. package/src/__tests__/migration-cli-flows.test.ts +0 -186
  723. package/src/__tests__/migration-ordering.test.ts +0 -267
  724. package/src/__tests__/oauth-connect-handler.test.ts +0 -361
  725. package/src/__tests__/platform-move-helper.test.ts +0 -108
  726. package/src/__tests__/platform-socket-path.test.ts +0 -52
  727. package/src/__tests__/platform-workspace-migration.test.ts +0 -1051
  728. package/src/__tests__/recording-intent-handler.test.ts +0 -1155
  729. package/src/__tests__/script-proxy-profile-template-fallback.test.ts +0 -127
  730. package/src/__tests__/sms-messaging-provider.test.ts +0 -156
  731. package/src/__tests__/tool-permission-simulate-handler.test.ts +0 -367
  732. package/src/__tests__/twitter-auth-handler.test.ts +0 -561
  733. package/src/__tests__/work-item-output.test.ts +0 -150
  734. package/src/amazon/session.ts +0 -58
  735. package/src/cli/channels.ts +0 -51
  736. package/src/cli/influencer.ts +0 -319
  737. package/src/cli/integrations.ts +0 -372
  738. package/src/cli/ipc-client.ts +0 -88
  739. package/src/config/bundled-skills/configure-settings/SKILL.md +0 -86
  740. package/src/config/bundled-skills/doordash/lib/shared/ipc.ts +0 -32
  741. package/src/config/bundled-skills/sms-setup/SKILL.md +0 -210
  742. package/src/config/core-schema.ts +0 -434
  743. package/src/config/memory-schema.ts +0 -617
  744. package/src/daemon/auth-manager.ts +0 -106
  745. package/src/daemon/handlers/apps.ts +0 -758
  746. package/src/daemon/handlers/avatar.ts +0 -73
  747. package/src/daemon/handlers/browser.ts +0 -3
  748. package/src/daemon/handlers/computer-use.ts +0 -231
  749. package/src/daemon/handlers/config-dispatch.ts +0 -29
  750. package/src/daemon/handlers/config-heartbeat.ts +0 -299
  751. package/src/daemon/handlers/config-inbox.ts +0 -457
  752. package/src/daemon/handlers/config-integrations.ts +0 -409
  753. package/src/daemon/handlers/config-platform.ts +0 -77
  754. package/src/daemon/handlers/config-slack.ts +0 -41
  755. package/src/daemon/handlers/config-tools.ts +0 -226
  756. package/src/daemon/handlers/config-trust.ts +0 -135
  757. package/src/daemon/handlers/config.ts +0 -64
  758. package/src/daemon/handlers/contacts.ts +0 -193
  759. package/src/daemon/handlers/diagnostics.ts +0 -382
  760. package/src/daemon/handlers/documents.ts +0 -188
  761. package/src/daemon/handlers/guardian-actions.ts +0 -82
  762. package/src/daemon/handlers/home-base.ts +0 -82
  763. package/src/daemon/handlers/index.ts +0 -222
  764. package/src/daemon/handlers/misc.ts +0 -1139
  765. package/src/daemon/handlers/navigate-settings.ts +0 -29
  766. package/src/daemon/handlers/oauth-connect.ts +0 -202
  767. package/src/daemon/handlers/open-bundle-handler.ts +0 -88
  768. package/src/daemon/handlers/publish.ts +0 -176
  769. package/src/daemon/handlers/signing.ts +0 -56
  770. package/src/daemon/handlers/subagents.ts +0 -286
  771. package/src/daemon/handlers/twitter-auth.ts +0 -220
  772. package/src/daemon/handlers/work-items.ts +0 -796
  773. package/src/daemon/handlers/workspace-files.ts +0 -84
  774. package/src/daemon/handlers.ts +0 -16
  775. package/src/daemon/ipc-blob-store.ts +0 -246
  776. package/src/daemon/ipc-contract-inventory.json +0 -348
  777. package/src/daemon/ipc-contract-inventory.ts +0 -202
  778. package/src/daemon/ipc-handler.ts +0 -120
  779. package/src/daemon/ipc-protocol.ts +0 -85
  780. package/src/daemon/ipc-validate.ts +0 -254
  781. package/src/memory/app-migration.ts +0 -114
  782. package/src/memory/channel-delivery-store.ts +0 -40
  783. package/src/memory/channel-guardian-store.ts +0 -83
  784. package/src/memory/conversation-store.ts +0 -102
  785. package/src/memory/schema-migration.ts +0 -38
  786. package/src/messaging/providers/sms/adapter.ts +0 -232
  787. package/src/messaging/providers/sms/client.ts +0 -93
  788. package/src/messaging/providers/sms/types.ts +0 -7
  789. package/src/migrations/config-merge.ts +0 -62
  790. package/src/migrations/data-layout.ts +0 -89
  791. package/src/migrations/data-merge.ts +0 -44
  792. package/src/migrations/hooks-merge.ts +0 -118
  793. package/src/migrations/index.ts +0 -6
  794. package/src/migrations/log.ts +0 -28
  795. package/src/migrations/skills-merge.ts +0 -44
  796. package/src/migrations/workspace-layout.ts +0 -94
  797. package/src/notifications/adapters/sms.ts +0 -94
  798. package/src/runtime/channel-approval-parser.ts +0 -123
  799. package/src/runtime/channel-invite-transports/sms.ts +0 -53
  800. package/src/runtime/routes/approval-strategies/guardian-legacy-fallback-strategy.ts +0 -82
  801. package/src/runtime/routes/integration-routes.ts +0 -381
  802. package/src/runtime/routes/twilio-routes.ts +0 -1251
  803. package/src/twitter/router.ts +0 -131
  804. package/src/twitter/session.ts +0 -54
  805. package/src/watcher/providers/slack.ts +0 -282
  806. /package/src/{amazon → cli/commands/amazon}/cart.ts +0 -0
  807. /package/src/{amazon → cli/commands/amazon}/checkout.ts +0 -0
  808. /package/src/{amazon → cli/commands/amazon}/product-details.ts +0 -0
  809. /package/src/{amazon → cli/commands/amazon}/search.ts +0 -0
  810. /package/src/{twitter → cli/commands/twitter}/oauth-client.ts +0 -0
  811. /package/src/config/{calls-schema.ts → schemas/calls.ts} +0 -0
  812. /package/src/config/{elevenlabs-schema.ts → schemas/elevenlabs.ts} +0 -0
  813. /package/src/config/{mcp-schema.ts → schemas/mcp.ts} +0 -0
  814. /package/src/config/{notifications-schema.ts → schemas/notifications.ts} +0 -0
  815. /package/src/config/{sandbox-schema.ts → schemas/sandbox.ts} +0 -0
  816. /package/src/config/{skills-schema.ts → schemas/skills.ts} +0 -0
  817. /package/src/daemon/{ipc-contract → message-types}/apps.ts +0 -0
  818. /package/src/daemon/{ipc-contract → message-types}/browser.ts +0 -0
  819. /package/src/daemon/{ipc-contract → message-types}/contacts.ts +0 -0
  820. /package/src/daemon/{ipc-contract → message-types}/documents.ts +0 -0
  821. /package/src/daemon/{ipc-contract → message-types}/guardian-actions.ts +0 -0
  822. /package/src/daemon/{ipc-contract → message-types}/inbox.ts +0 -0
  823. /package/src/daemon/{ipc-contract → message-types}/messages.ts +0 -0
  824. /package/src/daemon/{ipc-contract → message-types}/pairing.ts +0 -0
  825. /package/src/daemon/{ipc-contract → message-types}/schedules.ts +0 -0
  826. /package/src/daemon/{ipc-contract → message-types}/settings.ts +0 -0
  827. /package/src/daemon/{ipc-contract → message-types}/skills.ts +0 -0
  828. /package/src/daemon/{ipc-contract → message-types}/subagents.ts +0 -0
  829. /package/src/daemon/{ipc-contract → message-types}/surfaces.ts +0 -0
  830. /package/src/daemon/{ipc-contract → message-types}/trust.ts +0 -0
  831. /package/src/daemon/{ipc-contract → message-types}/work-items.ts +0 -0
  832. /package/src/{cli/email-guardrails.ts → email/guardrails.ts} +0 -0
  833. /package/src/{config → prompts}/__tests__/build-cli-reference-section.test.ts +0 -0
  834. /package/src/{config → prompts}/templates/BOOTSTRAP.md +0 -0
  835. /package/src/{config → prompts}/templates/IDENTITY.md +0 -0
  836. /package/src/{config → prompts}/templates/SOUL.md +0 -0
  837. /package/src/{config → prompts}/templates/UPDATES.md +0 -0
  838. /package/src/{config → prompts}/templates/USER.md +0 -0
  839. /package/src/{config → prompts}/update-bulletin-format.ts +0 -0
  840. /package/src/{config → prompts}/update-bulletin-state.ts +0 -0
  841. /package/src/{config → prompts}/update-bulletin-template-path.ts +0 -0
  842. /package/src/{config → prompts}/update-bulletin.ts +0 -0
  843. /package/src/{config → prompts}/user-reference.ts +0 -0
@@ -1,1051 +0,0 @@
1
- import { randomBytes } from "node:crypto";
2
- import {
3
- existsSync,
4
- mkdirSync,
5
- readFileSync,
6
- rmSync,
7
- writeFileSync,
8
- } from "node:fs";
9
- import { tmpdir } from "node:os";
10
- import { join } from "node:path";
11
- import { afterEach, describe, expect, test } from "bun:test";
12
-
13
- import { migrateToWorkspaceLayout } from "../util/platform.js";
14
-
15
- const originalBaseDataDir = process.env.BASE_DATA_DIR;
16
-
17
- function makeTmpBase(): string {
18
- const base = join(
19
- tmpdir(),
20
- `ws-migration-test-${randomBytes(4).toString("hex")}`,
21
- );
22
- mkdirSync(base, { recursive: true });
23
- return base;
24
- }
25
-
26
- afterEach(() => {
27
- if (originalBaseDataDir == null) {
28
- delete process.env.BASE_DATA_DIR;
29
- } else {
30
- process.env.BASE_DATA_DIR = originalBaseDataDir;
31
- }
32
- });
33
-
34
- /**
35
- * Populate a fake ~/.vellum directory with all legacy items that the
36
- * migration is expected to relocate.
37
- */
38
- function populateLegacyLayout(root: string): void {
39
- mkdirSync(root, { recursive: true });
40
-
41
- // data dir with sandbox/fs content
42
- const dataDir = join(root, "data");
43
- mkdirSync(join(dataDir, "sandbox", "fs", "project"), { recursive: true });
44
- writeFileSync(join(dataDir, "sandbox", "fs", "hello.txt"), "sandbox-file");
45
- writeFileSync(
46
- join(dataDir, "sandbox", "fs", "project", "main.ts"),
47
- "project-code",
48
- );
49
- mkdirSync(join(dataDir, "db"), { recursive: true });
50
- writeFileSync(join(dataDir, "db", "assistant.db"), "db-content");
51
- mkdirSync(join(dataDir, "logs"), { recursive: true });
52
- writeFileSync(join(dataDir, "logs", "vellum.log"), "log-content");
53
-
54
- // config.json
55
- writeFileSync(join(root, "config.json"), '{"theme":"dark"}');
56
-
57
- // hooks
58
- mkdirSync(join(root, "hooks"), { recursive: true });
59
- writeFileSync(join(root, "hooks", "on-start.sh"), "#!/bin/bash");
60
-
61
- // prompt files
62
- writeFileSync(join(root, "IDENTITY.md"), "# Identity");
63
- writeFileSync(join(root, "SOUL.md"), "# Soul");
64
- writeFileSync(join(root, "USER.md"), "# User");
65
-
66
- // skills
67
- mkdirSync(join(root, "skills"), { recursive: true });
68
- writeFileSync(join(root, "skills", "search.json"), "{}");
69
-
70
- // runtime files that should NOT move
71
- writeFileSync(join(root, "vellum.sock"), "socket-placeholder");
72
- writeFileSync(join(root, "vellum.pid"), "12345");
73
- }
74
-
75
- describe("migrateToWorkspaceLayout", () => {
76
- test("full legacy migration moves all items into workspace/", () => {
77
- const base = makeTmpBase();
78
- process.env.BASE_DATA_DIR = base;
79
- const root = join(base, ".vellum");
80
- const ws = join(root, "workspace");
81
-
82
- populateLegacyLayout(root);
83
-
84
- migrateToWorkspaceLayout();
85
-
86
- // (a) sandbox/fs content was extracted to become workspace root
87
- expect(existsSync(ws)).toBe(true);
88
- expect(readFileSync(join(ws, "hello.txt"), "utf-8")).toBe("sandbox-file");
89
- expect(readFileSync(join(ws, "project", "main.ts"), "utf-8")).toBe(
90
- "project-code",
91
- );
92
- // Original sandbox/fs should be gone (renamed)
93
- expect(existsSync(join(root, "data", "sandbox", "fs"))).toBe(false);
94
-
95
- // (b) config.json moved
96
- expect(existsSync(join(root, "config.json"))).toBe(false);
97
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(
98
- '{"theme":"dark"}',
99
- );
100
-
101
- // (c) data dir moved
102
- expect(existsSync(join(root, "data"))).toBe(false);
103
- expect(readFileSync(join(ws, "data", "db", "assistant.db"), "utf-8")).toBe(
104
- "db-content",
105
- );
106
- expect(readFileSync(join(ws, "data", "logs", "vellum.log"), "utf-8")).toBe(
107
- "log-content",
108
- );
109
-
110
- // (d) hooks moved
111
- expect(existsSync(join(root, "hooks"))).toBe(false);
112
- expect(readFileSync(join(ws, "hooks", "on-start.sh"), "utf-8")).toBe(
113
- "#!/bin/bash",
114
- );
115
-
116
- // (e) IDENTITY.md moved
117
- expect(existsSync(join(root, "IDENTITY.md"))).toBe(false);
118
- expect(readFileSync(join(ws, "IDENTITY.md"), "utf-8")).toBe("# Identity");
119
-
120
- // (f) skills moved
121
- expect(existsSync(join(root, "skills"))).toBe(false);
122
- expect(readFileSync(join(ws, "skills", "search.json"), "utf-8")).toBe("{}");
123
-
124
- // (g) SOUL.md moved
125
- expect(existsSync(join(root, "SOUL.md"))).toBe(false);
126
- expect(readFileSync(join(ws, "SOUL.md"), "utf-8")).toBe("# Soul");
127
-
128
- // (h) USER.md moved
129
- expect(existsSync(join(root, "USER.md"))).toBe(false);
130
- expect(readFileSync(join(ws, "USER.md"), "utf-8")).toBe("# User");
131
-
132
- rmSync(base, { recursive: true, force: true });
133
- });
134
-
135
- test("idempotent: second run is a no-op", () => {
136
- const base = makeTmpBase();
137
- process.env.BASE_DATA_DIR = base;
138
- const root = join(base, ".vellum");
139
- const ws = join(root, "workspace");
140
-
141
- populateLegacyLayout(root);
142
-
143
- // First run
144
- migrateToWorkspaceLayout();
145
-
146
- // Snapshot workspace state after first run
147
- const configAfterFirst = readFileSync(join(ws, "config.json"), "utf-8");
148
- const identityAfterFirst = readFileSync(join(ws, "IDENTITY.md"), "utf-8");
149
-
150
- // Second run — should not throw and should not change anything
151
- migrateToWorkspaceLayout();
152
-
153
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(
154
- configAfterFirst,
155
- );
156
- expect(readFileSync(join(ws, "IDENTITY.md"), "utf-8")).toBe(
157
- identityAfterFirst,
158
- );
159
- expect(existsSync(join(ws, "data", "db", "assistant.db"))).toBe(true);
160
- expect(existsSync(join(ws, "hooks", "on-start.sh"))).toBe(true);
161
- expect(existsSync(join(ws, "skills", "search.json"))).toBe(true);
162
- expect(readFileSync(join(ws, "SOUL.md"), "utf-8")).toBe("# Soul");
163
- expect(readFileSync(join(ws, "USER.md"), "utf-8")).toBe("# User");
164
-
165
- rmSync(base, { recursive: true, force: true });
166
- });
167
-
168
- test("destination conflict leaves source intact", () => {
169
- const base = makeTmpBase();
170
- process.env.BASE_DATA_DIR = base;
171
- const root = join(base, ".vellum");
172
- const ws = join(root, "workspace");
173
-
174
- // Create workspace dir with conflicting content already in place
175
- mkdirSync(ws, { recursive: true });
176
- writeFileSync(join(ws, "config.json"), "existing-config");
177
- writeFileSync(join(ws, "IDENTITY.md"), "existing-identity");
178
-
179
- // Create legacy items that should NOT overwrite existing workspace items
180
- mkdirSync(root, { recursive: true });
181
- writeFileSync(join(root, "config.json"), "legacy-config");
182
- writeFileSync(join(root, "IDENTITY.md"), "legacy-identity");
183
-
184
- migrateToWorkspaceLayout();
185
-
186
- // Workspace content should be unchanged (not overwritten)
187
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(
188
- "existing-config",
189
- );
190
- expect(readFileSync(join(ws, "IDENTITY.md"), "utf-8")).toBe(
191
- "existing-identity",
192
- );
193
-
194
- // Source files should still exist (not moved because destination existed)
195
- expect(existsSync(join(root, "config.json"))).toBe(true);
196
- expect(readFileSync(join(root, "config.json"), "utf-8")).toBe(
197
- "legacy-config",
198
- );
199
- expect(existsSync(join(root, "IDENTITY.md"))).toBe(true);
200
- expect(readFileSync(join(root, "IDENTITY.md"), "utf-8")).toBe(
201
- "legacy-identity",
202
- );
203
-
204
- rmSync(base, { recursive: true, force: true });
205
- });
206
-
207
- test("root runtime files (vellum.sock, vellum.pid) are unaffected", () => {
208
- const base = makeTmpBase();
209
- process.env.BASE_DATA_DIR = base;
210
- const root = join(base, ".vellum");
211
-
212
- populateLegacyLayout(root);
213
-
214
- migrateToWorkspaceLayout();
215
-
216
- // Runtime files should remain at root level
217
- expect(existsSync(join(root, "vellum.sock"))).toBe(true);
218
- expect(readFileSync(join(root, "vellum.sock"), "utf-8")).toBe(
219
- "socket-placeholder",
220
- );
221
- expect(existsSync(join(root, "vellum.pid"))).toBe(true);
222
- expect(readFileSync(join(root, "vellum.pid"), "utf-8")).toBe("12345");
223
-
224
- rmSync(base, { recursive: true, force: true });
225
- });
226
-
227
- test("partially migrated tree: completes remaining items without touching already-migrated ones", () => {
228
- const base = makeTmpBase();
229
- process.env.BASE_DATA_DIR = base;
230
- const root = join(base, ".vellum");
231
- const ws = join(root, "workspace");
232
-
233
- // Simulate a partial migration: workspace already exists with some items,
234
- // but other legacy items are still at root level.
235
- mkdirSync(ws, { recursive: true });
236
-
237
- // Already migrated: config.json and IDENTITY.md are in workspace
238
- writeFileSync(join(ws, "config.json"), "already-migrated-config");
239
- writeFileSync(join(ws, "IDENTITY.md"), "already-migrated-identity");
240
-
241
- // Not yet migrated: hooks, skills, SOUL.md, USER.md still at root
242
- mkdirSync(join(root, "hooks"), { recursive: true });
243
- writeFileSync(join(root, "hooks", "on-start.sh"), "legacy-hook");
244
- mkdirSync(join(root, "skills"), { recursive: true });
245
- writeFileSync(join(root, "skills", "search.json"), "legacy-skill");
246
- writeFileSync(join(root, "SOUL.md"), "legacy-soul");
247
- writeFileSync(join(root, "USER.md"), "legacy-user");
248
-
249
- // Also leave a data dir at root (not yet migrated)
250
- mkdirSync(join(root, "data", "db"), { recursive: true });
251
- writeFileSync(join(root, "data", "db", "assistant.db"), "legacy-db");
252
-
253
- migrateToWorkspaceLayout();
254
-
255
- // Already-migrated items should be untouched
256
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(
257
- "already-migrated-config",
258
- );
259
- expect(readFileSync(join(ws, "IDENTITY.md"), "utf-8")).toBe(
260
- "already-migrated-identity",
261
- );
262
-
263
- // Remaining items should now be migrated into workspace
264
- expect(existsSync(join(root, "hooks"))).toBe(false);
265
- expect(readFileSync(join(ws, "hooks", "on-start.sh"), "utf-8")).toBe(
266
- "legacy-hook",
267
- );
268
- expect(existsSync(join(root, "skills"))).toBe(false);
269
- expect(readFileSync(join(ws, "skills", "search.json"), "utf-8")).toBe(
270
- "legacy-skill",
271
- );
272
- expect(existsSync(join(root, "SOUL.md"))).toBe(false);
273
- expect(readFileSync(join(ws, "SOUL.md"), "utf-8")).toBe("legacy-soul");
274
- expect(existsSync(join(root, "USER.md"))).toBe(false);
275
- expect(readFileSync(join(ws, "USER.md"), "utf-8")).toBe("legacy-user");
276
- expect(existsSync(join(root, "data"))).toBe(false);
277
- expect(readFileSync(join(ws, "data", "db", "assistant.db"), "utf-8")).toBe(
278
- "legacy-db",
279
- );
280
-
281
- rmSync(base, { recursive: true, force: true });
282
- });
283
-
284
- test("destination directory conflicts: existing workspace dirs are not overwritten", () => {
285
- const base = makeTmpBase();
286
- process.env.BASE_DATA_DIR = base;
287
- const root = join(base, ".vellum");
288
- const ws = join(root, "workspace");
289
-
290
- // Pre-existing workspace directories with content
291
- mkdirSync(join(ws, "hooks"), { recursive: true });
292
- writeFileSync(join(ws, "hooks", "existing-hook.sh"), "ws-hook");
293
- mkdirSync(join(ws, "skills"), { recursive: true });
294
- writeFileSync(join(ws, "skills", "existing-skill.json"), "ws-skill");
295
- mkdirSync(join(ws, "data", "db"), { recursive: true });
296
- writeFileSync(join(ws, "data", "db", "assistant.db"), "ws-db");
297
-
298
- // Legacy items at root that would conflict with workspace dirs
299
- mkdirSync(join(root, "hooks"), { recursive: true });
300
- writeFileSync(join(root, "hooks", "legacy-hook.sh"), "root-hook");
301
- mkdirSync(join(root, "skills"), { recursive: true });
302
- writeFileSync(join(root, "skills", "legacy-skill.json"), "root-skill");
303
- mkdirSync(join(root, "data", "logs"), { recursive: true });
304
- writeFileSync(join(root, "data", "logs", "vellum.log"), "root-log");
305
-
306
- migrateToWorkspaceLayout();
307
-
308
- // Workspace directories should retain their original content
309
- expect(readFileSync(join(ws, "hooks", "existing-hook.sh"), "utf-8")).toBe(
310
- "ws-hook",
311
- );
312
- expect(
313
- readFileSync(join(ws, "skills", "existing-skill.json"), "utf-8"),
314
- ).toBe("ws-skill");
315
- expect(readFileSync(join(ws, "data", "db", "assistant.db"), "utf-8")).toBe(
316
- "ws-db",
317
- );
318
-
319
- // Legacy hook entries are merged into workspace (not stranded)
320
- expect(existsSync(join(root, "hooks", "legacy-hook.sh"))).toBe(false);
321
- expect(readFileSync(join(ws, "hooks", "legacy-hook.sh"), "utf-8")).toBe(
322
- "root-hook",
323
- );
324
- // Legacy skills entries are merged into workspace (not stranded)
325
- expect(existsSync(join(root, "skills", "legacy-skill.json"))).toBe(false);
326
- expect(readFileSync(join(ws, "skills", "legacy-skill.json"), "utf-8")).toBe(
327
- "root-skill",
328
- );
329
- // Legacy data entries are merged into workspace/data (not orphaned)
330
- expect(existsSync(join(root, "data", "logs", "vellum.log"))).toBe(false);
331
- expect(readFileSync(join(ws, "data", "logs", "vellum.log"), "utf-8")).toBe(
332
- "root-log",
333
- );
334
- // Existing workspace data entries are preserved
335
- expect(readFileSync(join(ws, "data", "db", "assistant.db"), "utf-8")).toBe(
336
- "ws-db",
337
- );
338
-
339
- rmSync(base, { recursive: true, force: true });
340
- });
341
-
342
- test("legacy skills are merged when workspace/skills was pre-created by ensureDataDir", () => {
343
- const base = makeTmpBase();
344
- process.env.BASE_DATA_DIR = base;
345
- const root = join(base, ".vellum");
346
- const ws = join(root, "workspace");
347
-
348
- // ensureDataDir pre-created an empty workspace/skills directory
349
- mkdirSync(join(ws, "skills"), { recursive: true });
350
-
351
- // Legacy skills directory has actual skill subdirectories
352
- mkdirSync(join(root, "skills", "web-search"), { recursive: true });
353
- writeFileSync(
354
- join(root, "skills", "web-search", "SKILL.md"),
355
- "---\nname: Web Search\ndescription: Search the web\n---\nBody",
356
- );
357
- mkdirSync(join(root, "skills", "code-review"), { recursive: true });
358
- writeFileSync(
359
- join(root, "skills", "code-review", "SKILL.md"),
360
- "---\nname: Code Review\ndescription: Review code\n---\nBody",
361
- );
362
-
363
- migrateToWorkspaceLayout();
364
-
365
- // Legacy skills should be merged into workspace/skills
366
- expect(existsSync(join(ws, "skills", "web-search", "SKILL.md"))).toBe(true);
367
- expect(
368
- readFileSync(join(ws, "skills", "web-search", "SKILL.md"), "utf-8"),
369
- ).toContain("Web Search");
370
- expect(existsSync(join(ws, "skills", "code-review", "SKILL.md"))).toBe(
371
- true,
372
- );
373
- expect(
374
- readFileSync(join(ws, "skills", "code-review", "SKILL.md"), "utf-8"),
375
- ).toContain("Code Review");
376
-
377
- // Legacy skill dirs should be moved out
378
- expect(existsSync(join(root, "skills", "web-search"))).toBe(false);
379
- expect(existsSync(join(root, "skills", "code-review"))).toBe(false);
380
-
381
- rmSync(base, { recursive: true, force: true });
382
- });
383
-
384
- test("legacy skill merge does not overwrite existing workspace skills", () => {
385
- const base = makeTmpBase();
386
- process.env.BASE_DATA_DIR = base;
387
- const root = join(base, ".vellum");
388
- const ws = join(root, "workspace");
389
-
390
- // Workspace already has a skill with the same ID
391
- mkdirSync(join(ws, "skills", "web-search"), { recursive: true });
392
- writeFileSync(
393
- join(ws, "skills", "web-search", "SKILL.md"),
394
- "workspace-version",
395
- );
396
-
397
- // Legacy also has the same skill and one unique skill
398
- mkdirSync(join(root, "skills", "web-search"), { recursive: true });
399
- writeFileSync(
400
- join(root, "skills", "web-search", "SKILL.md"),
401
- "legacy-version",
402
- );
403
- mkdirSync(join(root, "skills", "unique-skill"), { recursive: true });
404
- writeFileSync(
405
- join(root, "skills", "unique-skill", "SKILL.md"),
406
- "unique-content",
407
- );
408
-
409
- migrateToWorkspaceLayout();
410
-
411
- // Workspace version should not be overwritten
412
- expect(
413
- readFileSync(join(ws, "skills", "web-search", "SKILL.md"), "utf-8"),
414
- ).toBe("workspace-version");
415
-
416
- // Unique skill from legacy should be merged in
417
- expect(existsSync(join(ws, "skills", "unique-skill", "SKILL.md"))).toBe(
418
- true,
419
- );
420
- expect(
421
- readFileSync(join(ws, "skills", "unique-skill", "SKILL.md"), "utf-8"),
422
- ).toBe("unique-content");
423
-
424
- rmSync(base, { recursive: true, force: true });
425
- });
426
-
427
- test("hooks config.json merge: legacy hook entries are preserved when workspace config exists", () => {
428
- const base = makeTmpBase();
429
- process.env.BASE_DATA_DIR = base;
430
- const root = join(base, ".vellum");
431
- const ws = join(root, "workspace");
432
-
433
- // Workspace hooks dir already exists with its own config.json
434
- mkdirSync(join(ws, "hooks"), { recursive: true });
435
- writeFileSync(
436
- join(ws, "hooks", "config.json"),
437
- JSON.stringify({
438
- version: 1,
439
- hooks: { "on-save": { enabled: true } },
440
- }),
441
- );
442
-
443
- // Legacy hooks dir has config.json with different hook entries
444
- mkdirSync(join(root, "hooks"), { recursive: true });
445
- writeFileSync(
446
- join(root, "hooks", "config.json"),
447
- JSON.stringify({
448
- version: 1,
449
- hooks: {
450
- "on-start": { enabled: true, settings: { delay: 100 } },
451
- "on-save": { enabled: false }, // conflicts — workspace value should win
452
- },
453
- }),
454
- );
455
-
456
- migrateToWorkspaceLayout();
457
-
458
- // Workspace hooks config should have the missing on-start entry merged in
459
- const merged = JSON.parse(
460
- readFileSync(join(ws, "hooks", "config.json"), "utf-8"),
461
- );
462
- expect(merged.hooks["on-start"]).toEqual({
463
- enabled: true,
464
- settings: { delay: 100 },
465
- });
466
- // Existing workspace hook entry should not be overwritten
467
- expect(merged.hooks["on-save"]).toEqual({ enabled: true });
468
-
469
- // Merged hook was removed from legacy config; conflicting one remains
470
- const legacyAfter = JSON.parse(
471
- readFileSync(join(root, "hooks", "config.json"), "utf-8"),
472
- );
473
- expect(legacyAfter.hooks["on-start"]).toBeUndefined();
474
- expect(legacyAfter.hooks["on-save"]).toEqual({ enabled: false });
475
-
476
- rmSync(base, { recursive: true, force: true });
477
- });
478
-
479
- test("hooks config.json merge: legacy file deleted when all hooks merged", () => {
480
- const base = makeTmpBase();
481
- process.env.BASE_DATA_DIR = base;
482
- const root = join(base, ".vellum");
483
- const ws = join(root, "workspace");
484
-
485
- mkdirSync(join(ws, "hooks"), { recursive: true });
486
- writeFileSync(
487
- join(ws, "hooks", "config.json"),
488
- JSON.stringify({ version: 1, hooks: {} }),
489
- );
490
-
491
- mkdirSync(join(root, "hooks"), { recursive: true });
492
- writeFileSync(
493
- join(root, "hooks", "config.json"),
494
- JSON.stringify({
495
- version: 1,
496
- hooks: { "on-start": { enabled: true } },
497
- }),
498
- );
499
-
500
- migrateToWorkspaceLayout();
501
-
502
- // All hooks were merged so legacy config.json should be deleted
503
- expect(existsSync(join(root, "hooks", "config.json"))).toBe(false);
504
-
505
- const merged = JSON.parse(
506
- readFileSync(join(ws, "hooks", "config.json"), "utf-8"),
507
- );
508
- expect(merged.hooks["on-start"]).toEqual({ enabled: true });
509
-
510
- rmSync(base, { recursive: true, force: true });
511
- });
512
-
513
- test("hooks config.json merge: non-object JSON does not crash", () => {
514
- const base = makeTmpBase();
515
- process.env.BASE_DATA_DIR = base;
516
- const root = join(base, ".vellum");
517
- const ws = join(root, "workspace");
518
-
519
- mkdirSync(join(ws, "hooks"), { recursive: true });
520
- writeFileSync(
521
- join(ws, "hooks", "config.json"),
522
- JSON.stringify({ version: 1, hooks: {} }),
523
- );
524
-
525
- mkdirSync(join(root, "hooks"), { recursive: true });
526
- writeFileSync(join(root, "hooks", "config.json"), "null");
527
-
528
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
529
-
530
- // Workspace config should be unchanged
531
- const wsConfig = JSON.parse(
532
- readFileSync(join(ws, "hooks", "config.json"), "utf-8"),
533
- );
534
- expect(wsConfig.version).toBe(1);
535
-
536
- rmSync(base, { recursive: true, force: true });
537
- });
538
-
539
- test("stale empty directories from a previous failed run do not cause errors", () => {
540
- const base = makeTmpBase();
541
- process.env.BASE_DATA_DIR = base;
542
- const root = join(base, ".vellum");
543
- const ws = join(root, "workspace");
544
-
545
- // Simulate aftermath of a partial migration: workspace already has
546
- // the real content, but empty leftover dirs remain at root.
547
- mkdirSync(ws, { recursive: true });
548
- writeFileSync(join(ws, "config.json"), "migrated-config");
549
-
550
- // Empty stale directories at root (e.g. sandbox dir after fs was moved out)
551
- mkdirSync(join(root, "data", "sandbox"), { recursive: true });
552
- // Empty hooks dir
553
- mkdirSync(join(root, "hooks"), { recursive: true });
554
- // Empty skills dir
555
- mkdirSync(join(root, "skills"), { recursive: true });
556
-
557
- // Migration should not throw
558
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
559
-
560
- // Workspace content should be preserved
561
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(
562
- "migrated-config",
563
- );
564
-
565
- // The empty stale dirs that didn't conflict should be moved into workspace
566
- // (data/ moves because ws/data doesn't exist yet)
567
- expect(existsSync(join(root, "data"))).toBe(false);
568
- expect(existsSync(join(ws, "data", "sandbox"))).toBe(true);
569
-
570
- // hooks and skills: moved successfully since no ws/hooks or ws/skills existed
571
- expect(existsSync(join(root, "hooks"))).toBe(false);
572
- expect(existsSync(join(ws, "hooks"))).toBe(true);
573
- expect(existsSync(join(root, "skills"))).toBe(false);
574
- expect(existsSync(join(ws, "skills"))).toBe(true);
575
-
576
- rmSync(base, { recursive: true, force: true });
577
- });
578
-
579
- test("stale empty dirs at root with existing workspace counterparts are harmless", () => {
580
- const base = makeTmpBase();
581
- process.env.BASE_DATA_DIR = base;
582
- const root = join(base, ".vellum");
583
- const ws = join(root, "workspace");
584
-
585
- // Workspace already fully set up
586
- mkdirSync(join(ws, "hooks"), { recursive: true });
587
- writeFileSync(join(ws, "hooks", "real-hook.sh"), "hook-content");
588
- mkdirSync(join(ws, "skills"), { recursive: true });
589
- writeFileSync(join(ws, "skills", "real-skill.json"), "skill-content");
590
- mkdirSync(join(ws, "data"), { recursive: true });
591
-
592
- // Stale empty dirs at root that conflict with workspace dirs
593
- mkdirSync(join(root, "hooks"), { recursive: true });
594
- mkdirSync(join(root, "skills"), { recursive: true });
595
- mkdirSync(join(root, "data"), { recursive: true });
596
-
597
- // Should not throw
598
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
599
-
600
- // Workspace content untouched
601
- expect(readFileSync(join(ws, "hooks", "real-hook.sh"), "utf-8")).toBe(
602
- "hook-content",
603
- );
604
- expect(readFileSync(join(ws, "skills", "real-skill.json"), "utf-8")).toBe(
605
- "skill-content",
606
- );
607
-
608
- // Stale root dirs remain (skipped due to destination conflict)
609
- expect(existsSync(join(root, "hooks"))).toBe(true);
610
- expect(existsSync(join(root, "skills"))).toBe(true);
611
- expect(existsSync(join(root, "data"))).toBe(true);
612
-
613
- rmSync(base, { recursive: true, force: true });
614
- });
615
-
616
- test("protected/ directory at root is never touched by migration", () => {
617
- const base = makeTmpBase();
618
- process.env.BASE_DATA_DIR = base;
619
- const root = join(base, ".vellum");
620
-
621
- populateLegacyLayout(root);
622
-
623
- // Add a protected directory with sensitive content
624
- mkdirSync(join(root, "protected"), { recursive: true });
625
- writeFileSync(join(root, "protected", "trust.json"), '{"rules":[]}');
626
- writeFileSync(join(root, "protected", "keys.enc"), "encrypted-keys");
627
-
628
- migrateToWorkspaceLayout();
629
-
630
- // protected/ should remain exactly at root, untouched
631
- expect(existsSync(join(root, "protected"))).toBe(true);
632
- expect(readFileSync(join(root, "protected", "trust.json"), "utf-8")).toBe(
633
- '{"rules":[]}',
634
- );
635
- expect(readFileSync(join(root, "protected", "keys.enc"), "utf-8")).toBe(
636
- "encrypted-keys",
637
- );
638
-
639
- // It should NOT appear in workspace
640
- expect(existsSync(join(root, "workspace", "protected"))).toBe(false);
641
-
642
- // Other items should have migrated normally
643
- expect(existsSync(join(root, "workspace", "IDENTITY.md"))).toBe(true);
644
- expect(existsSync(join(root, "workspace", "SOUL.md"))).toBe(true);
645
-
646
- // Runtime files also untouched
647
- expect(existsSync(join(root, "vellum.sock"))).toBe(true);
648
- expect(existsSync(join(root, "vellum.pid"))).toBe(true);
649
-
650
- rmSync(base, { recursive: true, force: true });
651
- });
652
-
653
- test("config key merge: legacy slackWebhookUrl is preserved when workspace config already exists", () => {
654
- const base = makeTmpBase();
655
- process.env.BASE_DATA_DIR = base;
656
- const root = join(base, ".vellum");
657
- const ws = join(root, "workspace");
658
-
659
- mkdirSync(ws, { recursive: true });
660
-
661
- // Legacy root config has slackWebhookUrl that was written by old code
662
- writeFileSync(
663
- join(root, "config.json"),
664
- JSON.stringify({
665
- slackWebhookUrl: "https://hooks.slack.com/old",
666
- theme: "dark",
667
- }),
668
- );
669
-
670
- // Workspace config already exists with different keys but no slackWebhookUrl
671
- writeFileSync(
672
- join(ws, "config.json"),
673
- JSON.stringify({ model: "claude-3", theme: "light" }),
674
- );
675
-
676
- migrateToWorkspaceLayout();
677
-
678
- // Workspace config should have the missing slackWebhookUrl merged in
679
- const merged = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
680
- expect(merged.slackWebhookUrl).toBe("https://hooks.slack.com/old");
681
- // Existing workspace keys should be preserved (not overwritten)
682
- expect(merged.model).toBe("claude-3");
683
- expect(merged.theme).toBe("light"); // workspace value wins over legacy
684
-
685
- // Merged key (slackWebhookUrl) was removed from legacy config;
686
- // shared key (theme) remains so the file is kept.
687
- expect(existsSync(join(root, "config.json"))).toBe(true);
688
- const remaining = JSON.parse(
689
- readFileSync(join(root, "config.json"), "utf-8"),
690
- );
691
- expect(remaining.slackWebhookUrl).toBeUndefined();
692
- expect(remaining.theme).toBe("dark");
693
-
694
- rmSync(base, { recursive: true, force: true });
695
- });
696
-
697
- test("config key merge: legacy file deleted when all keys were merged", () => {
698
- const base = makeTmpBase();
699
- process.env.BASE_DATA_DIR = base;
700
- const root = join(base, ".vellum");
701
- const ws = join(root, "workspace");
702
-
703
- mkdirSync(ws, { recursive: true });
704
-
705
- // Legacy config has only keys missing from workspace
706
- writeFileSync(
707
- join(root, "config.json"),
708
- JSON.stringify({ slackWebhookUrl: "https://hooks.slack.com/old" }),
709
- );
710
- writeFileSync(
711
- join(ws, "config.json"),
712
- JSON.stringify({ model: "claude-3" }),
713
- );
714
-
715
- migrateToWorkspaceLayout();
716
-
717
- const merged = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
718
- expect(merged.slackWebhookUrl).toBe("https://hooks.slack.com/old");
719
- expect(merged.model).toBe("claude-3");
720
-
721
- // Legacy config should be deleted since all its keys were merged
722
- expect(existsSync(join(root, "config.json"))).toBe(false);
723
-
724
- rmSync(base, { recursive: true, force: true });
725
- });
726
-
727
- test("config key merge: does not resurrect keys deleted from workspace", () => {
728
- const base = makeTmpBase();
729
- process.env.BASE_DATA_DIR = base;
730
- const root = join(base, ".vellum");
731
- const ws = join(root, "workspace");
732
-
733
- mkdirSync(ws, { recursive: true });
734
-
735
- // Legacy config has slackWebhookUrl
736
- writeFileSync(
737
- join(root, "config.json"),
738
- JSON.stringify({
739
- slackWebhookUrl: "https://hooks.slack.com/old",
740
- theme: "dark",
741
- }),
742
- );
743
- writeFileSync(
744
- join(ws, "config.json"),
745
- JSON.stringify({ model: "claude-3" }),
746
- );
747
-
748
- // First run merges slackWebhookUrl into workspace
749
- migrateToWorkspaceLayout();
750
- const afterFirst = JSON.parse(
751
- readFileSync(join(ws, "config.json"), "utf-8"),
752
- );
753
- expect(afterFirst.slackWebhookUrl).toBe("https://hooks.slack.com/old");
754
-
755
- // User deletes slackWebhookUrl from workspace config
756
- delete afterFirst.slackWebhookUrl;
757
- writeFileSync(join(ws, "config.json"), JSON.stringify(afterFirst));
758
-
759
- // Second run should NOT resurrect the deleted key
760
- migrateToWorkspaceLayout();
761
- const afterSecond = JSON.parse(
762
- readFileSync(join(ws, "config.json"), "utf-8"),
763
- );
764
- expect(afterSecond.slackWebhookUrl).toBeUndefined();
765
-
766
- rmSync(base, { recursive: true, force: true });
767
- });
768
-
769
- test("config key merge: non-object JSON in config files does not crash", () => {
770
- const base = makeTmpBase();
771
- process.env.BASE_DATA_DIR = base;
772
- const root = join(base, ".vellum");
773
- const ws = join(root, "workspace");
774
-
775
- mkdirSync(ws, { recursive: true });
776
-
777
- // null is valid JSON but not a plain object
778
- writeFileSync(join(root, "config.json"), "null");
779
- writeFileSync(
780
- join(ws, "config.json"),
781
- JSON.stringify({ model: "claude-3" }),
782
- );
783
-
784
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
785
- // Workspace config should be unchanged
786
- const wsConfig = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
787
- expect(wsConfig.model).toBe("claude-3");
788
-
789
- // Array legacy config
790
- writeFileSync(join(root, "config.json"), "[1,2,3]");
791
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
792
- expect(
793
- JSON.parse(readFileSync(join(ws, "config.json"), "utf-8")).model,
794
- ).toBe("claude-3");
795
-
796
- // Array workspace config
797
- writeFileSync(join(root, "config.json"), JSON.stringify({ theme: "dark" }));
798
- writeFileSync(join(ws, "config.json"), "[1,2,3]");
799
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
800
-
801
- rmSync(base, { recursive: true, force: true });
802
- });
803
-
804
- test("config key merge: no-op when legacy config has no extra keys", () => {
805
- const base = makeTmpBase();
806
- process.env.BASE_DATA_DIR = base;
807
- const root = join(base, ".vellum");
808
- const ws = join(root, "workspace");
809
-
810
- mkdirSync(ws, { recursive: true });
811
-
812
- // Both configs have the same keys
813
- writeFileSync(join(root, "config.json"), JSON.stringify({ theme: "dark" }));
814
- writeFileSync(join(ws, "config.json"), JSON.stringify({ theme: "light" }));
815
-
816
- const wsBefore = readFileSync(join(ws, "config.json"), "utf-8");
817
-
818
- migrateToWorkspaceLayout();
819
-
820
- // Workspace config should be unchanged
821
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(wsBefore);
822
-
823
- rmSync(base, { recursive: true, force: true });
824
- });
825
-
826
- test("config key merge: non-object JSON (null) does not crash", () => {
827
- const base = makeTmpBase();
828
- process.env.BASE_DATA_DIR = base;
829
- const root = join(base, ".vellum");
830
- const ws = join(root, "workspace");
831
-
832
- mkdirSync(ws, { recursive: true });
833
-
834
- // Legacy config contains null (valid JSON but not an object)
835
- writeFileSync(join(root, "config.json"), "null");
836
- writeFileSync(join(ws, "config.json"), JSON.stringify({ theme: "dark" }));
837
-
838
- // Should not throw
839
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
840
-
841
- // Workspace config should be unchanged
842
- const parsed = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
843
- expect(parsed.theme).toBe("dark");
844
-
845
- rmSync(base, { recursive: true, force: true });
846
- });
847
-
848
- test("config key merge: non-object JSON (array) does not crash", () => {
849
- const base = makeTmpBase();
850
- process.env.BASE_DATA_DIR = base;
851
- const root = join(base, ".vellum");
852
- const ws = join(root, "workspace");
853
-
854
- mkdirSync(ws, { recursive: true });
855
-
856
- // Legacy config is an array
857
- writeFileSync(join(root, "config.json"), "[1, 2, 3]");
858
- writeFileSync(join(ws, "config.json"), JSON.stringify({ model: "gpt-4" }));
859
-
860
- expect(() => migrateToWorkspaceLayout()).not.toThrow();
861
-
862
- const parsed = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
863
- expect(parsed.model).toBe("gpt-4");
864
-
865
- rmSync(base, { recursive: true, force: true });
866
- });
867
-
868
- test("config key merge: merged keys are removed from legacy to prevent resurrection", () => {
869
- const base = makeTmpBase();
870
- process.env.BASE_DATA_DIR = base;
871
- const root = join(base, ".vellum");
872
- const ws = join(root, "workspace");
873
-
874
- mkdirSync(ws, { recursive: true });
875
-
876
- // Legacy has slackWebhookUrl (missing from workspace) and theme (already in workspace)
877
- writeFileSync(
878
- join(root, "config.json"),
879
- JSON.stringify({
880
- slackWebhookUrl: "https://hooks.slack.com/old",
881
- theme: "dark",
882
- }),
883
- );
884
- writeFileSync(
885
- join(ws, "config.json"),
886
- JSON.stringify({ model: "claude-3", theme: "light" }),
887
- );
888
-
889
- migrateToWorkspaceLayout();
890
-
891
- // Merged key should be in workspace
892
- const merged = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
893
- expect(merged.slackWebhookUrl).toBe("https://hooks.slack.com/old");
894
-
895
- // Legacy should no longer contain the merged key
896
- const legacyAfter = JSON.parse(
897
- readFileSync(join(root, "config.json"), "utf-8"),
898
- );
899
- expect(legacyAfter.slackWebhookUrl).toBeUndefined();
900
- // Non-merged key should still be in legacy
901
- expect(legacyAfter.theme).toBe("dark");
902
-
903
- // Second run should be a no-op (no keys to merge)
904
- const wsBeforeSecond = readFileSync(join(ws, "config.json"), "utf-8");
905
- migrateToWorkspaceLayout();
906
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(wsBeforeSecond);
907
-
908
- rmSync(base, { recursive: true, force: true });
909
- });
910
-
911
- test("config key merge: legacy file deleted when all keys have been merged", () => {
912
- const base = makeTmpBase();
913
- process.env.BASE_DATA_DIR = base;
914
- const root = join(base, ".vellum");
915
- const ws = join(root, "workspace");
916
-
917
- mkdirSync(ws, { recursive: true });
918
-
919
- // Legacy only has keys missing from workspace
920
- writeFileSync(
921
- join(root, "config.json"),
922
- JSON.stringify({ slackWebhookUrl: "https://hooks.slack.com/old" }),
923
- );
924
- writeFileSync(
925
- join(ws, "config.json"),
926
- JSON.stringify({ model: "claude-3" }),
927
- );
928
-
929
- migrateToWorkspaceLayout();
930
-
931
- // Legacy file should be deleted (all keys were merged)
932
- expect(existsSync(join(root, "config.json"))).toBe(false);
933
-
934
- // Workspace should have the merged key
935
- const merged = JSON.parse(readFileSync(join(ws, "config.json"), "utf-8"));
936
- expect(merged.slackWebhookUrl).toBe("https://hooks.slack.com/old");
937
- expect(merged.model).toBe("claude-3");
938
-
939
- rmSync(base, { recursive: true, force: true });
940
- });
941
-
942
- test("sandbox/fs extraction with user data/ dir does not orphan internal state", () => {
943
- const base = makeTmpBase();
944
- process.env.BASE_DATA_DIR = base;
945
- const root = join(base, ".vellum");
946
- const ws = join(root, "workspace");
947
-
948
- mkdirSync(root, { recursive: true });
949
-
950
- // Legacy data dir: sandbox/fs contains a user project with its own data/ folder
951
- const dataDir = join(root, "data");
952
- mkdirSync(join(dataDir, "sandbox", "fs", "data", "models"), {
953
- recursive: true,
954
- });
955
- writeFileSync(
956
- join(dataDir, "sandbox", "fs", "data", "models", "model.pkl"),
957
- "user-model",
958
- );
959
- writeFileSync(join(dataDir, "sandbox", "fs", "app.py"), "user-app");
960
-
961
- // Internal state dirs inside data/
962
- mkdirSync(join(dataDir, "db"), { recursive: true });
963
- writeFileSync(join(dataDir, "db", "assistant.db"), "internal-db");
964
- mkdirSync(join(dataDir, "logs"), { recursive: true });
965
- writeFileSync(join(dataDir, "logs", "vellum.log"), "internal-log");
966
- mkdirSync(join(dataDir, "sandbox", "metadata"), { recursive: true });
967
- writeFileSync(
968
- join(dataDir, "sandbox", "metadata", "state.json"),
969
- "sandbox-state",
970
- );
971
-
972
- migrateToWorkspaceLayout();
973
-
974
- // (a) sandbox/fs was extracted to workspace root
975
- expect(readFileSync(join(ws, "app.py"), "utf-8")).toBe("user-app");
976
- // User's data/ directory is now workspace/data
977
- expect(readFileSync(join(ws, "data", "models", "model.pkl"), "utf-8")).toBe(
978
- "user-model",
979
- );
980
-
981
- // Internal state from root/data/ was merged into workspace/data/
982
- expect(readFileSync(join(ws, "data", "db", "assistant.db"), "utf-8")).toBe(
983
- "internal-db",
984
- );
985
- expect(readFileSync(join(ws, "data", "logs", "vellum.log"), "utf-8")).toBe(
986
- "internal-log",
987
- );
988
-
989
- // sandbox/ subdir from root/data/ was merged too
990
- expect(
991
- readFileSync(
992
- join(ws, "data", "sandbox", "metadata", "state.json"),
993
- "utf-8",
994
- ),
995
- ).toBe("sandbox-state");
996
-
997
- rmSync(base, { recursive: true, force: true });
998
- });
999
-
1000
- test("mixed partial migration with sandbox/fs already extracted", () => {
1001
- const base = makeTmpBase();
1002
- process.env.BASE_DATA_DIR = base;
1003
- const root = join(base, ".vellum");
1004
- const ws = join(root, "workspace");
1005
-
1006
- // Workspace already exists (sandbox/fs was previously extracted),
1007
- // but some files are still at root awaiting migration.
1008
- mkdirSync(join(ws, "project"), { recursive: true });
1009
- writeFileSync(join(ws, "hello.txt"), "sandbox-file");
1010
- writeFileSync(join(ws, "project", "main.ts"), "project-code");
1011
-
1012
- // Legacy items still at root
1013
- writeFileSync(join(root, "config.json"), "legacy-config");
1014
- writeFileSync(join(root, "IDENTITY.md"), "legacy-identity");
1015
- writeFileSync(join(root, "SOUL.md"), "legacy-soul");
1016
-
1017
- // data dir with remaining content (sandbox/fs is gone but rest remains)
1018
- mkdirSync(join(root, "data", "db"), { recursive: true });
1019
- writeFileSync(join(root, "data", "db", "assistant.db"), "legacy-db");
1020
- mkdirSync(join(root, "data", "logs"), { recursive: true });
1021
- writeFileSync(join(root, "data", "logs", "vellum.log"), "legacy-log");
1022
-
1023
- migrateToWorkspaceLayout();
1024
-
1025
- // sandbox/fs content (now workspace root content) should be intact
1026
- expect(readFileSync(join(ws, "hello.txt"), "utf-8")).toBe("sandbox-file");
1027
- expect(readFileSync(join(ws, "project", "main.ts"), "utf-8")).toBe(
1028
- "project-code",
1029
- );
1030
-
1031
- // Legacy items should now be in workspace
1032
- expect(readFileSync(join(ws, "config.json"), "utf-8")).toBe(
1033
- "legacy-config",
1034
- );
1035
- expect(readFileSync(join(ws, "IDENTITY.md"), "utf-8")).toBe(
1036
- "legacy-identity",
1037
- );
1038
- expect(readFileSync(join(ws, "SOUL.md"), "utf-8")).toBe("legacy-soul");
1039
- expect(readFileSync(join(ws, "data", "db", "assistant.db"), "utf-8")).toBe(
1040
- "legacy-db",
1041
- );
1042
-
1043
- // Root should be clean of migrated items
1044
- expect(existsSync(join(root, "config.json"))).toBe(false);
1045
- expect(existsSync(join(root, "IDENTITY.md"))).toBe(false);
1046
- expect(existsSync(join(root, "SOUL.md"))).toBe(false);
1047
- expect(existsSync(join(root, "data"))).toBe(false);
1048
-
1049
- rmSync(base, { recursive: true, force: true });
1050
- });
1051
- });