@vellumai/assistant 0.5.13 → 0.5.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (425) hide show
  1. package/.env.example +1 -6
  2. package/AGENTS.md +4 -0
  3. package/ARCHITECTURE.md +0 -1
  4. package/bunfig.toml +1 -0
  5. package/docs/architecture/memory.md +3 -3
  6. package/openapi.yaml +127 -22
  7. package/package.json +1 -1
  8. package/src/__tests__/access-request-decision.test.ts +2 -32
  9. package/src/__tests__/actor-token-service.test.ts +1 -31
  10. package/src/__tests__/anthropic-provider.test.ts +53 -40
  11. package/src/__tests__/app-git-history.test.ts +9 -17
  12. package/src/__tests__/app-git-service.test.ts +14 -20
  13. package/src/__tests__/app-store-dir-names.test.ts +10 -20
  14. package/src/__tests__/approval-cascade.test.ts +2 -19
  15. package/src/__tests__/approval-primitive.test.ts +2 -27
  16. package/src/__tests__/approval-routes-http.test.ts +2 -30
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -28
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -45
  19. package/src/__tests__/attachments-store.test.ts +5 -32
  20. package/src/__tests__/audit-log-rotation.test.ts +5 -36
  21. package/src/__tests__/avatar-e2e.test.ts +1 -9
  22. package/src/__tests__/avatar-generator.test.ts +1 -7
  23. package/src/__tests__/browser-fill-credential.test.ts +0 -4
  24. package/src/__tests__/browser-manager.test.ts +0 -6
  25. package/src/__tests__/call-controller.test.ts +1 -22
  26. package/src/__tests__/call-conversation-messages.test.ts +0 -21
  27. package/src/__tests__/call-domain.test.ts +0 -25
  28. package/src/__tests__/call-pointer-messages.test.ts +0 -21
  29. package/src/__tests__/call-recovery.test.ts +0 -22
  30. package/src/__tests__/call-routes-http.test.ts +0 -24
  31. package/src/__tests__/call-store.test.ts +0 -21
  32. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -24
  33. package/src/__tests__/canonical-guardian-store.test.ts +48 -21
  34. package/src/__tests__/channel-approval-routes.test.ts +6 -26
  35. package/src/__tests__/channel-approvals.test.ts +1 -38
  36. package/src/__tests__/channel-delivery-store.test.ts +0 -21
  37. package/src/__tests__/channel-guardian.test.ts +0 -26
  38. package/src/__tests__/channel-reply-delivery.test.ts +5 -0
  39. package/src/__tests__/channel-retry-sweep.test.ts +0 -21
  40. package/src/__tests__/checker.test.ts +26 -61
  41. package/src/__tests__/clawhub.test.ts +9 -25
  42. package/src/__tests__/cli-command-risk-guard.test.ts +0 -18
  43. package/src/__tests__/config-loader-backfill.test.ts +9 -28
  44. package/src/__tests__/config-schema-cmd.test.ts +5 -25
  45. package/src/__tests__/config-schema.test.ts +21 -40
  46. package/src/__tests__/config-watcher.test.ts +4 -91
  47. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -21
  48. package/src/__tests__/contacts-tools.test.ts +0 -21
  49. package/src/__tests__/context-memory-e2e.test.ts +0 -21
  50. package/src/__tests__/context-window-manager.test.ts +130 -3
  51. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -4
  52. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -4
  53. package/src/__tests__/conversation-agent-loop.test.ts +0 -4
  54. package/src/__tests__/conversation-attachments.test.ts +1 -24
  55. package/src/__tests__/conversation-attention-store.test.ts +0 -21
  56. package/src/__tests__/conversation-attention-telegram.test.ts +0 -22
  57. package/src/__tests__/conversation-clear-safety.test.ts +0 -22
  58. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -21
  59. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -24
  60. package/src/__tests__/conversation-disk-view-integration.test.ts +1 -23
  61. package/src/__tests__/conversation-disk-view.test.ts +5 -27
  62. package/src/__tests__/conversation-error.test.ts +1 -1
  63. package/src/__tests__/conversation-fork-crud.test.ts +1 -33
  64. package/src/__tests__/conversation-fork-route.test.ts +0 -27
  65. package/src/__tests__/conversation-history-web-search.test.ts +23 -16
  66. package/src/__tests__/conversation-init.benchmark.test.ts +22 -43
  67. package/src/__tests__/conversation-key-store-disk-view.test.ts +8 -34
  68. package/src/__tests__/conversation-load-history-repair.test.ts +0 -4
  69. package/src/__tests__/conversation-pre-run-repair.test.ts +0 -4
  70. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -4
  71. package/src/__tests__/conversation-queue.test.ts +8 -8
  72. package/src/__tests__/conversation-routes-disk-view.test.ts +13 -51
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +64 -38
  74. package/src/__tests__/conversation-slash-commands.test.ts +5 -0
  75. package/src/__tests__/conversation-slash-queue.test.ts +0 -4
  76. package/src/__tests__/conversation-slash-unknown.test.ts +0 -4
  77. package/src/__tests__/conversation-speed-override.test.ts +326 -0
  78. package/src/__tests__/conversation-starter-routes.test.ts +0 -23
  79. package/src/__tests__/conversation-store.test.ts +0 -21
  80. package/src/__tests__/conversation-unread-route.test.ts +0 -24
  81. package/src/__tests__/conversation-usage.test.ts +56 -21
  82. package/src/__tests__/conversation-wipe.test.ts +0 -21
  83. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  84. package/src/__tests__/conversation-workspace-injection.test.ts +0 -4
  85. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -4
  86. package/src/__tests__/credential-execution-shell-lockdown.test.ts +8 -5
  87. package/src/__tests__/credential-vault-unit.test.ts +9 -428
  88. package/src/__tests__/credentials-cli.test.ts +10 -10
  89. package/src/__tests__/daemon-assistant-events.test.ts +0 -19
  90. package/src/__tests__/date-context.test.ts +77 -97
  91. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +7 -24
  92. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +29 -42
  93. package/src/__tests__/delete-managed-skill-tool.test.ts +2 -10
  94. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -26
  95. package/src/__tests__/docker-signing-key-bootstrap.test.ts +61 -15
  96. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -36
  97. package/src/__tests__/email-cli.test.ts +6 -6
  98. package/src/__tests__/ephemeral-permissions.test.ts +5 -17
  99. package/src/__tests__/first-greeting.test.ts +4 -32
  100. package/src/__tests__/followup-tools.test.ts +0 -21
  101. package/src/__tests__/gateway-only-enforcement.test.ts +0 -20
  102. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -23
  103. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -23
  104. package/src/__tests__/guardian-action-followup-store.test.ts +0 -21
  105. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -21
  106. package/src/__tests__/guardian-action-late-reply.test.ts +0 -21
  107. package/src/__tests__/guardian-action-store.test.ts +0 -21
  108. package/src/__tests__/guardian-action-sweep.test.ts +0 -21
  109. package/src/__tests__/guardian-binding-drift-heal.test.ts +0 -23
  110. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +172 -22
  111. package/src/__tests__/guardian-dispatch.test.ts +0 -21
  112. package/src/__tests__/guardian-grant-minting.test.ts +0 -22
  113. package/src/__tests__/guardian-outbound-http.test.ts +0 -22
  114. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -23
  115. package/src/__tests__/guardian-routing-invariants.test.ts +0 -22
  116. package/src/__tests__/guardian-routing-state.test.ts +0 -22
  117. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -24
  118. package/src/__tests__/headless-browser-interactions.test.ts +0 -4
  119. package/src/__tests__/headless-browser-navigate.test.ts +0 -4
  120. package/src/__tests__/headless-browser-read-tools.test.ts +0 -4
  121. package/src/__tests__/headless-browser-snapshot.test.ts +0 -4
  122. package/src/__tests__/heartbeat-service.test.ts +99 -26
  123. package/src/__tests__/hooks-blocking.test.ts +3 -3
  124. package/src/__tests__/hooks-config.test.ts +7 -7
  125. package/src/__tests__/hooks-discovery.test.ts +3 -3
  126. package/src/__tests__/hooks-integration.test.ts +5 -5
  127. package/src/__tests__/hooks-manager.test.ts +3 -3
  128. package/src/__tests__/hooks-runner.test.ts +5 -23
  129. package/src/__tests__/hooks-settings.test.ts +3 -3
  130. package/src/__tests__/hooks-templates.test.ts +3 -3
  131. package/src/__tests__/http-conversation-lineage.test.ts +0 -27
  132. package/src/__tests__/identity-intro-cache.test.ts +0 -4
  133. package/src/__tests__/inbound-invite-redemption.test.ts +0 -22
  134. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -16
  135. package/src/__tests__/intent-routing.test.ts +2 -55
  136. package/src/__tests__/invite-redemption-service.test.ts +0 -21
  137. package/src/__tests__/invite-routes-http.test.ts +0 -21
  138. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +0 -17
  139. package/src/__tests__/journal-context.test.ts +8 -75
  140. package/src/__tests__/list-messages-attachments.test.ts +0 -22
  141. package/src/__tests__/llm-context-route-provider.test.ts +0 -21
  142. package/src/__tests__/llm-request-log-turn-query.test.ts +46 -28
  143. package/src/__tests__/llm-usage-store.test.ts +0 -21
  144. package/src/__tests__/log-export-workspace.test.ts +1 -1
  145. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
  146. package/src/__tests__/managed-store.test.ts +1 -1
  147. package/src/__tests__/mcp-cli.test.ts +7 -10
  148. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -21
  149. package/src/__tests__/memory-jobs-worker-backoff.test.ts +0 -11
  150. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -21
  151. package/src/__tests__/memory-recall-log-store.test.ts +0 -27
  152. package/src/__tests__/memory-recall-quality.test.ts +0 -21
  153. package/src/__tests__/memory-regressions.experimental.test.ts +31 -30
  154. package/src/__tests__/memory-regressions.test.ts +282 -70
  155. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -21
  156. package/src/__tests__/memory-upsert-concurrency.test.ts +0 -21
  157. package/src/__tests__/messaging-send-tool.test.ts +201 -0
  158. package/src/__tests__/migration-cross-version-compatibility.test.ts +18 -13
  159. package/src/__tests__/migration-export-http.test.ts +7 -1
  160. package/src/__tests__/migration-import-commit-http.test.ts +16 -14
  161. package/src/__tests__/migration-import-preflight-http.test.ts +27 -44
  162. package/src/__tests__/migration-validate-http.test.ts +1 -28
  163. package/src/__tests__/native-web-search.test.ts +25 -22
  164. package/src/__tests__/non-member-access-request.test.ts +0 -22
  165. package/src/__tests__/notification-guardian-path.test.ts +0 -21
  166. package/src/__tests__/notification-schedule-dedup.test.ts +1 -25
  167. package/src/__tests__/oauth-apps-routes.test.ts +103 -2
  168. package/src/__tests__/oauth-cli.test.ts +52 -0
  169. package/src/__tests__/oauth-provider-profiles.test.ts +0 -16
  170. package/src/__tests__/oauth-provider-serializer.test.ts +232 -0
  171. package/src/__tests__/oauth-providers-routes.test.ts +257 -0
  172. package/src/__tests__/oauth-store.test.ts +0 -21
  173. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  174. package/src/__tests__/openai-provider.test.ts +261 -0
  175. package/src/__tests__/pairing-concurrent.test.ts +6 -6
  176. package/src/__tests__/pairing-routes.test.ts +7 -1
  177. package/src/__tests__/path-policy.test.ts +1 -1
  178. package/src/__tests__/platform.test.ts +64 -88
  179. package/src/__tests__/playbook-execution.test.ts +0 -21
  180. package/src/__tests__/playbook-tools.test.ts +0 -21
  181. package/src/__tests__/pricing.test.ts +100 -0
  182. package/src/__tests__/relay-server.test.ts +1 -25
  183. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -24
  184. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -24
  185. package/src/__tests__/runtime-events-sse.test.ts +0 -24
  186. package/src/__tests__/sandbox-diagnostics.test.ts +2 -1
  187. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
  188. package/src/__tests__/schedule-store.test.ts +0 -21
  189. package/src/__tests__/schedule-tools.test.ts +0 -21
  190. package/src/__tests__/scheduler-recurrence.test.ts +0 -21
  191. package/src/__tests__/scoped-approval-grants.test.ts +0 -21
  192. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -21
  193. package/src/__tests__/secret-allowlist.test.ts +1 -1
  194. package/src/__tests__/secret-ingress-channel.test.ts +0 -5
  195. package/src/__tests__/secret-ingress-cli.test.ts +0 -6
  196. package/src/__tests__/secret-ingress-http.test.ts +0 -5
  197. package/src/__tests__/secret-ingress.test.ts +0 -5
  198. package/src/__tests__/send-endpoint-busy.test.ts +0 -24
  199. package/src/__tests__/sequence-store.test.ts +0 -21
  200. package/src/__tests__/server-history-render.test.ts +0 -24
  201. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -4
  202. package/src/__tests__/skill-load-inline-command.test.ts +9 -0
  203. package/src/__tests__/skill-load-inline-includes.test.ts +9 -0
  204. package/src/__tests__/skill-load-tool.test.ts +11 -0
  205. package/src/__tests__/skills-uninstall.test.ts +10 -8
  206. package/src/__tests__/skills.test.ts +1 -1
  207. package/src/__tests__/slack-channel-config.test.ts +1 -1
  208. package/src/__tests__/slack-inbound-verification.test.ts +0 -22
  209. package/src/__tests__/starter-bundle.test.ts +4 -1
  210. package/src/__tests__/suggestion-routes.test.ts +2 -0
  211. package/src/__tests__/system-prompt.test.ts +1 -1
  212. package/src/__tests__/terminal-tools.test.ts +1 -1
  213. package/src/__tests__/test-preload.ts +31 -0
  214. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
  215. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  216. package/src/__tests__/tool-executor.test.ts +0 -20
  217. package/src/__tests__/tool-input-summary.test.ts +124 -0
  218. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -1
  219. package/src/__tests__/trust-store.test.ts +7 -1
  220. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -1
  221. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -1
  222. package/src/__tests__/trusted-contact-multichannel.test.ts +1 -1
  223. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  224. package/src/__tests__/turn-boundary-resolution.test.ts +1 -1
  225. package/src/__tests__/twilio-routes.test.ts +1 -1
  226. package/src/__tests__/update-bulletin.test.ts +1 -1
  227. package/src/__tests__/vbundle-pax-and-symlink.test.ts +1 -1
  228. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -0
  229. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
  230. package/src/__tests__/voice-session-bridge.test.ts +1 -1
  231. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
  232. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
  233. package/src/__tests__/workspace-migration-down-functions.test.ts +15 -3
  234. package/src/__tests__/workspace-migration-seed-device-id.test.ts +40 -4
  235. package/src/agent/loop.ts +6 -9
  236. package/src/approvals/guardian-decision-primitive.ts +46 -18
  237. package/src/approvals/guardian-request-resolvers.ts +19 -2
  238. package/src/calls/active-call-lease.ts +2 -2
  239. package/src/cli/AGENTS.md +1 -1
  240. package/src/cli/commands/doctor.ts +9 -9
  241. package/src/cli/commands/memory.ts +142 -0
  242. package/src/cli/commands/oauth/__tests__/connect.test.ts +13 -11
  243. package/src/cli/commands/oauth/__tests__/ping.test.ts +1 -1
  244. package/src/cli/commands/oauth/connect.ts +13 -12
  245. package/src/cli/commands/oauth/index.ts +1 -1
  246. package/src/cli/commands/oauth/providers.ts +47 -62
  247. package/src/cli/commands/platform/__tests__/connect.test.ts +72 -46
  248. package/src/cli/commands/platform/__tests__/disconnect.test.ts +54 -1
  249. package/src/cli/commands/platform/__tests__/status.test.ts +36 -0
  250. package/src/cli/commands/platform/connect.ts +17 -7
  251. package/src/cli/commands/platform/disconnect.ts +28 -3
  252. package/src/cli/commands/platform/index.ts +3 -3
  253. package/src/cli.ts +1 -299
  254. package/src/config/assistant-feature-flags.ts +23 -15
  255. package/src/config/bundled-skills/app-builder/TOOLS.json +16 -0
  256. package/src/config/bundled-skills/app-builder/tools/app-create.ts +4 -0
  257. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +5 -1
  258. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +9 -1
  259. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +5 -1
  260. package/src/config/bundled-skills/contacts/TOOLS.json +8 -0
  261. package/src/config/bundled-skills/contacts/tools/contact-search.ts +10 -1
  262. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +16 -2
  263. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +1 -0
  264. package/src/config/bundled-skills/messaging/SKILL.md +7 -7
  265. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +37 -0
  266. package/src/config/bundled-skills/slack/SKILL.md +18 -0
  267. package/src/config/env-registry.ts +15 -11
  268. package/src/config/env.ts +1 -11
  269. package/src/config/feature-flag-registry.json +16 -0
  270. package/src/config/schema.ts +4 -0
  271. package/src/config/schemas/heartbeat.ts +6 -1
  272. package/src/config/schemas/inference.ts +14 -3
  273. package/src/config/schemas/memory-processing.ts +16 -8
  274. package/src/config/schemas/memory-retrieval.ts +3 -3
  275. package/src/config/skills.ts +1 -1
  276. package/src/context/window-manager.ts +174 -51
  277. package/src/credential-execution/executable-discovery.ts +2 -2
  278. package/src/daemon/approved-devices-store.ts +2 -2
  279. package/src/daemon/assistant-attachments.ts +2 -0
  280. package/src/daemon/config-watcher.ts +4 -50
  281. package/src/daemon/conversation-agent-loop-handlers.ts +9 -1
  282. package/src/daemon/conversation-agent-loop.ts +12 -0
  283. package/src/daemon/conversation-error.ts +3 -5
  284. package/src/daemon/conversation-history.ts +7 -3
  285. package/src/daemon/conversation-lifecycle.ts +16 -0
  286. package/src/daemon/conversation-messaging.ts +1 -0
  287. package/src/daemon/conversation-notifiers.ts +67 -30
  288. package/src/daemon/conversation-process.ts +161 -2
  289. package/src/daemon/conversation-queue-manager.ts +2 -0
  290. package/src/daemon/conversation-runtime-assembly.ts +33 -11
  291. package/src/daemon/conversation-slash.ts +14 -3
  292. package/src/daemon/conversation-tool-setup.ts +2 -0
  293. package/src/daemon/conversation-usage.ts +32 -4
  294. package/src/daemon/conversation.ts +33 -1
  295. package/src/daemon/daemon-control.ts +32 -16
  296. package/src/daemon/date-context.ts +47 -45
  297. package/src/daemon/dictation-profile-store.ts +2 -2
  298. package/src/daemon/handlers/conversations.ts +19 -0
  299. package/src/daemon/handlers/shared.ts +14 -21
  300. package/src/daemon/lifecycle.ts +5 -7
  301. package/src/daemon/message-types/conversations.ts +2 -0
  302. package/src/daemon/message-types/guardian-actions.ts +3 -17
  303. package/src/daemon/message-types/integrations.ts +11 -1
  304. package/src/daemon/message-types/messages.ts +1 -0
  305. package/src/daemon/pairing-store.ts +2 -79
  306. package/src/daemon/server.ts +154 -8
  307. package/src/daemon/watch-handler.ts +65 -21
  308. package/src/email/guardrails.ts +3 -3
  309. package/src/heartbeat/heartbeat-service.ts +14 -7
  310. package/src/hooks/cli.ts +2 -2
  311. package/src/hooks/config.ts +2 -2
  312. package/src/hooks/discovery.ts +2 -2
  313. package/src/hooks/manager.ts +2 -2
  314. package/src/hooks/runner.ts +5 -2
  315. package/src/hooks/templates.ts +2 -2
  316. package/src/memory/admin.ts +181 -2
  317. package/src/memory/app-git-service.ts +61 -4
  318. package/src/memory/attachments-store.ts +2 -0
  319. package/src/memory/canonical-guardian-store.ts +16 -0
  320. package/src/memory/db-init.ts +8 -0
  321. package/src/memory/embedding-local.ts +5 -2
  322. package/src/memory/indexer.ts +44 -26
  323. package/src/memory/items-extractor.ts +34 -82
  324. package/src/memory/job-handlers/batch-extraction.ts +741 -0
  325. package/src/memory/job-handlers/journal-carry-forward.test.ts +383 -0
  326. package/src/memory/job-handlers/journal-carry-forward.ts +255 -0
  327. package/src/memory/jobs-store.ts +28 -0
  328. package/src/memory/jobs-worker.ts +56 -9
  329. package/src/memory/lifecycle-events-store.ts +4 -2
  330. package/src/memory/llm-request-log-store.ts +40 -2
  331. package/src/memory/llm-usage-store.ts +4 -3
  332. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +71 -0
  333. package/src/memory/migrations/200-usage-llm-call-count.ts +20 -0
  334. package/src/memory/migrations/index.ts +2 -0
  335. package/src/memory/query-expansion.ts +83 -0
  336. package/src/memory/retriever.test.ts +119 -0
  337. package/src/memory/retriever.ts +513 -105
  338. package/src/memory/schema/guardian.ts +4 -0
  339. package/src/memory/schema/infrastructure.ts +1 -0
  340. package/src/memory/search/formatting.test.ts +140 -0
  341. package/src/memory/search/formatting.ts +143 -198
  342. package/src/memory/search/mmr.ts +136 -0
  343. package/src/memory/search/staleness.ts +0 -15
  344. package/src/memory/search/tier-classifier.ts +10 -21
  345. package/src/memory/search/types.ts +17 -0
  346. package/src/messaging/providers/slack/adapter.ts +51 -5
  347. package/src/notifications/broadcaster.ts +13 -0
  348. package/src/notifications/copy-composer.ts +8 -0
  349. package/src/oauth/connect-orchestrator.ts +1 -1
  350. package/src/oauth/connection-resolver.ts +2 -2
  351. package/src/oauth/provider-serializer.ts +116 -0
  352. package/src/permissions/trust-store.ts +24 -7
  353. package/src/prompts/__tests__/build-cli-reference-section.test.ts +5 -0
  354. package/src/prompts/journal-context.ts +50 -35
  355. package/src/prompts/persona-resolver.ts +1 -1
  356. package/src/prompts/system-prompt.ts +27 -28
  357. package/src/prompts/templates/BOOTSTRAP.md +14 -1
  358. package/src/prompts/templates/HEARTBEAT.md +10 -0
  359. package/src/prompts/templates/NOW.md +19 -25
  360. package/src/prompts/templates/SOUL.md +13 -1
  361. package/src/prompts/templates/UPDATES.md +12 -0
  362. package/src/prompts/update-bulletin.ts +1 -1
  363. package/src/providers/anthropic/client.ts +89 -18
  364. package/src/providers/model-catalog.ts +22 -2
  365. package/src/providers/model-intents.ts +2 -2
  366. package/src/providers/openai/client.ts +40 -1
  367. package/src/providers/retry.ts +23 -4
  368. package/src/providers/types.ts +2 -0
  369. package/src/runtime/assistant-scope.ts +1 -1
  370. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -0
  371. package/src/runtime/auth/route-policy.ts +1 -0
  372. package/src/runtime/auth/token-service.ts +51 -29
  373. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -1
  374. package/src/runtime/guardian-decision-types.ts +16 -10
  375. package/src/runtime/http-server.ts +3 -14
  376. package/src/runtime/http-types.ts +1 -0
  377. package/src/runtime/migrations/vbundle-builder.ts +7 -4
  378. package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -4
  379. package/src/runtime/migrations/vbundle-importer.ts +1 -1
  380. package/src/runtime/routes/conversation-query-routes.ts +40 -8
  381. package/src/runtime/routes/conversation-routes.ts +125 -3
  382. package/src/runtime/routes/guardian-action-routes.ts +9 -3
  383. package/src/runtime/routes/identity-routes.ts +25 -4
  384. package/src/runtime/routes/llm-context-normalization.ts +1 -0
  385. package/src/runtime/routes/log-export-routes.ts +34 -12
  386. package/src/runtime/routes/migration-routes.ts +6 -10
  387. package/src/runtime/routes/oauth-apps.ts +2 -9
  388. package/src/runtime/routes/oauth-providers.ts +60 -0
  389. package/src/runtime/routes/pairing-routes.ts +0 -8
  390. package/src/runtime/routes/settings-routes.ts +0 -1
  391. package/src/runtime/routes/telemetry-routes.ts +16 -4
  392. package/src/security/encrypted-store.ts +2 -2
  393. package/src/security/secret-allowlist.ts +3 -3
  394. package/src/signals/emit-event.ts +42 -0
  395. package/src/signals/user-message.ts +37 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +83 -19
  397. package/src/telemetry/usage-telemetry-reporter.ts +23 -17
  398. package/src/tools/browser/runtime-check.ts +2 -2
  399. package/src/tools/credentials/vault.ts +2 -249
  400. package/src/tools/memory/definitions.ts +1 -1
  401. package/src/tools/memory/handlers.test.ts +50 -8
  402. package/src/tools/memory/handlers.ts +3 -1
  403. package/src/tools/side-effects.ts +1 -6
  404. package/src/tools/terminal/safe-env.ts +3 -2
  405. package/src/tools/terminal/shell.ts +11 -14
  406. package/src/tools/tool-approval-handler.ts +20 -1
  407. package/src/tools/tool-input-summary.ts +66 -0
  408. package/src/tools/types.ts +4 -0
  409. package/src/usage/types.ts +4 -0
  410. package/src/util/device-id.ts +10 -10
  411. package/src/util/platform.ts +71 -33
  412. package/src/util/pricing.ts +19 -6
  413. package/src/util/strip-comment-lines.ts +28 -0
  414. package/src/workspace/git-service.ts +8 -18
  415. package/src/workspace/migrations/003-seed-device-id.ts +6 -4
  416. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +7 -1
  417. package/src/workspace/migrations/017-seed-persona-dirs.ts +2 -4
  418. package/src/workspace/migrations/021-move-signals-to-workspace.ts +84 -0
  419. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +94 -0
  420. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +86 -0
  421. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +126 -0
  422. package/src/workspace/migrations/migrate-to-workspace-volume.ts +3 -6
  423. package/src/workspace/migrations/registry.ts +8 -0
  424. package/src/signals/confirm.ts +0 -82
  425. package/src/signals/trust-rule.ts +0 -174
