@vellumai/assistant 0.8.0 → 0.8.1

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 (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -0,0 +1,410 @@
1
+ /**
2
+ * Tests for workspace migration `081-backfill-bash-allowed-tools-for-injection-credentials`.
3
+ *
4
+ * After migration 080 hardened the Vercel credential (removing its
5
+ * injectionTemplates and setting allowedTools to publish tools only),
6
+ * the shell.ts policy enforcement rejects proxied bash for every OTHER
7
+ * service whose allowedTools was never populated. This migration
8
+ * backfills `"bash"` into allowedTools for credentials that have
9
+ * non-empty injectionTemplates and empty/missing allowedTools.
10
+ *
11
+ * Cases covered:
12
+ * 1. Credential with injectionTemplates and empty allowedTools gets ["bash"] added.
13
+ * 2. Credential with injectionTemplates and existing populated allowedTools is NOT modified.
14
+ * 3. Credential without injectionTemplates is NOT modified.
15
+ * 4. Vercel credential (no injectionTemplates after migration 080) is NOT modified.
16
+ * 5. Missing metadata file -> no-op.
17
+ * 6. Malformed JSON -> no-op.
18
+ * 7. Idempotent: second run is a no-op.
19
+ * 8. Multiple qualifying credentials are all backfilled.
20
+ * 9. Unrecognized future schema version -> no-op.
21
+ * 10. Non-object root -> no-op.
22
+ */
23
+
24
+ import {
25
+ existsSync,
26
+ mkdirSync,
27
+ mkdtempSync,
28
+ readFileSync,
29
+ rmSync,
30
+ statSync,
31
+ writeFileSync,
32
+ } from "node:fs";
33
+ import { tmpdir } from "node:os";
34
+ import { join } from "node:path";
35
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
36
+
37
+ import { backfillBashAllowedToolsForInjectionCredentialsMigration } from "../workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.js";
38
+
39
+ let workspaceDir: string;
40
+ let metadataPath: string;
41
+
42
+ beforeEach(() => {
43
+ workspaceDir = mkdtempSync(join(tmpdir(), "vellum-migration-081-test-"));
44
+ metadataPath = join(workspaceDir, "data", "credentials", "metadata.json");
45
+ });
46
+
47
+ afterEach(() => {
48
+ if (existsSync(workspaceDir)) {
49
+ rmSync(workspaceDir, { recursive: true, force: true });
50
+ }
51
+ });
52
+
53
+ function writeMetadata(contents: unknown): void {
54
+ mkdirSync(join(workspaceDir, "data", "credentials"), { recursive: true });
55
+ writeFileSync(metadataPath, JSON.stringify(contents, null, 2), "utf-8");
56
+ }
57
+
58
+ function readMetadata(): Record<string, unknown> {
59
+ return JSON.parse(readFileSync(metadataPath, "utf-8"));
60
+ }
61
+
62
+ /** A credential with injectionTemplates and empty allowedTools (needs backfill). */
63
+ function makeSentryCredential(
64
+ overrides?: Record<string, unknown>,
65
+ ): Record<string, unknown> {
66
+ return {
67
+ credentialId: "cred-sentry-123",
68
+ service: "sentry",
69
+ field: "auth_token",
70
+ allowedTools: [],
71
+ allowedDomains: [],
72
+ injectionTemplates: [
73
+ {
74
+ hostPattern: "sentry.io",
75
+ injectionType: "header",
76
+ headerName: "Authorization",
77
+ valuePrefix: "Bearer ",
78
+ },
79
+ ],
80
+ createdAt: 1700000000000,
81
+ updatedAt: 1700000000000,
82
+ ...overrides,
83
+ };
84
+ }
85
+
86
+ /** A credential with injectionTemplates and missing allowedTools (needs backfill). */
87
+ function makeResendCredential(): Record<string, unknown> {
88
+ return {
89
+ credentialId: "cred-resend-456",
90
+ service: "resend",
91
+ field: "api_key",
92
+ allowedDomains: [],
93
+ injectionTemplates: [
94
+ {
95
+ hostPattern: "api.resend.com",
96
+ injectionType: "header",
97
+ headerName: "Authorization",
98
+ valuePrefix: "Bearer ",
99
+ },
100
+ ],
101
+ createdAt: 1700000000000,
102
+ updatedAt: 1700000000000,
103
+ };
104
+ }
105
+
106
+ /** The Vercel credential after migration 080 (no injectionTemplates, populated allowedTools). */
107
+ function makeHardenedVercelCredential(): Record<string, unknown> {
108
+ return {
109
+ credentialId: "cred-vercel-789",
110
+ service: "vercel",
111
+ field: "api_token",
112
+ allowedTools: ["publish_page", "unpublish_page"],
113
+ allowedDomains: [],
114
+ createdAt: 1700000000000,
115
+ updatedAt: 1700000000000,
116
+ };
117
+ }
118
+
119
+ /** A credential with populated allowedTools AND injectionTemplates (should NOT be modified). */
120
+ function makeCredentialWithPopulatedAllowedTools(): Record<string, unknown> {
121
+ return {
122
+ credentialId: "cred-custom-101",
123
+ service: "custom_service",
124
+ field: "token",
125
+ allowedTools: ["custom_tool_a", "custom_tool_b"],
126
+ allowedDomains: [],
127
+ injectionTemplates: [
128
+ {
129
+ hostPattern: "custom.example.com",
130
+ injectionType: "header",
131
+ headerName: "Authorization",
132
+ valuePrefix: "Token ",
133
+ },
134
+ ],
135
+ createdAt: 1700000000000,
136
+ updatedAt: 1700000000000,
137
+ };
138
+ }
139
+
140
+ /** A credential with no injectionTemplates (should NOT be modified). */
141
+ function makeCredentialWithoutInjectionTemplates(): Record<string, unknown> {
142
+ return {
143
+ credentialId: "cred-slack-202",
144
+ service: "slack",
145
+ field: "bot_token",
146
+ allowedTools: [],
147
+ allowedDomains: ["slack.com"],
148
+ createdAt: 1700000000000,
149
+ updatedAt: 1700000000000,
150
+ };
151
+ }
152
+
153
+ describe("workspace migration 081-backfill-bash-allowed-tools-for-injection-credentials", () => {
154
+ test("has the expected id and description", () => {
155
+ expect(backfillBashAllowedToolsForInjectionCredentialsMigration.id).toBe(
156
+ "081-backfill-bash-allowed-tools-for-injection-credentials",
157
+ );
158
+ expect(
159
+ backfillBashAllowedToolsForInjectionCredentialsMigration.description,
160
+ ).toContain("bash");
161
+ });
162
+
163
+ test("credential with injectionTemplates and empty allowedTools gets bash added", () => {
164
+ writeMetadata({
165
+ version: 5,
166
+ credentials: [makeSentryCredential()],
167
+ });
168
+
169
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
170
+
171
+ const result = readMetadata();
172
+ const creds = result.credentials as Record<string, unknown>[];
173
+ expect(creds).toHaveLength(1);
174
+
175
+ const sentry = creds[0];
176
+ expect(sentry.service).toBe("sentry");
177
+ expect(sentry.allowedTools).toEqual(["bash"]);
178
+ // injectionTemplates should be preserved (not removed).
179
+ expect(sentry.injectionTemplates).toBeDefined();
180
+ expect((sentry.injectionTemplates as unknown[]).length).toBeGreaterThan(0);
181
+ // updatedAt should have been bumped.
182
+ expect(sentry.updatedAt).not.toBe(1700000000000);
183
+ // createdAt should be preserved.
184
+ expect(sentry.createdAt).toBe(1700000000000);
185
+ });
186
+
187
+ test("credential with injectionTemplates and missing allowedTools gets bash added", () => {
188
+ writeMetadata({
189
+ version: 5,
190
+ credentials: [makeResendCredential()],
191
+ });
192
+
193
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
194
+
195
+ const result = readMetadata();
196
+ const creds = result.credentials as Record<string, unknown>[];
197
+ const resend = creds[0];
198
+ expect(resend.service).toBe("resend");
199
+ expect(resend.allowedTools).toEqual(["bash"]);
200
+ });
201
+
202
+ test("credential with injectionTemplates and existing populated allowedTools is NOT modified", () => {
203
+ const original = makeCredentialWithPopulatedAllowedTools();
204
+ writeMetadata({
205
+ version: 5,
206
+ credentials: [original],
207
+ });
208
+ const before = readFileSync(metadataPath, "utf-8");
209
+
210
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
211
+
212
+ const after = readFileSync(metadataPath, "utf-8");
213
+ expect(after).toBe(before);
214
+ });
215
+
216
+ test("credential without injectionTemplates is NOT modified", () => {
217
+ writeMetadata({
218
+ version: 5,
219
+ credentials: [makeCredentialWithoutInjectionTemplates()],
220
+ });
221
+ const before = readFileSync(metadataPath, "utf-8");
222
+
223
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
224
+
225
+ const after = readFileSync(metadataPath, "utf-8");
226
+ expect(after).toBe(before);
227
+ });
228
+
229
+ test("Vercel credential (no injectionTemplates after migration 080) is NOT modified", () => {
230
+ writeMetadata({
231
+ version: 5,
232
+ credentials: [makeHardenedVercelCredential()],
233
+ });
234
+ const before = readFileSync(metadataPath, "utf-8");
235
+
236
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
237
+
238
+ const after = readFileSync(metadataPath, "utf-8");
239
+ expect(after).toBe(before);
240
+ });
241
+
242
+ test("missing metadata file is a no-op (no error, no file created)", () => {
243
+ expect(existsSync(metadataPath)).toBe(false);
244
+
245
+ expect(() =>
246
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(
247
+ workspaceDir,
248
+ ),
249
+ ).not.toThrow();
250
+
251
+ expect(existsSync(metadataPath)).toBe(false);
252
+ });
253
+
254
+ test("malformed JSON is a no-op (does not throw, leaves file alone)", () => {
255
+ mkdirSync(join(workspaceDir, "data", "credentials"), { recursive: true });
256
+ writeFileSync(metadataPath, "{not valid json", "utf-8");
257
+ const before = readFileSync(metadataPath, "utf-8");
258
+
259
+ expect(() =>
260
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(
261
+ workspaceDir,
262
+ ),
263
+ ).not.toThrow();
264
+
265
+ expect(readFileSync(metadataPath, "utf-8")).toBe(before);
266
+ });
267
+
268
+ test("idempotent: second run on backfilled file is a no-op", () => {
269
+ writeMetadata({
270
+ version: 5,
271
+ credentials: [makeSentryCredential()],
272
+ });
273
+
274
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
275
+ const afterFirst = readFileSync(metadataPath, "utf-8");
276
+ const afterFirstStat = statSync(metadataPath);
277
+
278
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
279
+ const afterSecond = readFileSync(metadataPath, "utf-8");
280
+
281
+ expect(afterSecond).toBe(afterFirst);
282
+ expect(statSync(metadataPath).mtimeMs).toBe(afterFirstStat.mtimeMs);
283
+ });
284
+
285
+ test("multiple qualifying credentials are all backfilled", () => {
286
+ writeMetadata({
287
+ version: 5,
288
+ credentials: [
289
+ makeSentryCredential(),
290
+ makeResendCredential(),
291
+ makeHardenedVercelCredential(),
292
+ makeCredentialWithPopulatedAllowedTools(),
293
+ makeCredentialWithoutInjectionTemplates(),
294
+ ],
295
+ });
296
+
297
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
298
+
299
+ const result = readMetadata();
300
+ const creds = result.credentials as Record<string, unknown>[];
301
+ expect(creds).toHaveLength(5);
302
+
303
+ // Sentry: should be backfilled.
304
+ const sentry = creds.find((c) => c.service === "sentry");
305
+ expect(sentry!.allowedTools).toEqual(["bash"]);
306
+ expect(sentry!.updatedAt).not.toBe(1700000000000);
307
+
308
+ // Resend: should be backfilled.
309
+ const resend = creds.find((c) => c.service === "resend");
310
+ expect(resend!.allowedTools).toEqual(["bash"]);
311
+ expect(resend!.updatedAt).not.toBe(1700000000000);
312
+
313
+ // Vercel: NOT modified (no injectionTemplates, populated allowedTools).
314
+ const vercel = creds.find((c) => c.service === "vercel");
315
+ expect(vercel!.allowedTools).toEqual(["publish_page", "unpublish_page"]);
316
+ expect(vercel!.updatedAt).toBe(1700000000000);
317
+
318
+ // Custom: NOT modified (populated allowedTools even though it has injectionTemplates).
319
+ const custom = creds.find((c) => c.service === "custom_service");
320
+ expect(custom!.allowedTools).toEqual(["custom_tool_a", "custom_tool_b"]);
321
+ expect(custom!.updatedAt).toBe(1700000000000);
322
+
323
+ // Slack: NOT modified (no injectionTemplates).
324
+ const slack = creds.find((c) => c.service === "slack");
325
+ expect(slack!.allowedTools).toEqual([]);
326
+ expect(slack!.updatedAt).toBe(1700000000000);
327
+ });
328
+
329
+ test("unrecognized future schema version is a no-op", () => {
330
+ writeMetadata({
331
+ version: 99,
332
+ credentials: [makeSentryCredential()],
333
+ });
334
+ const before = readFileSync(metadataPath, "utf-8");
335
+
336
+ expect(() =>
337
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(
338
+ workspaceDir,
339
+ ),
340
+ ).not.toThrow();
341
+
342
+ expect(readFileSync(metadataPath, "utf-8")).toBe(before);
343
+ });
344
+
345
+ test("non-object root is a no-op", () => {
346
+ writeMetadata([1, 2, 3]);
347
+ const before = readFileSync(metadataPath, "utf-8");
348
+
349
+ expect(() =>
350
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(
351
+ workspaceDir,
352
+ ),
353
+ ).not.toThrow();
354
+
355
+ expect(readFileSync(metadataPath, "utf-8")).toBe(before);
356
+ });
357
+
358
+ test("file with no version field defaults to version 1 and processes", () => {
359
+ writeMetadata({
360
+ credentials: [makeSentryCredential()],
361
+ });
362
+
363
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
364
+
365
+ const result = readMetadata();
366
+ const creds = result.credentials as Record<string, unknown>[];
367
+ const sentry = creds.find((c) => c.service === "sentry");
368
+ expect(sentry!.allowedTools).toEqual(["bash"]);
369
+ });
370
+
371
+ test("down() is a no-op", () => {
372
+ writeMetadata({
373
+ version: 5,
374
+ credentials: [makeSentryCredential()],
375
+ });
376
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
377
+ const after = readFileSync(metadataPath, "utf-8");
378
+
379
+ expect(() =>
380
+ backfillBashAllowedToolsForInjectionCredentialsMigration.down(
381
+ workspaceDir,
382
+ ),
383
+ ).not.toThrow();
384
+
385
+ expect(readFileSync(metadataPath, "utf-8")).toBe(after);
386
+ });
387
+
388
+ test("post-080+081 scenario: Vercel has no bash, injection services have bash", () => {
389
+ // Simulate state after migration 080 has already run:
390
+ // - Vercel: hardened (no injectionTemplates, allowedTools = publish tools)
391
+ // - Sentry: still has injectionTemplates, empty allowedTools
392
+ writeMetadata({
393
+ version: 5,
394
+ credentials: [makeHardenedVercelCredential(), makeSentryCredential()],
395
+ });
396
+
397
+ backfillBashAllowedToolsForInjectionCredentialsMigration.run(workspaceDir);
398
+
399
+ const result = readMetadata();
400
+ const creds = result.credentials as Record<string, unknown>[];
401
+
402
+ // Vercel: should still have publish tools only, no bash.
403
+ const vercel = creds.find((c) => c.service === "vercel");
404
+ expect(vercel!.allowedTools).toEqual(["publish_page", "unpublish_page"]);
405
+
406
+ // Sentry: should now have bash.
407
+ const sentry = creds.find((c) => c.service === "sentry");
408
+ expect(sentry!.allowedTools).toEqual(["bash"]);
409
+ });
410
+ });
@@ -0,0 +1,268 @@
1
+ import {
2
+ existsSync,
3
+ mkdirSync,
4
+ readFileSync,
5
+ rmSync,
6
+ writeFileSync,
7
+ } from "node:fs";
8
+ import { tmpdir } from "node:os";
9
+ import { join } from "node:path";
10
+ import { afterEach, beforeEach, describe, expect, test } from "bun:test";
11
+
12
+ import { backfillManagedProfileLabelsMigration } from "../workspace/migrations/082-backfill-managed-profile-labels.js";
13
+
14
+ let workspaceDir: string;
15
+
16
+ function freshWorkspace(): void {
17
+ workspaceDir = join(
18
+ tmpdir(),
19
+ `vellum-migration-082-test-${Date.now()}-${Math.random().toString(36).slice(2)}`,
20
+ );
21
+ mkdirSync(workspaceDir, { recursive: true });
22
+ }
23
+
24
+ function writeConfig(data: Record<string, unknown>): void {
25
+ writeFileSync(
26
+ join(workspaceDir, "config.json"),
27
+ JSON.stringify(data, null, 2) + "\n",
28
+ );
29
+ }
30
+
31
+ function readConfig(): Record<string, unknown> {
32
+ return JSON.parse(readFileSync(join(workspaceDir, "config.json"), "utf-8"));
33
+ }
34
+
35
+ beforeEach(() => {
36
+ freshWorkspace();
37
+ });
38
+
39
+ afterEach(() => {
40
+ if (existsSync(workspaceDir)) {
41
+ rmSync(workspaceDir, { recursive: true, force: true });
42
+ }
43
+ });
44
+
45
+ describe("082-backfill-managed-profile-labels migration", () => {
46
+ test("has correct migration id", () => {
47
+ expect(backfillManagedProfileLabelsMigration.id).toBe(
48
+ "082-backfill-managed-profile-labels",
49
+ );
50
+ });
51
+
52
+ test("backfills missing labels on the canonical managed triplet (Marina QA #5)", () => {
53
+ // The exact shape migration 052 writes — provider + model + numeric
54
+ // tuning fields, no label, no source, no provider_connection.
55
+ writeConfig({
56
+ llm: {
57
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
58
+ profiles: {
59
+ balanced: {
60
+ provider: "anthropic",
61
+ model: "claude-sonnet-4-6",
62
+ maxTokens: 16000,
63
+ effort: "high",
64
+ thinking: { enabled: true, streamThinking: true },
65
+ },
66
+ "quality-optimized": {
67
+ provider: "anthropic",
68
+ model: "claude-opus-4-7",
69
+ maxTokens: 32000,
70
+ effort: "max",
71
+ thinking: { enabled: true, streamThinking: true },
72
+ },
73
+ "cost-optimized": {
74
+ provider: "anthropic",
75
+ model: "claude-haiku-4-5-20251001",
76
+ maxTokens: 8192,
77
+ effort: "low",
78
+ thinking: { enabled: false, streamThinking: false },
79
+ },
80
+ },
81
+ activeProfile: "balanced",
82
+ },
83
+ });
84
+
85
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
86
+
87
+ const config = readConfig();
88
+ const profiles = (config.llm as Record<string, unknown>).profiles as Record<
89
+ string,
90
+ Record<string, unknown>
91
+ >;
92
+ expect(profiles.balanced.label).toBe("Balanced");
93
+ expect(profiles["quality-optimized"].label).toBe("Quality");
94
+ expect(profiles["cost-optimized"].label).toBe("Speed");
95
+ });
96
+
97
+ test("preserves user-set string labels without rewriting", () => {
98
+ writeConfig({
99
+ llm: {
100
+ profiles: {
101
+ balanced: {
102
+ provider: "anthropic",
103
+ model: "claude-sonnet-4-6",
104
+ label: "My Balanced",
105
+ },
106
+ "quality-optimized": {
107
+ provider: "anthropic",
108
+ model: "claude-opus-4-7",
109
+ // No label — backfills.
110
+ },
111
+ "cost-optimized": {
112
+ provider: "anthropic",
113
+ model: "claude-haiku-4-5-20251001",
114
+ label: "Speed (Managed)",
115
+ },
116
+ },
117
+ },
118
+ });
119
+
120
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
121
+
122
+ const config = readConfig();
123
+ const profiles = (config.llm as Record<string, unknown>).profiles as Record<
124
+ string,
125
+ Record<string, unknown>
126
+ >;
127
+ expect(profiles.balanced.label).toBe("My Balanced");
128
+ expect(profiles["quality-optimized"].label).toBe("Quality");
129
+ expect(profiles["cost-optimized"].label).toBe("Speed (Managed)");
130
+ });
131
+
132
+ test("preserves explicit null labels (user cleared the label)", () => {
133
+ // `null` is a meaningful signal — the user cleared the label via the
134
+ // PUT route. Treat the key as present and skip backfill.
135
+ writeConfig({
136
+ llm: {
137
+ profiles: {
138
+ balanced: {
139
+ provider: "anthropic",
140
+ model: "claude-sonnet-4-6",
141
+ label: null,
142
+ },
143
+ },
144
+ },
145
+ });
146
+
147
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
148
+
149
+ const config = readConfig();
150
+ const profiles = (config.llm as Record<string, unknown>).profiles as Record<
151
+ string,
152
+ Record<string, unknown>
153
+ >;
154
+ expect(profiles.balanced.label).toBeNull();
155
+ });
156
+
157
+ test("does NOT touch non-canonical profile names", () => {
158
+ writeConfig({
159
+ llm: {
160
+ profiles: {
161
+ "my-custom": {
162
+ provider: "openai",
163
+ model: "gpt-5.4",
164
+ // No label — must NOT be backfilled.
165
+ },
166
+ balanced: {
167
+ provider: "anthropic",
168
+ model: "claude-sonnet-4-6",
169
+ // Missing label — gets backfilled.
170
+ },
171
+ },
172
+ },
173
+ });
174
+
175
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
176
+
177
+ const config = readConfig();
178
+ const profiles = (config.llm as Record<string, unknown>).profiles as Record<
179
+ string,
180
+ Record<string, unknown>
181
+ >;
182
+ expect("label" in profiles["my-custom"]).toBe(false);
183
+ expect(profiles.balanced.label).toBe("Balanced");
184
+ });
185
+
186
+ test("is idempotent — second run produces no further changes", () => {
187
+ writeConfig({
188
+ llm: {
189
+ profiles: {
190
+ balanced: {
191
+ provider: "anthropic",
192
+ model: "claude-sonnet-4-6",
193
+ },
194
+ },
195
+ },
196
+ });
197
+
198
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
199
+ const afterFirst = readFileSync(
200
+ join(workspaceDir, "config.json"),
201
+ "utf-8",
202
+ );
203
+
204
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
205
+ const afterSecond = readFileSync(
206
+ join(workspaceDir, "config.json"),
207
+ "utf-8",
208
+ );
209
+
210
+ expect(afterSecond).toBe(afterFirst);
211
+ });
212
+
213
+ test("no-op when config.json does not exist", () => {
214
+ // Fresh workspace, no config file. Migration must not throw or create
215
+ // the file.
216
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
217
+ expect(existsSync(join(workspaceDir, "config.json"))).toBe(false);
218
+ });
219
+
220
+ test("no-op when llm.profiles is absent", () => {
221
+ writeConfig({ llm: { default: { provider: "anthropic" } } });
222
+ const before = readFileSync(join(workspaceDir, "config.json"), "utf-8");
223
+
224
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
225
+
226
+ const after = readFileSync(join(workspaceDir, "config.json"), "utf-8");
227
+ expect(after).toBe(before);
228
+ });
229
+
230
+ test("ignores malformed config.json without throwing", () => {
231
+ writeFileSync(join(workspaceDir, "config.json"), "{ not valid json");
232
+ // Should not throw.
233
+ expect(() =>
234
+ backfillManagedProfileLabelsMigration.run(workspaceDir),
235
+ ).not.toThrow();
236
+ });
237
+
238
+ test("does NOT skip when VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH is set", () => {
239
+ // Unlike the seed migrations (040/046/052/054/...), this is a forward
240
+ // data repair that runs regardless. Platform-supplied overlay labels
241
+ // already win at the profile level (the on-disk entry has a `label`
242
+ // key, so this migration leaves it alone). Skipping the whole
243
+ // migration when the env var is set would leave migration-052 holes
244
+ // unhealed on platform-style hatches.
245
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = "/tmp/overlay.json";
246
+ writeConfig({
247
+ llm: {
248
+ profiles: {
249
+ balanced: {
250
+ provider: "anthropic",
251
+ model: "claude-sonnet-4-6",
252
+ },
253
+ },
254
+ },
255
+ });
256
+
257
+ try {
258
+ backfillManagedProfileLabelsMigration.run(workspaceDir);
259
+
260
+ const config = readConfig();
261
+ const profiles = (config.llm as Record<string, unknown>)
262
+ .profiles as Record<string, Record<string, unknown>>;
263
+ expect(profiles.balanced.label).toBe("Balanced");
264
+ } finally {
265
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
266
+ }
267
+ });
268
+ });
@@ -127,9 +127,9 @@ describe("038-unify-llm-callsite-configs migration", () => {
127
127
  // if llm.default exists`) then silently skipped, and migration 039
128
128
  // stripped `services.inference.{provider,model}` — losing the user's
129
129
  // actual configuration. The fix prefers legacy source keys over the
130
- // injected schema defaults whenever both are present. (The loader
131
- // no longer writes defaults to disk, but workspaces still on disk
132
- // from that era can carry the bad state forward.)
130
+ // injected schema defaults whenever both are present. (Defaults are
131
+ // applied in-memory only; legacy workspaces may still carry the
132
+ // on-disk state from that era.)
133
133
  writeConfig({
134
134
  services: {
135
135
  inference: {