@@ -41,11 +41,70 @@ mock.module("../config/bundled-skills/messaging/tools/shared.js", () => ({
41
41
  extractEmail: (a: string) => a.toLowerCase(),
42
42
  }));
43
43
 
44
+ // ── Cross-post dependency mocks ──
45
+
46
+ const addMessageMock = mock(
47
+ async (
48
+ conversationId: string,
49
+ role: string,
50
+ content: string,
51
+ _metadata?: Record<string, unknown>,
52
+ _opts?: { skipIndexing?: boolean },
53
+ ) => ({
54
+ id: "xpost-msg-1",
55
+ conversationId,
56
+ role,
57
+ content,
58
+ createdAt: Date.now(),
59
+ }),
60
+ );
61
+
62
+ const getConversationMock = mock(
63
+ (_id: string) => null as { id: string; createdAt: number } | null,
64
+ );
65
+
66
+ const syncMessageToDiskMock = mock(
67
+ (
68
+ _conversationId: string,
69
+ _messageId: string,
70
+ _createdAtMs: number,
71
+ ) => {},
72
+ );
73
+
74
+ const getBindingByChannelChatMock = mock(
75
+ (_sourceChannel: string, _externalChatId: string) =>
76
+ null as { conversationId: string; sourceChannel: string; externalChatId: string } | null,
77
+ );
78
+
79
+ mock.module("../memory/conversation-crud.js", () => ({
80
+ addMessage: addMessageMock,
81
+ getConversation: getConversationMock,
82
+ }));
83
+
84
+ mock.module("../memory/conversation-disk-view.js", () => ({
85
+ syncMessageToDisk: syncMessageToDiskMock,
86
+ }));
87
+
88
+ mock.module("../memory/external-conversation-store.js", () => ({
89
+ getBindingByChannelChat: getBindingByChannelChatMock,
90
+ }));
91
+
92
+ mock.module("../util/logger.js", () => ({
93
+ getLogger: () =>
94
+ new Proxy({} as Record<string, unknown>, {
95
+ get: () => () => {},
96
+ }),
97
+ }));
98
+
44
99
  import { run } from "../config/bundled-skills/messaging/tools/messaging-send.js";
45
100
 
46
101
  describe("messaging-send tool", () => {
47
102
  beforeEach(() => {
48
103
  sendMessageMock.mockClear();
104
+ addMessageMock.mockClear();
105
+ getConversationMock.mockClear();
106
+ syncMessageToDiskMock.mockClear();
107
+ getBindingByChannelChatMock.mockClear();
49
108
  });
50
109
 
51
110
  test("passes assistantId from tool context to provider send options", async () => {
@@ -106,4 +165,146 @@ describe("messaging-send tool", () => {
106
165
  },
107
166
  );
108
167
  });
168
+
169
+ test("cross-posts outbound message to bound conversation", async () => {
170
+ getBindingByChannelChatMock.mockImplementation(() => ({
171
+ conversationId: "bound-conv-99",
172
+ sourceChannel: "phone",
173
+ externalChatId: "+15550004444",
174
+ }));
175
+ getConversationMock.mockImplementation(() => ({
176
+ id: "bound-conv-99",
177
+ createdAt: 1700000000000,
178
+ }));
179
+
180
+ const result = await run(
181
+ {
182
+ platform: "phone",
183
+ conversation_id: "+15550004444",
184
+ text: "hello from A",
185
+ },
186
+ {
187
+ workingDir: "/tmp",
188
+ conversationId: "conv-A",
189
+ assistantId: "ast-1",
190
+ trustClass: "guardian" as const,
191
+ },
192
+ );
193
+
194
+ expect(result.isError).toBe(false);
195
+ expect(addMessageMock).toHaveBeenCalledWith(
196
+ "bound-conv-99",
197
+ "assistant",
198
+ JSON.stringify([{ type: "text", text: "hello from A" }]),
199
+ { automated: true, crossPostedFrom: "conv-A" },
200
+ { skipIndexing: true },
201
+ );
202
+ expect(syncMessageToDiskMock).toHaveBeenCalledWith(
203
+ "bound-conv-99",
204
+ "xpost-msg-1",
205
+ 1700000000000,
206
+ );
207
+ });
208
+
209
+ test("does not cross-post when bound conversation is the sender", async () => {
210
+ getBindingByChannelChatMock.mockImplementation(() => ({
211
+ conversationId: "conv-A",
212
+ sourceChannel: "phone",
213
+ externalChatId: "+15550004444",
214
+ }));
215
+
216
+ await run(
217
+ {
218
+ platform: "phone",
219
+ conversation_id: "+15550004444",
220
+ text: "hello",
221
+ },
222
+ {
223
+ workingDir: "/tmp",
224
+ conversationId: "conv-A",
225
+ assistantId: "ast-1",
226
+ trustClass: "guardian" as const,
227
+ },
228
+ );
229
+
230
+ expect(addMessageMock).not.toHaveBeenCalled();
231
+ });
232
+
233
+ test("does not cross-post when no binding exists", async () => {
234
+ getBindingByChannelChatMock.mockImplementation(() => null);
235
+
236
+ await run(
237
+ {
238
+ platform: "phone",
239
+ conversation_id: "+15550004444",
240
+ text: "hello",
241
+ },
242
+ {
243
+ workingDir: "/tmp",
244
+ conversationId: "conv-A",
245
+ assistantId: "ast-1",
246
+ trustClass: "guardian" as const,
247
+ },
248
+ );
249
+
250
+ expect(addMessageMock).not.toHaveBeenCalled();
251
+ });
252
+
253
+ test("cross-post failure does not fail the send", async () => {
254
+ getBindingByChannelChatMock.mockImplementation(() => ({
255
+ conversationId: "bound-conv-99",
256
+ sourceChannel: "phone",
257
+ externalChatId: "+15550004444",
258
+ }));
259
+ getConversationMock.mockImplementation(() => ({
260
+ id: "bound-conv-99",
261
+ createdAt: 1700000000000,
262
+ }));
263
+ addMessageMock.mockImplementation(async () => {
264
+ throw new Error("DB write failed");
265
+ });
266
+
267
+ const result = await run(
268
+ {
269
+ platform: "phone",
270
+ conversation_id: "+15550004444",
271
+ text: "hello",
272
+ },
273
+ {
274
+ workingDir: "/tmp",
275
+ conversationId: "conv-A",
276
+ assistantId: "ast-1",
277
+ trustClass: "guardian" as const,
278
+ },
279
+ );
280
+
281
+ expect(result.isError).toBe(false);
282
+ expect(result.content).toContain("Message sent");
283
+ });
284
+
285
+ test("does not cross-post when bound conversation no longer exists", async () => {
286
+ getBindingByChannelChatMock.mockImplementation(() => ({
287
+ conversationId: "deleted-conv",
288
+ sourceChannel: "phone",
289
+ externalChatId: "+15550004444",
290
+ }));
291
+ getConversationMock.mockImplementation(() => null);
292
+
293
+ await run(
294
+ {
295
+ platform: "phone",
296
+ conversation_id: "+15550004444",
297
+ text: "hello",
298
+ },
299
+ {
300
+ workingDir: "/tmp",
301
+ conversationId: "conv-A",
302
+ assistantId: "ast-1",
303
+ trustClass: "guardian" as const,
304
+ },
305
+ );
306
+
307
+ expect(getBindingByChannelChatMock).toHaveBeenCalled();
308
+ expect(addMessageMock).not.toHaveBeenCalled();
309
+ });
109
310
  });
@@ -58,7 +58,7 @@ const testDbPath = join(testDbDir, "assistant.db");
58
58
  const testConfigPath = join(testDir, "config.json");
59
59
 
60
60
  mock.module("../util/platform.js", () => ({
61
- getRootDir: () => testDir,
61
+ getProtectedDir: () => join(testDir, "protected"),
62
62
  getDataDir: () => join(testDir, "data"),
63
63
  getWorkspaceDir: () => testDir,
64
64
  getWorkspaceConfigPath: () => testConfigPath,
@@ -78,6 +78,12 @@ mock.module("../util/logger.js", () => ({
78
78
  }),
79
79
  }));
80
80
 
81
+ mock.module("../permissions/trust-store.js", () => ({
82
+ getAllRules: () => [],
83
+ isStarterBundleAccepted: () => false,
84
+ clearCache: () => {},
85
+ }));
86
+
81
87
  mock.module("../config/loader.js", () => ({
82
88
  getConfig: () => ({
83
89
  ui: {},
@@ -445,7 +451,7 @@ describe("schema version compatibility", () => {
445
451
  { schema_version: "3.0" },
446
452
  );
447
453
 
448
- const resolver = new DefaultPathResolver(undefined, testDir);
454
+ const resolver = new DefaultPathResolver(testDir);
449
455
  const result = commitImport({
450
456
  archiveData: vbundle,
451
457
  pathResolver: resolver,
@@ -463,7 +469,7 @@ describe("schema version compatibility", () => {
463
469
  schema_version: "5.0-beta",
464
470
  });
465
471
 
466
- const resolver = new DefaultPathResolver(undefined, testDir);
472
+ const resolver = new DefaultPathResolver(testDir);
467
473
  const validationResult = validateVBundle(vbundle);
468
474
  expect(validationResult.manifest).toBeDefined();
469
475
 
@@ -830,7 +836,7 @@ describe("round-trip: export -> validate -> preflight -> import", () => {
830
836
  );
831
837
 
832
838
  // Step 3: Analyze (preflight)
833
- const resolver = new DefaultPathResolver(undefined, testDir);
839
+ const resolver = new DefaultPathResolver(testDir);
834
840
  const report = analyzeImport({
835
841
  manifest: validationResult.manifest!,
836
842
  pathResolver: resolver,
@@ -899,7 +905,7 @@ describe("partial failure scenarios", () => {
899
905
  "I am a file, not a directory",
900
906
  );
901
907
 
902
- const resolver = new DefaultPathResolver(undefined, blockerWorkspace);
908
+ const resolver = new DefaultPathResolver(blockerWorkspace);
903
909
  const result = commitImport({
904
910
  archiveData: vbundle,
905
911
  pathResolver: resolver,
@@ -917,7 +923,7 @@ describe("partial failure scenarios", () => {
917
923
  });
918
924
 
919
925
  test("commitImport with invalid archive returns validation_failed", () => {
920
- const resolver = new DefaultPathResolver(undefined, testDir);
926
+ const resolver = new DefaultPathResolver(testDir);
921
927
  const result = commitImport({
922
928
  archiveData: new Uint8Array([0xba, 0xad, 0xf0, 0x0d]),
923
929
  pathResolver: resolver,
@@ -1005,7 +1011,7 @@ describe("partial failure scenarios", () => {
1005
1011
  ]);
1006
1012
  const corruptVBundle = gzipSync(tar);
1007
1013
 
1008
- const resolver = new DefaultPathResolver(undefined, testDir);
1014
+ const resolver = new DefaultPathResolver(testDir);
1009
1015
  const result = commitImport({
1010
1016
  archiveData: corruptVBundle,
1011
1017
  pathResolver: resolver,
@@ -1037,7 +1043,7 @@ describe("edge cases", () => {
1037
1043
  expect(result.manifest?.files[0].size).toBe(0);
1038
1044
 
1039
1045
  // Import should also succeed
1040
- const resolver = new DefaultPathResolver(undefined, testDir);
1046
+ const resolver = new DefaultPathResolver(testDir);
1041
1047
  const importResult = commitImport({
1042
1048
  archiveData: vbundle,
1043
1049
  pathResolver: resolver,
@@ -1427,7 +1433,7 @@ describe("diagnostic quality", () => {
1427
1433
  });
1428
1434
 
1429
1435
  test("import commit validation_failed response includes error codes and messages", () => {
1430
- const resolver = new DefaultPathResolver(undefined, testDir);
1436
+ const resolver = new DefaultPathResolver(testDir);
1431
1437
  const result = commitImport({
1432
1438
  archiveData: new Uint8Array([0x00]),
1433
1439
  pathResolver: resolver,
@@ -1636,7 +1642,7 @@ describe("builder -> validator consistency", () => {
1636
1642
 
1637
1643
  describe("import analyzer edge cases", () => {
1638
1644
  test("all-unchanged files produce correct summary", () => {
1639
- const resolver = new DefaultPathResolver(undefined, testDir);
1645
+ const resolver = new DefaultPathResolver(testDir);
1640
1646
  const existingConfig = new Uint8Array(readFileSync(testConfigPath));
1641
1647
 
1642
1648
  const report = analyzeImport({
@@ -1669,7 +1675,6 @@ describe("import analyzer edge cases", () => {
1669
1675
 
1670
1676
  test("all-create scenario (fresh install) produces correct summary", () => {
1671
1677
  const resolver = new DefaultPathResolver(
1672
- undefined,
1673
1678
  join(testDir, "nonexistent-workspace"),
1674
1679
  );
1675
1680
 
@@ -1701,7 +1706,7 @@ describe("import analyzer edge cases", () => {
1701
1706
  });
1702
1707
 
1703
1708
  test("mixed create/overwrite/unchanged produces accurate counts", () => {
1704
- const resolver = new DefaultPathResolver(undefined, testDir);
1709
+ const resolver = new DefaultPathResolver(testDir);
1705
1710
 
1706
1711
  // db: different from disk -> overwrite
1707
1712
  // config: same as disk -> unchanged
@@ -1734,7 +1739,7 @@ describe("import analyzer edge cases", () => {
1734
1739
  });
1735
1740
 
1736
1741
  test("unknown archive path produces UNKNOWN_ARCHIVE_PATH conflict", () => {
1737
- const resolver = new DefaultPathResolver(undefined, testDir);
1742
+ const resolver = new DefaultPathResolver(testDir);
1738
1743
 
1739
1744
  const report = analyzeImport({
1740
1745
  manifest: {
@@ -32,7 +32,7 @@ const testDbPath = join(testDbDir, "assistant.db");
32
32
  const testConfigPath = join(testDir, "config.json");
33
33
 
34
34
  mock.module("../util/platform.js", () => ({
35
- getRootDir: () => testDir,
35
+ getProtectedDir: () => join(testDir, "protected"),
36
36
  getDataDir: () => join(testDir, "data"),
37
37
  getWorkspaceDir: () => testDir,
38
38
  getWorkspaceConfigPath: () => testConfigPath,
@@ -52,6 +52,12 @@ mock.module("../util/logger.js", () => ({
52
52
  }),
53
53
  }));
54
54
 
55
+ mock.module("../permissions/trust-store.js", () => ({
56
+ getAllRules: () => [],
57
+ isStarterBundleAccepted: () => false,
58
+ clearCache: () => {},
59
+ }));
60
+
55
61
  mock.module("../config/loader.js", () => ({
56
62
  getConfig: () => ({
57
63
  ui: {},
@@ -53,7 +53,7 @@ const testDbPath = join(testDbDir, "assistant.db");
53
53
  const testConfigPath = join(testDir, "config.json");
54
54
 
55
55
  mock.module("../util/platform.js", () => ({
56
- getRootDir: () => testDir,
56
+ getProtectedDir: () => join(testDir, "protected"),
57
57
  getDataDir: () => join(testDir, "data"),
58
58
  getWorkspaceDir: () => testDir,
59
59
  getWorkspaceConfigPath: () => testConfigPath,
@@ -73,6 +73,12 @@ mock.module("../util/logger.js", () => ({
73
73
  }),
74
74
  }));
75
75
 
76
+ mock.module("../permissions/trust-store.js", () => ({
77
+ getAllRules: () => [],
78
+ isStarterBundleAccepted: () => false,
79
+ clearCache: () => {},
80
+ }));
81
+
76
82
  mock.module("../config/loader.js", () => ({
77
83
  getConfig: () => ({
78
84
  ui: {},
@@ -639,7 +645,7 @@ describe("commitImport", () => {
639
645
  { path: "data/db/assistant.db", data: newDbData },
640
646
  ]);
641
647
 
642
- const resolver = new DefaultPathResolver(undefined, testDir);
648
+ const resolver = new DefaultPathResolver(testDir);
643
649
  const result = commitImport({
644
650
  archiveData: vbundle,
645
651
  pathResolver: resolver,
@@ -653,7 +659,7 @@ describe("commitImport", () => {
653
659
  });
654
660
 
655
661
  test("returns validation_failed for invalid bundles", () => {
656
- const resolver = new DefaultPathResolver(undefined, testDir);
662
+ const resolver = new DefaultPathResolver(testDir);
657
663
  const result = commitImport({
658
664
  archiveData: new Uint8Array([0xba, 0xad]),
659
665
  pathResolver: resolver,
@@ -683,7 +689,7 @@ describe("commitImport", () => {
683
689
  { path: "data/db/assistant.db", data: dbData },
684
690
  ]);
685
691
 
686
- const resolver = new DefaultPathResolver(undefined, nonexistentWorkspace);
692
+ const resolver = new DefaultPathResolver(nonexistentWorkspace);
687
693
  const result = commitImport({
688
694
  archiveData: vbundle,
689
695
  pathResolver: resolver,
@@ -707,7 +713,7 @@ describe("commitImport", () => {
707
713
  { path: "data/db/assistant.db", data: newDbData },
708
714
  ]);
709
715
 
710
- const resolver = new DefaultPathResolver(undefined, testDir);
716
+ const resolver = new DefaultPathResolver(testDir);
711
717
  const result = commitImport({
712
718
  archiveData: vbundle,
713
719
  pathResolver: resolver,
@@ -737,7 +743,7 @@ describe("commitImport", () => {
737
743
  { path: "config/settings.json", data: newConfigData },
738
744
  ]);
739
745
 
740
- const resolver = new DefaultPathResolver(undefined, testDir);
746
+ const resolver = new DefaultPathResolver(testDir);
741
747
  const result = commitImport({
742
748
  archiveData: vbundle,
743
749
  pathResolver: resolver,
@@ -785,7 +791,7 @@ describe("commitImport — workspace clearing", () => {
785
791
  { path: "workspace/skills/new-skill/SKILL.md", data: skillData },
786
792
  ]);
787
793
 
788
- const resolver = new DefaultPathResolver(undefined, testDir);
794
+ const resolver = new DefaultPathResolver(testDir);
789
795
  const result = commitImport({
790
796
  archiveData: vbundle,
791
797
  pathResolver: resolver,
@@ -814,7 +820,7 @@ describe("commitImport — workspace clearing", () => {
814
820
  { path: "skills/new-skill/SKILL.md", data: skillData },
815
821
  ]);
816
822
 
817
- const resolver = new DefaultPathResolver(undefined, testDir);
823
+ const resolver = new DefaultPathResolver(testDir);
818
824
  const result = commitImport({
819
825
  archiveData: vbundle,
820
826
  pathResolver: resolver,
@@ -841,11 +847,7 @@ describe("commitImport — workspace clearing", () => {
841
847
  { path: "hooks/new-hook/hook.sh", data: hookData },
842
848
  ]);
843
849
 
844
- const resolver = new DefaultPathResolver(
845
- undefined,
846
- testDir,
847
- externalHooksDir,
848
- );
850
+ const resolver = new DefaultPathResolver(testDir, externalHooksDir);
849
851
  const result = commitImport({
850
852
  archiveData: vbundle,
851
853
  pathResolver: resolver,
@@ -881,7 +883,7 @@ describe("commitImport — workspace clearing", () => {
881
883
  },
882
884
  ]);
883
885
 
884
- const resolver = new DefaultPathResolver(undefined, testDir);
886
+ const resolver = new DefaultPathResolver(testDir);
885
887
  // No workspaceDir — no clearing
886
888
  const result = commitImport({
887
889
  archiveData: vbundle,
@@ -39,7 +39,7 @@ const testDbPath = join(testDbDir, "assistant.db");
39
39
  const testConfigPath = join(testDir, "config.json");
40
40
 
41
41
  mock.module("../util/platform.js", () => ({
42
- getRootDir: () => testDir,
42
+ getProtectedDir: () => join(testDir, "protected"),
43
43
  getDataDir: () => join(testDir, "data"),
44
44
  getWorkspaceDir: () => testDir,
45
45
  getWorkspaceConfigPath: () => testConfigPath,
@@ -59,6 +59,12 @@ mock.module("../util/logger.js", () => ({
59
59
  }),
60
60
  }));
61
61
 
62
+ mock.module("../permissions/trust-store.js", () => ({
63
+ getAllRules: () => [],
64
+ isStarterBundleAccepted: () => false,
65
+ clearCache: () => {},
66
+ }));
67
+
62
68
  mock.module("../config/loader.js", () => ({
63
69
  getConfig: () => ({
64
70
  ui: {},
@@ -525,7 +531,6 @@ describe("handleMigrationImportPreflight — validation failures", () => {
525
531
  describe("analyzeImport", () => {
526
532
  test("detects create when file does not exist on disk", () => {
527
533
  const resolver = new DefaultPathResolver(
528
- undefined,
529
534
  join(testDir, "nonexistent-workspace"),
530
535
  );
531
536
 
@@ -553,7 +558,7 @@ describe("analyzeImport", () => {
553
558
  });
554
559
 
555
560
  test("detects unchanged when file on disk matches bundle", () => {
556
- const resolver = new DefaultPathResolver(undefined, testDir);
561
+ const resolver = new DefaultPathResolver(testDir);
557
562
 
558
563
  const report = analyzeImport({
559
564
  manifest: {
@@ -577,7 +582,7 @@ describe("analyzeImport", () => {
577
582
  });
578
583
 
579
584
  test("detects overwrite when file on disk differs from bundle", () => {
580
- const resolver = new DefaultPathResolver(undefined, testDir);
585
+ const resolver = new DefaultPathResolver(testDir);
581
586
 
582
587
  const report = analyzeImport({
583
588
  manifest: {
@@ -602,7 +607,7 @@ describe("analyzeImport", () => {
602
607
  });
603
608
 
604
609
  test("flags unknown archive paths as conflicts with skip action", () => {
605
- const resolver = new DefaultPathResolver(undefined, testDir);
610
+ const resolver = new DefaultPathResolver(testDir);
606
611
 
607
612
  const report = analyzeImport({
608
613
  manifest: {
@@ -640,7 +645,7 @@ describe("analyzeImport", () => {
640
645
  });
641
646
 
642
647
  test("includes manifest in report", () => {
643
- const resolver = new DefaultPathResolver(undefined, testDir);
648
+ const resolver = new DefaultPathResolver(testDir);
644
649
  const manifest = {
645
650
  schema_version: "1.0",
646
651
  created_at: "2024-01-01T00:00:00.000Z",
@@ -667,82 +672,60 @@ describe("analyzeImport", () => {
667
672
  // DefaultPathResolver unit tests
668
673
  // ---------------------------------------------------------------------------
669
674
 
675
+ const WORKSPACE_DIR = "/home/user/.vellum/workspace";
676
+
670
677
  describe("DefaultPathResolver", () => {
671
678
  test("resolves data/db/assistant.db to workspace db path (backward compat)", () => {
672
- const resolver = new DefaultPathResolver(
673
- undefined,
674
- "/home/user/.vellum/workspace",
675
- );
679
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
676
680
  expect(resolver.resolve("data/db/assistant.db")).toBe(
677
- "/home/user/.vellum/workspace/data/db/assistant.db",
681
+ `${WORKSPACE_DIR}/data/db/assistant.db`,
678
682
  );
679
683
  });
680
684
 
681
685
  test("resolves config/settings.json to workspace config path (backward compat)", () => {
682
- const resolver = new DefaultPathResolver(
683
- undefined,
684
- "/home/user/.vellum/workspace",
685
- );
686
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
686
687
  expect(resolver.resolve("config/settings.json")).toBe(
687
- "/home/user/.vellum/workspace/config.json",
688
+ `${WORKSPACE_DIR}/config.json`,
688
689
  );
689
690
  });
690
691
 
691
692
  test("returns null for unknown paths", () => {
692
- const resolver = new DefaultPathResolver(
693
- undefined,
694
- "/home/user/.vellum/workspace",
695
- );
693
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
696
694
  expect(resolver.resolve("unknown/path.txt")).toBeNull();
697
695
  });
698
696
 
699
697
  test("resolves valid skills path via backward compat", () => {
700
- const resolver = new DefaultPathResolver(
701
- undefined,
702
- "/home/user/.vellum/workspace",
703
- );
698
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
704
699
  expect(resolver.resolve("skills/my-skill/SKILL.md")).toBe(
705
- "/home/user/.vellum/workspace/skills/my-skill/SKILL.md",
700
+ `${WORKSPACE_DIR}/skills/my-skill/SKILL.md`,
706
701
  );
707
702
  });
708
703
 
709
704
  test("resolves workspace/ prefix paths", () => {
710
- const resolver = new DefaultPathResolver(
711
- undefined,
712
- "/home/user/.vellum/workspace",
713
- );
705
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
714
706
  expect(resolver.resolve("workspace/data/db/assistant.db")).toBe(
715
- "/home/user/.vellum/workspace/data/db/assistant.db",
707
+ `${WORKSPACE_DIR}/data/db/assistant.db`,
716
708
  );
717
709
  expect(resolver.resolve("workspace/config.json")).toBe(
718
- "/home/user/.vellum/workspace/config.json",
710
+ `${WORKSPACE_DIR}/config.json`,
719
711
  );
720
712
  expect(resolver.resolve("workspace/skills/my-skill/SKILL.md")).toBe(
721
- "/home/user/.vellum/workspace/skills/my-skill/SKILL.md",
713
+ `${WORKSPACE_DIR}/skills/my-skill/SKILL.md`,
722
714
  );
723
715
  });
724
716
 
725
717
  test("returns null for workspace/ path traversal attempt", () => {
726
- const resolver = new DefaultPathResolver(
727
- undefined,
728
- "/home/user/.vellum/workspace",
729
- );
718
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
730
719
  expect(resolver.resolve("workspace/../../etc/passwd")).toBeNull();
731
720
  });
732
721
 
733
722
  test("returns null for skills path traversal attempt (../../etc/passwd)", () => {
734
- const resolver = new DefaultPathResolver(
735
- undefined,
736
- "/home/user/.vellum/workspace",
737
- );
723
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
738
724
  expect(resolver.resolve("skills/../../etc/passwd")).toBeNull();
739
725
  });
740
726
 
741
727
  test("returns null for skills path traversal attempt (../../../.ssh/authorized_keys)", () => {
742
- const resolver = new DefaultPathResolver(
743
- undefined,
744
- "/home/user/.vellum/workspace",
745
- );
728
+ const resolver = new DefaultPathResolver(WORKSPACE_DIR);
746
729
  expect(resolver.resolve("skills/../../../.ssh/authorized_keys")).toBeNull();
747
730
  });
748
731
 
@@ -9,11 +9,8 @@
9
9
  * - Integration: existing routes are unaffected by the new endpoint
10
10
  */
11
11
  import { createHash } from "node:crypto";
12
- import { mkdtempSync, realpathSync, rmSync } from "node:fs";
13
- import { tmpdir } from "node:os";
14
- import { join } from "node:path";
15
12
  import { gzipSync } from "node:zlib";
16
- import { afterAll, describe, expect, mock, test } from "bun:test";
13
+ import { describe, expect, mock, test } from "bun:test";
17
14
 
18
15
  /** Convert a Uint8Array to an ArrayBuffer for BodyInit compatibility. */
19
16
  function toArrayBuffer(data: Uint8Array): ArrayBuffer {
@@ -24,22 +21,6 @@ function toArrayBuffer(data: Uint8Array): ArrayBuffer {
24
21
  ) as ArrayBuffer;
25
22
  }
26
23
 
27
- const testDir = realpathSync(
28
- mkdtempSync(join(tmpdir(), "migration-validate-http-test-")),
29
- );
30
-
31
- mock.module("../util/platform.js", () => ({
32
- getRootDir: () => testDir,
33
- getDataDir: () => testDir,
34
- isMacOS: () => process.platform === "darwin",
35
- isLinux: () => process.platform === "linux",
36
- isWindows: () => process.platform === "win32",
37
- getPidPath: () => join(testDir, "test.pid"),
38
- getDbPath: () => join(testDir, "test.db"),
39
- getLogPath: () => join(testDir, "test.log"),
40
- ensureDataDir: () => {},
41
- }));
42
-
43
24
  mock.module("../util/logger.js", () => ({
44
25
  getLogger: () =>
45
26
  new Proxy({} as Record<string, unknown>, {
@@ -73,14 +54,6 @@ mock.module("../config/env.js", () => ({
73
54
  import { validateVBundle } from "../runtime/migrations/vbundle-validator.js";
74
55
  import { handleMigrationValidate } from "../runtime/routes/migration-routes.js";
75
56
 
76
- afterAll(() => {
77
- try {
78
- rmSync(testDir, { recursive: true });
79
- } catch {
80
- /* best effort */
81
- }
82
- });
83
-
84
57
  // ---------------------------------------------------------------------------
85
58
  // Tar archive builder helpers
86
59
  // ---------------------------------------------------------------------------