@vellumai/assistant 0.8.0 → 0.8.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (991) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +2 -7
  3. package/Dockerfile +80 -5
  4. package/README.md +2 -2
  5. package/bun.lock +11 -1
  6. package/docker-entrypoint.sh +21 -0
  7. package/docker-init-apt-root.sh +94 -0
  8. package/docker-kata-apt-env.sh +39 -0
  9. package/docs/plugins.md +88 -47
  10. package/docs/skills.md +9 -7
  11. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  12. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  13. package/eslint.config.mjs +12 -0
  14. package/examples/plugins/echo/README.md +27 -27
  15. package/examples/plugins/echo/package.json +3 -0
  16. package/examples/plugins/echo/register.ts +31 -31
  17. package/knip.json +2 -1
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/node_modules/@vellumai/slack-text/src/index.test.ts +114 -14
  20. package/node_modules/@vellumai/slack-text/src/index.ts +82 -18
  21. package/openapi.yaml +4462 -991
  22. package/package.json +5 -1
  23. package/scripts/generate-openapi.ts +135 -14
  24. package/scripts/sync-llm-catalog.ts +165 -0
  25. package/scripts/sync-web-search-catalog.ts +129 -0
  26. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  27. package/src/__tests__/agent-image-optimize.test.ts +11 -3
  28. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  29. package/src/__tests__/agent-wake-disk-pressure-callsite.test.ts +131 -0
  30. package/src/__tests__/anthropic-provider.test.ts +137 -2
  31. package/src/__tests__/app-builder-tool-scripts.test.ts +9 -3
  32. package/src/__tests__/app-control-flow.test.ts +7 -0
  33. package/src/__tests__/app-executors.test.ts +220 -4
  34. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  35. package/src/__tests__/auto-analysis-end-to-end.test.ts +35 -0
  36. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  37. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  38. package/src/__tests__/btw-routes.test.ts +1 -0
  39. package/src/__tests__/bundled-asset.test.ts +6 -6
  40. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  41. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  42. package/src/__tests__/channel-availability-routes.test.ts +206 -0
  43. package/src/__tests__/channel-delivery-store.test.ts +289 -1
  44. package/src/__tests__/channel-policy.test.ts +12 -0
  45. package/src/__tests__/checker.test.ts +89 -0
  46. package/src/__tests__/circuit-breaker-pipeline.test.ts +0 -1
  47. package/src/__tests__/clawhub.test.ts +75 -16
  48. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  49. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  50. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  51. package/src/__tests__/compactor-tail-resolution.test.ts +41 -0
  52. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  53. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  54. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  55. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  56. package/src/__tests__/config-schema.test.ts +35 -3
  57. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  58. package/src/__tests__/config-set-route.test.ts +278 -0
  59. package/src/__tests__/config-sounds-sync.test.ts +97 -0
  60. package/src/__tests__/config-watcher-skill-reseed.test.ts +453 -0
  61. package/src/__tests__/config-watcher.test.ts +6 -0
  62. package/src/__tests__/contacts-tools.test.ts +51 -199
  63. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  64. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  65. package/src/__tests__/context-search-conversations-source.test.ts +159 -18
  66. package/src/__tests__/context-search-fanout.test.ts +20 -157
  67. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -4
  68. package/src/__tests__/context-search-types.test.ts +7 -2
  69. package/src/__tests__/context-search-workspace-source.test.ts +7 -0
  70. package/src/__tests__/context-token-estimator.test.ts +1 -0
  71. package/src/__tests__/conversation-abort-tool-results.test.ts +4 -1
  72. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -0
  73. package/src/__tests__/conversation-agent-loop-overflow.test.ts +93 -92
  74. package/src/__tests__/conversation-agent-loop.test.ts +2 -0
  75. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  76. package/src/__tests__/conversation-error.test.ts +80 -3
  77. package/src/__tests__/conversation-fork-crud.test.ts +323 -1
  78. package/src/__tests__/conversation-inference-profile-route.test.ts +54 -18
  79. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  80. package/src/__tests__/conversation-lifecycle.test.ts +297 -0
  81. package/src/__tests__/conversation-message-sync-tags.test.ts +97 -0
  82. package/src/__tests__/conversation-pairing.test.ts +54 -0
  83. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  84. package/src/__tests__/conversation-process-callsite.test.ts +25 -2
  85. package/src/__tests__/conversation-provider-retry-repair.test.ts +5 -1
  86. package/src/__tests__/conversation-queue.test.ts +4 -1
  87. package/src/__tests__/conversation-runtime-assembly.test.ts +80 -13
  88. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  89. package/src/__tests__/conversation-slash-queue.test.ts +59 -1
  90. package/src/__tests__/conversation-slash-unknown.test.ts +4 -1
  91. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  92. package/src/__tests__/conversation-surfaces-table-action.test.ts +360 -0
  93. package/src/__tests__/conversation-sync-tags.test.ts +235 -0
  94. package/src/__tests__/conversation-workspace-injection.test.ts +5 -1
  95. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +5 -1
  96. package/src/__tests__/credential-security-invariants.test.ts +8 -8
  97. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  98. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  99. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  100. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  101. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  102. package/src/__tests__/db-slack-external-content-normalization.test.ts +301 -0
  103. package/src/__tests__/delete-managed-skill-tool.test.ts +55 -13
  104. package/src/__tests__/disk-pressure-tools.test.ts +1 -0
  105. package/src/__tests__/dm-backfill.test.ts +121 -10
  106. package/src/__tests__/document-tool-security.test.ts +258 -0
  107. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +0 -1
  108. package/src/__tests__/edit-propagation.test.ts +33 -0
  109. package/src/__tests__/empty-response-pipeline.test.ts +0 -4
  110. package/src/__tests__/external-plugin-loader.test.ts +482 -0
  111. package/src/__tests__/filing-service.test.ts +163 -3
  112. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  113. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  114. package/src/__tests__/get-skill-detail-audit.test.ts +0 -4
  115. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  116. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +42 -69
  117. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  118. package/src/__tests__/heartbeat-service.test.ts +50 -233
  119. package/src/__tests__/helpers/tar-fixtures.ts +39 -0
  120. package/src/__tests__/helpers/wait-for.ts +21 -0
  121. package/src/__tests__/history-repair-pipeline.test.ts +0 -3
  122. package/src/__tests__/history-repair.test.ts +162 -0
  123. package/src/__tests__/host-app-control-proxy.test.ts +365 -1
  124. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  125. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  126. package/src/__tests__/host-browser-routes.test.ts +325 -33
  127. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  128. package/src/__tests__/image-credentials.test.ts +1 -1
  129. package/src/__tests__/inbound-slack-persistence.test.ts +2 -0
  130. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  131. package/src/__tests__/inference-profile-reaper.test.ts +156 -0
  132. package/src/__tests__/inference-profile-session-handler.test.ts +410 -0
  133. package/src/__tests__/inference-profile-session-ipc.test.ts +248 -0
  134. package/src/__tests__/injector-chain.test.ts +10 -8
  135. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  136. package/src/__tests__/install-skill-routing.test.ts +157 -39
  137. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +107 -3
  138. package/src/__tests__/list-messages-page-latest.test.ts +55 -0
  139. package/src/__tests__/llm-call-pipeline.test.ts +0 -3
  140. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  141. package/src/__tests__/llm-catalog-parity.test.ts +190 -2
  142. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +222 -0
  143. package/src/__tests__/llm-request-log-source-factory.test.ts +100 -0
  144. package/src/__tests__/llm-resolver.test.ts +46 -0
  145. package/src/__tests__/llm-usage-store.test.ts +114 -0
  146. package/src/__tests__/managed-profile-guard.test.ts +145 -14
  147. package/src/__tests__/managed-skill-lifecycle.test.ts +109 -18
  148. package/src/__tests__/managed-store.test.ts +84 -192
  149. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  150. package/src/__tests__/mcp-cli.test.ts +182 -220
  151. package/src/__tests__/mcp-health-check.test.ts +56 -27
  152. package/src/__tests__/media-generate-image.test.ts +1 -1
  153. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  154. package/src/__tests__/memory-retrieval-pipeline.test.ts +0 -2
  155. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  156. package/src/__tests__/messages-after-tiebreaker.test.ts +122 -0
  157. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  158. package/src/__tests__/oauth-cli.test.ts +38 -2009
  159. package/src/__tests__/oauth-commands-routes.test.ts +863 -0
  160. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  161. package/src/__tests__/oauth-provider-profiles.test.ts +9 -0
  162. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  163. package/src/__tests__/openai-provider.test.ts +24 -0
  164. package/src/__tests__/openai-responses-cutover-guard.test.ts +48 -19
  165. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  166. package/src/__tests__/overflow-reduce-pipeline.test.ts +0 -2
  167. package/src/__tests__/persistence-pipeline.test.ts +0 -2
  168. package/src/__tests__/{managed-proxy-context.test.ts → platform-proxy-context.test.ts} +1 -1
  169. package/src/__tests__/platform.test.ts +2 -0
  170. package/src/__tests__/plugin-api-shim.test.ts +125 -0
  171. package/src/__tests__/plugin-bootstrap.test.ts +41 -38
  172. package/src/__tests__/plugin-external-api.test.ts +68 -0
  173. package/src/__tests__/plugin-registry.test.ts +0 -77
  174. package/src/__tests__/plugin-route-contribution.test.ts +31 -4
  175. package/src/__tests__/plugin-skill-contribution.test.ts +0 -2
  176. package/src/__tests__/plugin-tool-contribution.test.ts +47 -18
  177. package/src/__tests__/plugin-types.test.ts +15 -23
  178. package/src/__tests__/process-message-background-slack.test.ts +53 -0
  179. package/src/__tests__/process-message-display-content.test.ts +421 -0
  180. package/src/__tests__/profile-entry-status.test.ts +43 -0
  181. package/src/__tests__/provider-catalog-visibility.test.ts +142 -0
  182. package/src/__tests__/provider-error-scenarios.test.ts +111 -0
  183. package/src/__tests__/{provider-managed-proxy-integration.test.ts → provider-platform-proxy-integration.test.ts} +20 -12
  184. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  185. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  186. package/src/__tests__/relay-server.test.ts +118 -0
  187. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  188. package/src/__tests__/scaffold-managed-skill-tool.test.ts +65 -13
  189. package/src/__tests__/schedule-retry.test.ts +56 -4
  190. package/src/__tests__/schedule-routes.test.ts +151 -0
  191. package/src/__tests__/schedule-store.test.ts +94 -0
  192. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  193. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  194. package/src/__tests__/scheduler-reuse-conversation.test.ts +208 -5
  195. package/src/__tests__/scheduler-wake.test.ts +0 -63
  196. package/src/__tests__/schema-transforms.test.ts +20 -0
  197. package/src/__tests__/search-skills-unified.test.ts +0 -5
  198. package/src/__tests__/secret-allowlist.test.ts +1 -0
  199. package/src/__tests__/{secret-routes-managed-proxy.test.ts → secret-routes-platform-proxy.test.ts} +12 -4
  200. package/src/__tests__/server-history-render.test.ts +43 -0
  201. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  202. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  203. package/src/__tests__/skill-load-feature-flag.test.ts +1 -12
  204. package/src/__tests__/skill-load-tool.test.ts +29 -93
  205. package/src/__tests__/skill-memory.test.ts +23 -3
  206. package/src/__tests__/skills-file-content-endpoint.test.ts +9 -38
  207. package/src/__tests__/skills-files-catalog-fallback.test.ts +0 -3
  208. package/src/__tests__/skills-install-extract.test.ts +49 -38
  209. package/src/__tests__/skills-install-staging.test.ts +159 -0
  210. package/src/__tests__/skills-uninstall.test.ts +9 -41
  211. package/src/__tests__/skills.test.ts +51 -58
  212. package/src/__tests__/slack-channel-config.test.ts +9 -0
  213. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  214. package/src/__tests__/subagent-tool-filtering.test.ts +50 -0
  215. package/src/__tests__/suggestion-routes.test.ts +3 -3
  216. package/src/__tests__/sync-message-contract.test.ts +63 -0
  217. package/src/__tests__/system-prompt.test.ts +737 -63
  218. package/src/__tests__/task-scheduler.test.ts +88 -23
  219. package/src/__tests__/terminal-tools.test.ts +28 -1
  220. package/src/__tests__/thread-backfill.test.ts +557 -27
  221. package/src/__tests__/title-generate-pipeline.test.ts +0 -13
  222. package/src/__tests__/token-estimate-pipeline.test.ts +0 -3
  223. package/src/__tests__/tool-error-pipeline.test.ts +0 -3
  224. package/src/__tests__/tool-execute-pipeline.test.ts +0 -5
  225. package/src/__tests__/tool-executor-lifecycle-events.test.ts +1 -1
  226. package/src/__tests__/tool-executor.test.ts +16 -4
  227. package/src/__tests__/tool-result-truncate-pipeline.test.ts +0 -12
  228. package/src/__tests__/turn-events-store.test.ts +256 -0
  229. package/src/__tests__/twilio-routes.test.ts +4 -0
  230. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  231. package/src/__tests__/usage-cli.test.ts +11 -73
  232. package/src/__tests__/user-plugin-loader.test.ts +143 -5
  233. package/src/__tests__/vercel-config.test.ts +168 -0
  234. package/src/__tests__/voice-session-bridge.test.ts +198 -0
  235. package/src/__tests__/web-search-catalog-parity.test.ts +108 -0
  236. package/src/__tests__/web-search.test.ts +303 -2
  237. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  238. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +170 -0
  239. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  240. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +241 -0
  241. package/src/__tests__/workspace-migration-073-repair-recall-callsite-empty-profile.test.ts +153 -0
  242. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  243. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  244. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  245. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  246. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  247. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  248. package/src/__tests__/workspace-migration-085-memory-v2-bm25-b-reembed-disabled-v2-pages.test.ts +220 -0
  249. package/src/__tests__/workspace-migration-086-revert-stale-gemini-mis-rewrites.test.ts +269 -0
  250. package/src/__tests__/workspace-migration-remove-legacy-skills-index.test.ts +309 -0
  251. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  252. package/src/__tests__/workspace-migrations-runner.test.ts +111 -3
  253. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  254. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  255. package/src/acp/resolve-agent.test.ts +25 -0
  256. package/src/acp/resolve-agent.ts +13 -2
  257. package/src/acp/session-manager.ts +14 -0
  258. package/src/agent/image-optimize.ts +13 -5
  259. package/src/approvals/guardian-request-resolvers.ts +32 -87
  260. package/src/calls/relay-server.ts +35 -0
  261. package/src/calls/relay-setup-router.ts +36 -0
  262. package/src/calls/types.ts +1 -0
  263. package/src/calls/voice-session-bridge.ts +74 -36
  264. package/src/channels/config.ts +14 -1
  265. package/src/channels/types.ts +109 -0
  266. package/src/cli/AGENTS.md +164 -4
  267. package/src/cli/__tests__/notifications.test.ts +54 -0
  268. package/src/cli/__tests__/unknown-command.test.ts +24 -0
  269. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  270. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  271. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  272. package/src/cli/commands/__tests__/changelog.test.ts +578 -0
  273. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  274. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  275. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  276. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  277. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  278. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  279. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  280. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  281. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  282. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  283. package/src/cli/commands/__tests__/schedules.test.ts +491 -0
  284. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  285. package/src/cli/commands/__tests__/status.test.ts +249 -0
  286. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  287. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  288. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  289. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  290. package/src/cli/commands/attachment.ts +8 -3
  291. package/src/cli/commands/audit.ts +95 -64
  292. package/src/cli/commands/auth.ts +61 -58
  293. package/src/cli/commands/avatar.ts +276 -390
  294. package/src/cli/commands/backup.ts +409 -505
  295. package/src/cli/commands/bash.ts +9 -5
  296. package/src/cli/commands/browser.ts +28 -9
  297. package/src/cli/commands/cache.ts +9 -4
  298. package/src/cli/commands/changelog.ts +478 -0
  299. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  300. package/src/cli/commands/clients.ts +8 -3
  301. package/src/cli/commands/completions.ts +9 -9
  302. package/src/cli/commands/config.ts +102 -72
  303. package/src/cli/commands/contacts.ts +575 -696
  304. package/src/cli/commands/conversations-defer.ts +17 -69
  305. package/src/cli/commands/conversations-import.ts +90 -253
  306. package/src/cli/commands/conversations.ts +429 -434
  307. package/src/cli/commands/credential-execution.ts +9 -6
  308. package/src/cli/commands/credentials.ts +456 -736
  309. package/src/cli/commands/default-action.ts +10 -53
  310. package/src/cli/commands/domain.ts +128 -206
  311. package/src/cli/commands/email.ts +606 -794
  312. package/src/cli/commands/gateway.ts +8 -1
  313. package/src/cli/commands/image-generation.ts +157 -205
  314. package/src/cli/commands/inference-providers.ts +352 -0
  315. package/src/cli/commands/inference-session.ts +415 -0
  316. package/src/cli/commands/inference.ts +87 -65
  317. package/src/cli/commands/keys.ts +8 -3
  318. package/src/cli/commands/mcp.ts +103 -287
  319. package/src/cli/commands/memory-v2.ts +162 -516
  320. package/src/cli/commands/notifications.ts +342 -304
  321. package/src/cli/commands/oauth/apps.ts +292 -261
  322. package/src/cli/commands/oauth/connect.ts +176 -297
  323. package/src/cli/commands/oauth/disconnect.ts +16 -215
  324. package/src/cli/commands/oauth/index.ts +49 -45
  325. package/src/cli/commands/oauth/mode.ts +43 -199
  326. package/src/cli/commands/oauth/ping.ts +17 -125
  327. package/src/cli/commands/oauth/providers.ts +732 -921
  328. package/src/cli/commands/oauth/request.ts +60 -350
  329. package/src/cli/commands/oauth/shared.ts +11 -121
  330. package/src/cli/commands/oauth/status.ts +31 -121
  331. package/src/cli/commands/oauth/token.ts +13 -55
  332. package/src/cli/commands/pending.ts +19 -10
  333. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  334. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  335. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  336. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  337. package/src/cli/commands/platform/connect.ts +16 -80
  338. package/src/cli/commands/platform/disconnect.ts +14 -112
  339. package/src/cli/commands/platform/index.ts +177 -246
  340. package/src/cli/commands/plugins.ts +185 -0
  341. package/src/cli/commands/routes.ts +153 -336
  342. package/src/cli/commands/schedules.ts +391 -0
  343. package/src/cli/commands/sequence.ts +316 -360
  344. package/src/cli/commands/skills.ts +449 -671
  345. package/src/cli/commands/status.ts +58 -37
  346. package/src/cli/commands/stt.ts +94 -262
  347. package/src/cli/commands/task.ts +14 -40
  348. package/src/cli/commands/telemetry.ts +40 -0
  349. package/src/cli/commands/trust.ts +8 -3
  350. package/src/cli/commands/tts.ts +162 -167
  351. package/src/cli/commands/ui.ts +35 -42
  352. package/src/cli/commands/usage.ts +188 -126
  353. package/src/cli/commands/watchers.ts +8 -3
  354. package/src/cli/commands/webhooks.ts +99 -193
  355. package/src/cli/lib/__tests__/cli-colors.test.ts +48 -0
  356. package/src/cli/lib/__tests__/confirm-prompt.test.ts +159 -0
  357. package/src/cli/lib/__tests__/install-from-github.test.ts +355 -0
  358. package/src/cli/lib/__tests__/list-installed-plugins.test.ts +154 -0
  359. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  360. package/src/cli/lib/__tests__/uninstall-plugin.test.ts +124 -0
  361. package/src/cli/lib/__tests__/unknown-command.test.ts +106 -0
  362. package/src/cli/lib/cli-colors.ts +12 -0
  363. package/src/cli/lib/confirm-prompt.ts +79 -0
  364. package/src/cli/lib/daemon-credential-client.ts +4 -5
  365. package/src/cli/lib/install-from-github.ts +304 -0
  366. package/src/cli/lib/list-installed-plugins.ts +137 -0
  367. package/src/cli/lib/nested-value.ts +44 -0
  368. package/src/cli/lib/open-browser.ts +36 -0
  369. package/src/cli/lib/register-command.ts +19 -0
  370. package/src/cli/lib/time-ago.ts +34 -0
  371. package/src/cli/lib/uninstall-plugin.ts +82 -0
  372. package/src/cli/lib/unknown-command.ts +111 -0
  373. package/src/cli/program.ts +40 -6
  374. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  375. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  376. package/src/cli/utils/conversation-id.ts +30 -0
  377. package/src/cli/utils/parse-duration.ts +41 -0
  378. package/src/config/acp-defaults.test.ts +5 -1
  379. package/src/config/acp-defaults.ts +11 -4
  380. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  381. package/src/config/bundled-skills/app-builder/SKILL.md +23 -21
  382. package/src/config/bundled-skills/app-builder/TOOLS.json +7 -0
  383. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  384. package/src/config/bundled-skills/computer-use/TOOLS.json +15 -52
  385. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  386. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  387. package/src/config/bundled-skills/document/SKILL.md +23 -3
  388. package/src/config/bundled-skills/document/TOOLS.json +53 -0
  389. package/src/config/bundled-skills/document/tools/document-delete.ts +12 -0
  390. package/src/config/bundled-skills/document/tools/document-list.ts +12 -0
  391. package/src/config/bundled-skills/document/tools/document-read.ts +12 -0
  392. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  393. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  394. package/src/config/bundled-skills/skill-management/SKILL.md +2 -2
  395. package/src/config/bundled-skills/skill-management/TOOLS.json +7 -7
  396. package/src/config/bundled-tool-registry.ts +6 -2
  397. package/src/config/feature-flag-registry.json +57 -1
  398. package/src/config/llm-resolver.ts +16 -1
  399. package/src/config/loader.ts +140 -52
  400. package/src/config/raw-config-utils.ts +2 -30
  401. package/src/config/schema.ts +8 -7
  402. package/src/config/schemas/__tests__/llm-request-logs.test.ts +36 -0
  403. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  404. package/src/config/schemas/call-site-catalog.ts +29 -7
  405. package/src/config/schemas/channels.ts +8 -0
  406. package/src/config/schemas/compaction.ts +28 -0
  407. package/src/config/schemas/heartbeat.ts +9 -0
  408. package/src/config/schemas/llm-request-logs.ts +81 -0
  409. package/src/config/schemas/llm.ts +55 -2
  410. package/src/config/schemas/memory-retrieval.ts +18 -0
  411. package/src/config/schemas/memory-retrospective.ts +48 -0
  412. package/src/config/schemas/memory-v2.ts +32 -1
  413. package/src/config/schemas/memory.ts +4 -0
  414. package/src/config/schemas/services.ts +15 -12
  415. package/src/config/schemas/tools.ts +14 -0
  416. package/src/config/seed-inference-profiles.ts +195 -134
  417. package/src/config/skills.ts +3 -96
  418. package/src/contacts/contact-store.ts +0 -61
  419. package/src/context/compactor.ts +1047 -0
  420. package/src/context/token-estimator.ts +2 -2
  421. package/src/context/window-manager.ts +197 -1334
  422. package/src/credential-execution/managed-catalog.ts +37 -0
  423. package/src/credential-health/credential-health-service.ts +280 -19
  424. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +113 -0
  425. package/src/daemon/__tests__/conversation-tool-setup-exclude.test.ts +138 -0
  426. package/src/daemon/__tests__/conversation-tool-setup.test.ts +183 -4
  427. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  428. package/src/daemon/approval-generators.ts +26 -30
  429. package/src/daemon/config-watcher.ts +94 -29
  430. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  431. package/src/daemon/conversation-agent-loop.ts +293 -103
  432. package/src/daemon/conversation-error.ts +188 -33
  433. package/src/daemon/conversation-lifecycle.ts +80 -26
  434. package/src/daemon/conversation-messaging.ts +25 -6
  435. package/src/daemon/conversation-process.ts +85 -31
  436. package/src/daemon/conversation-runtime-assembly.ts +30 -6
  437. package/src/daemon/conversation-slash.ts +184 -25
  438. package/src/daemon/conversation-store.ts +24 -10
  439. package/src/daemon/conversation-surfaces.ts +76 -12
  440. package/src/daemon/conversation-tool-setup.ts +63 -21
  441. package/src/daemon/conversation.ts +81 -10
  442. package/src/daemon/external-plugins-bootstrap.ts +231 -185
  443. package/src/daemon/first-greeting.ts +22 -2
  444. package/src/daemon/guardian-action-generators.ts +7 -22
  445. package/src/daemon/handlers/config-model.ts +13 -130
  446. package/src/daemon/handlers/config-slack-channel.ts +25 -10
  447. package/src/daemon/handlers/config-vercel.ts +3 -1
  448. package/src/daemon/handlers/shared.ts +14 -5
  449. package/src/daemon/handlers/skills.ts +166 -84
  450. package/src/daemon/history-repair.ts +61 -7
  451. package/src/daemon/host-app-control-proxy.ts +129 -29
  452. package/src/daemon/host-bash-proxy.ts +85 -158
  453. package/src/daemon/host-browser-proxy.ts +96 -35
  454. package/src/daemon/host-proxy-base.ts +13 -1
  455. package/src/daemon/host-proxy-preactivation.ts +25 -1
  456. package/src/daemon/identity-helpers.ts +19 -0
  457. package/src/daemon/lifecycle.ts +79 -70
  458. package/src/daemon/meet-host-supervisor.ts +20 -19
  459. package/src/daemon/memory-v2-startup.ts +58 -2
  460. package/src/daemon/message-protocol.ts +7 -0
  461. package/src/daemon/message-types/bookmarks.ts +18 -0
  462. package/src/daemon/message-types/conversations.ts +37 -9
  463. package/src/daemon/message-types/messages.ts +70 -1
  464. package/src/daemon/message-types/subagents.ts +1 -0
  465. package/src/daemon/message-types/sync.ts +61 -0
  466. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  467. package/src/daemon/pkb-reminder-builder.ts +21 -7
  468. package/src/daemon/plugin-source-watcher.ts +146 -0
  469. package/src/daemon/process-message.ts +77 -26
  470. package/src/daemon/server.ts +34 -20
  471. package/src/daemon/shutdown-handlers.ts +0 -2
  472. package/src/daemon/skill-memory-refresh.ts +29 -0
  473. package/src/daemon/tool-setup-types.ts +9 -0
  474. package/src/daemon/tool-side-effects.ts +6 -4
  475. package/src/daemon/wake-target-adapter.ts +11 -0
  476. package/src/documents/document-store.ts +221 -3
  477. package/src/embedded/plugin-api.ts +40 -0
  478. package/src/export/transcript-formatter.ts +61 -2
  479. package/src/filing/filing-service.ts +79 -53
  480. package/src/heartbeat/__tests__/heartbeat-service.test.ts +444 -0
  481. package/src/heartbeat/heartbeat-run-store.ts +3 -1
  482. package/src/heartbeat/heartbeat-service.ts +189 -127
  483. package/src/home/__tests__/feed-types.test.ts +99 -127
  484. package/src/home/__tests__/feed-writer.test.ts +77 -278
  485. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  486. package/src/home/feed-types.ts +41 -73
  487. package/src/home/feed-writer.ts +25 -156
  488. package/src/home/post-connect-feed.ts +2 -3
  489. package/src/index.ts +18 -1
  490. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  491. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  492. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  493. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  494. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  495. package/src/ipc/assistant-server.ts +55 -6
  496. package/src/ipc/cli-client.ts +370 -50
  497. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  498. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  499. package/src/ipc/skill-routes/events.ts +30 -3
  500. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  501. package/src/live-voice/__tests__/live-voice-stt.test.ts +57 -0
  502. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  503. package/src/live-voice/live-voice-session-manager.ts +11 -4
  504. package/src/live-voice/live-voice-session.ts +14 -6
  505. package/src/mcp/client.ts +20 -4
  506. package/src/media/image-credentials.ts +3 -3
  507. package/src/memory/__tests__/bookmark-crud.test.ts +264 -0
  508. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  509. package/src/memory/__tests__/conversation-queries.test.ts +263 -0
  510. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  511. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  512. package/src/memory/__tests__/jobs-worker-v2-graph-trigger-embed.test.ts +113 -0
  513. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  514. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  515. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +318 -0
  516. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  517. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  518. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  519. package/src/memory/__tests__/message-content.test.ts +35 -0
  520. package/src/memory/bookmark-crud.ts +211 -0
  521. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  522. package/src/memory/context-search/agent-protocol.ts +5 -1
  523. package/src/memory/context-search/agent-runner.ts +60 -85
  524. package/src/memory/context-search/limits.ts +1 -4
  525. package/src/memory/context-search/search.ts +23 -113
  526. package/src/memory/context-search/sources/conversations.ts +80 -8
  527. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  528. package/src/memory/context-search/sources/memory.ts +7 -0
  529. package/src/memory/context-search/sources/workspace.ts +17 -10
  530. package/src/memory/context-search/types.ts +1 -1
  531. package/src/memory/conversation-bootstrap.ts +11 -0
  532. package/src/memory/conversation-crud.ts +368 -22
  533. package/src/memory/conversation-queries.ts +116 -12
  534. package/src/memory/conversation-title-service.ts +1 -0
  535. package/src/memory/conversation-types.ts +16 -0
  536. package/src/memory/db-init.ts +20 -0
  537. package/src/memory/delivery-crud.ts +152 -5
  538. package/src/memory/embedding-backend.ts +6 -5
  539. package/src/memory/embedding-runtime-manager.ts +1 -2
  540. package/src/memory/external-conversation-store.ts +66 -5
  541. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +66 -9
  542. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  543. package/src/memory/graph/conversation-graph-memory.ts +92 -5
  544. package/src/memory/graph/extraction.ts +4 -0
  545. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  546. package/src/memory/graph/tool-handlers.ts +17 -7
  547. package/src/memory/graph/tools.ts +45 -6
  548. package/src/memory/indexer.ts +51 -29
  549. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +86 -15
  550. package/src/memory/jobs/embed-concept-page.ts +65 -20
  551. package/src/memory/jobs-store.ts +51 -1
  552. package/src/memory/jobs-worker.ts +57 -3
  553. package/src/memory/llm-request-log-source-clickhouse.ts +324 -0
  554. package/src/memory/llm-request-log-source-local.ts +26 -0
  555. package/src/memory/llm-request-log-source.ts +64 -0
  556. package/src/memory/llm-request-log-store.ts +1 -1
  557. package/src/memory/llm-usage-store.ts +125 -5
  558. package/src/memory/memory-retrospective-constants.ts +13 -0
  559. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  560. package/src/memory/memory-retrospective-job.ts +351 -0
  561. package/src/memory/memory-retrospective-startup-cleanup.ts +175 -0
  562. package/src/memory/memory-retrospective-state.ts +162 -0
  563. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  564. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  565. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  566. package/src/memory/message-content.ts +38 -1
  567. package/src/memory/migrations/109-external-conversation-bindings.ts +15 -4
  568. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  569. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  570. package/src/memory/migrations/229-delete-private-conversations.test.ts +107 -1
  571. package/src/memory/migrations/229-delete-private-conversations.ts +19 -0
  572. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  573. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  574. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  575. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  576. package/src/memory/migrations/243-provider-connections.ts +68 -0
  577. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  578. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  579. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  580. package/src/memory/migrations/247-external-conversation-binding-thread-id.ts +78 -0
  581. package/src/memory/migrations/248-create-onboarding-events.ts +21 -0
  582. package/src/memory/migrations/249-normalize-slack-external-content.ts +240 -0
  583. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  584. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  585. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  586. package/src/memory/migrations/index.ts +13 -0
  587. package/src/memory/migrations/registry.ts +8 -0
  588. package/src/memory/onboarding-events-store.ts +106 -0
  589. package/src/memory/published-pages-store.ts +16 -0
  590. package/src/memory/schema/bookmarks.ts +36 -0
  591. package/src/memory/schema/calls.ts +1 -0
  592. package/src/memory/schema/conversations.ts +2 -0
  593. package/src/memory/schema/index.ts +2 -0
  594. package/src/memory/schema/inference.ts +27 -0
  595. package/src/memory/schema/infrastructure.ts +12 -0
  596. package/src/memory/schema/memory-core.ts +9 -0
  597. package/src/memory/search/semantic.ts +1 -4
  598. package/src/memory/turn-events-store.ts +127 -2
  599. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  600. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  601. package/src/memory/v2/__tests__/activation.test.ts +11 -12
  602. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  603. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  604. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  605. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  606. package/src/memory/v2/__tests__/injection.test.ts +726 -18
  607. package/src/memory/v2/__tests__/migration.test.ts +94 -3
  608. package/src/memory/v2/__tests__/page-index.test.ts +360 -0
  609. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  610. package/src/memory/v2/__tests__/prompts-router.test.ts +309 -0
  611. package/src/memory/v2/__tests__/qdrant.test.ts +138 -3
  612. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  613. package/src/memory/v2/__tests__/router.test.ts +531 -0
  614. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  615. package/src/memory/v2/__tests__/skill-store.test.ts +445 -11
  616. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  617. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  618. package/src/memory/v2/activation-store.ts +34 -5
  619. package/src/memory/v2/activation.ts +40 -27
  620. package/src/memory/v2/backfill-jobs.ts +17 -84
  621. package/src/memory/v2/consolidation-job.ts +85 -78
  622. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  623. package/src/memory/v2/injection.ts +466 -109
  624. package/src/memory/v2/migration.ts +147 -20
  625. package/src/memory/v2/page-index.ts +221 -0
  626. package/src/memory/v2/page-store.ts +3 -0
  627. package/src/memory/v2/prompts/consolidation.ts +9 -7
  628. package/src/memory/v2/prompts/router.ts +195 -0
  629. package/src/memory/v2/prompts/sweep.ts +2 -2
  630. package/src/memory/v2/qdrant.ts +234 -93
  631. package/src/memory/v2/reranker.ts +14 -7
  632. package/src/memory/v2/router.ts +323 -0
  633. package/src/memory/v2/sim.ts +25 -12
  634. package/src/memory/v2/skill-store.ts +204 -30
  635. package/src/memory/v2/static-context.ts +16 -9
  636. package/src/memory/v2/sweep-job.ts +122 -96
  637. package/src/memory/v2/types.ts +10 -6
  638. package/src/memory/validation.ts +13 -0
  639. package/src/messaging/providers/slack/__tests__/adapter-token-routing.test.ts +45 -5
  640. package/src/messaging/providers/slack/__tests__/download.test.ts +231 -0
  641. package/src/messaging/providers/slack/adapter.ts +43 -5
  642. package/src/messaging/providers/slack/client.ts +27 -0
  643. package/src/messaging/providers/slack/deep-link.ts +65 -0
  644. package/src/messaging/providers/slack/download.ts +104 -0
  645. package/src/messaging/providers/slack/message-metadata.test.ts +32 -0
  646. package/src/messaging/providers/slack/message-metadata.ts +27 -0
  647. package/src/messaging/providers/slack/render-transcript.test.ts +134 -0
  648. package/src/messaging/providers/slack/render-transcript.ts +69 -5
  649. package/src/messaging/providers/slack/types.ts +20 -1
  650. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  651. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  652. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  653. package/src/notifications/adapters/platform.ts +171 -0
  654. package/src/notifications/conversation-pairing.ts +4 -3
  655. package/src/notifications/copy-composer.ts +15 -0
  656. package/src/notifications/decision-engine.ts +2 -1
  657. package/src/notifications/destination-resolver.ts +21 -0
  658. package/src/notifications/emit-signal.ts +48 -2
  659. package/src/notifications/home-feed-side-effect.ts +165 -0
  660. package/src/notifications/signal.ts +8 -1
  661. package/src/oauth/connection-resolver.ts +8 -4
  662. package/src/oauth/platform-connection.ts +6 -2
  663. package/src/oauth/seed-providers.ts +10 -1
  664. package/src/permissions/checker.ts +14 -0
  665. package/src/permissions/ipc-risk-types.ts +3 -0
  666. package/src/permissions/question-prompter.test.ts +416 -0
  667. package/src/permissions/question-prompter.ts +294 -0
  668. package/src/platform/client.test.ts +1 -1
  669. package/src/platform/client.ts +1 -1
  670. package/src/plugin-api/constants.ts +26 -0
  671. package/src/plugin-api/index.ts +46 -0
  672. package/src/plugin-api/package.json +12 -0
  673. package/src/plugin-api/types.ts +144 -0
  674. package/src/plugins/defaults/circuit-breaker.ts +0 -5
  675. package/src/plugins/defaults/compaction.ts +0 -4
  676. package/src/plugins/defaults/empty-response.ts +0 -2
  677. package/src/plugins/defaults/history-repair.ts +0 -2
  678. package/src/plugins/defaults/injectors.ts +55 -6
  679. package/src/plugins/defaults/llm-call.ts +0 -2
  680. package/src/plugins/defaults/memory-retrieval.ts +0 -1
  681. package/src/plugins/defaults/overflow-reduce.ts +0 -1
  682. package/src/plugins/defaults/persistence.ts +0 -2
  683. package/src/plugins/defaults/title-generate.ts +0 -5
  684. package/src/plugins/defaults/token-estimate.ts +0 -2
  685. package/src/plugins/defaults/tool-error.ts +0 -7
  686. package/src/plugins/defaults/tool-execute.ts +0 -2
  687. package/src/plugins/defaults/tool-result-truncate.ts +0 -4
  688. package/src/plugins/ensure-plugin-api-shim.ts +96 -0
  689. package/src/plugins/external-api.ts +104 -0
  690. package/src/plugins/external-plugin-loader.ts +367 -0
  691. package/src/plugins/feature-gate.ts +22 -0
  692. package/src/plugins/pipeline.ts +37 -0
  693. package/src/plugins/registry.ts +48 -80
  694. package/src/plugins/types.ts +74 -53
  695. package/src/plugins/user-loader.ts +85 -43
  696. package/src/proactive-artifact/aux-message-injector.ts +11 -0
  697. package/src/proactive-artifact/job.test.ts +49 -9
  698. package/src/proactive-artifact/job.ts +4 -0
  699. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  700. package/src/proactive-artifact/trigger-state.ts +4 -0
  701. package/src/prompts/__tests__/system-prompt.test.ts +117 -0
  702. package/src/prompts/__tests__/task-progress-hint-section.test.ts +99 -0
  703. package/src/prompts/normalize-onboarding.ts +27 -0
  704. package/src/prompts/sections.ts +302 -0
  705. package/src/prompts/system-prompt.ts +72 -154
  706. package/src/prompts/templates/BOOTSTRAP.md +17 -1
  707. package/src/prompts/templates/system-sections.ts +173 -0
  708. package/src/prompts/update-bulletin-job.ts +61 -73
  709. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  710. package/src/providers/__tests__/inference.test.ts +303 -0
  711. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  712. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  713. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  714. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  715. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  716. package/src/providers/anthropic/client.ts +123 -54
  717. package/src/providers/call-site-routing.ts +94 -16
  718. package/src/providers/connection-resolution.ts +170 -0
  719. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  720. package/src/providers/inference/adapter-factory.ts +210 -0
  721. package/src/providers/inference/auth.ts +112 -0
  722. package/src/providers/inference/backfill.ts +196 -0
  723. package/src/providers/inference/connections.ts +401 -0
  724. package/src/providers/inference/resolve-auth.ts +73 -0
  725. package/src/providers/model-catalog.ts +386 -6
  726. package/src/providers/openai/chat-completions-provider.ts +10 -2
  727. package/src/providers/openai/responses-provider.ts +4 -2
  728. package/src/providers/openrouter/client.ts +7 -0
  729. package/src/providers/{managed-proxy → platform-proxy}/constants.ts +4 -1
  730. package/src/providers/{managed-proxy → platform-proxy}/context.ts +3 -3
  731. package/src/providers/provider-availability.ts +17 -2
  732. package/src/providers/provider-catalog-visibility.ts +36 -0
  733. package/src/providers/provider-env-vars.ts +17 -7
  734. package/src/providers/provider-secret-catalog.ts +49 -30
  735. package/src/providers/provider-send-message.ts +41 -20
  736. package/src/providers/registry.ts +151 -159
  737. package/src/providers/retry.ts +65 -11
  738. package/src/providers/search-provider-catalog.ts +121 -0
  739. package/src/runtime/AGENTS.md +18 -5
  740. package/src/runtime/__tests__/agent-wake.test.ts +152 -0
  741. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  742. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  743. package/src/runtime/actor-trust-resolver.ts +32 -10
  744. package/src/runtime/agent-wake.ts +64 -7
  745. package/src/runtime/assistant-event-hub.ts +3 -85
  746. package/src/runtime/auth/route-policy.ts +311 -9
  747. package/src/runtime/auth/same-actor.ts +2 -0
  748. package/src/runtime/background-job-runner.ts +339 -0
  749. package/src/runtime/btw-sidechain.ts +3 -0
  750. package/src/runtime/http-router.ts +36 -1
  751. package/src/runtime/http-server.ts +31 -5
  752. package/src/runtime/http-types.ts +21 -0
  753. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  754. package/src/runtime/middleware/request-logger.ts +62 -1
  755. package/src/runtime/migrations/origin-mode.ts +1 -1
  756. package/src/runtime/pending-interactions.ts +1 -0
  757. package/src/runtime/pre-first-message-gate.ts +83 -0
  758. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  759. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +268 -0
  760. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  761. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +319 -0
  762. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +280 -4
  763. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  764. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  765. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  766. package/src/runtime/routes/__tests__/question-routes.test.ts +395 -0
  767. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  768. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  769. package/src/runtime/routes/__tests__/tts-routes.test.ts +70 -3
  770. package/src/runtime/routes/acp-routes-list.test.ts +143 -0
  771. package/src/runtime/routes/acp-routes.ts +12 -8
  772. package/src/runtime/routes/app-management-routes.ts +228 -3
  773. package/src/runtime/routes/approval-routes.ts +0 -18
  774. package/src/runtime/routes/audit-routes.ts +43 -0
  775. package/src/runtime/routes/auth-routes.ts +72 -0
  776. package/src/runtime/routes/avatar-routes.ts +273 -20
  777. package/src/runtime/routes/backup-routes.ts +406 -2
  778. package/src/runtime/routes/bookmark-routes.ts +156 -0
  779. package/src/runtime/routes/btw-routes.ts +5 -1
  780. package/src/runtime/routes/channel-availability-routes.ts +121 -0
  781. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  782. package/src/runtime/routes/contact-routes.ts +0 -160
  783. package/src/runtime/routes/conversation-cli-routes.ts +233 -0
  784. package/src/runtime/routes/conversation-list-routes.ts +3 -20
  785. package/src/runtime/routes/conversation-management-routes.ts +47 -85
  786. package/src/runtime/routes/conversation-query-routes.ts +350 -97
  787. package/src/runtime/routes/conversation-routes.ts +121 -21
  788. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  789. package/src/runtime/routes/credential-routes.ts +540 -0
  790. package/src/runtime/routes/debug-routes.ts +2 -2
  791. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  792. package/src/runtime/routes/documents-routes.ts +25 -86
  793. package/src/runtime/routes/domain-routes.ts +167 -0
  794. package/src/runtime/routes/email-routes.ts +603 -0
  795. package/src/runtime/routes/errors.ts +2 -2
  796. package/src/runtime/routes/events-routes.ts +192 -0
  797. package/src/runtime/routes/group-routes.ts +5 -0
  798. package/src/runtime/routes/home-feed-routes.ts +6 -78
  799. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  800. package/src/runtime/routes/host-browser-routes.ts +103 -22
  801. package/src/runtime/routes/http-adapter.ts +2 -0
  802. package/src/runtime/routes/identity-routes.ts +5 -0
  803. package/src/runtime/routes/image-generation-routes.ts +99 -0
  804. package/src/runtime/routes/inbound-conversation.ts +28 -8
  805. package/src/runtime/routes/inbound-message-handler.ts +236 -41
  806. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +248 -1
  807. package/src/runtime/routes/inbound-stages/background-dispatch.ts +118 -7
  808. package/src/runtime/routes/inbound-stages/edit-intercept.ts +17 -4
  809. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  810. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  811. package/src/runtime/routes/index.ts +42 -0
  812. package/src/runtime/routes/inference-profile-session-handler.ts +285 -0
  813. package/src/runtime/routes/inference-profile-session-reaper.ts +84 -0
  814. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  815. package/src/runtime/routes/inference-provider-connection-routes.ts +361 -0
  816. package/src/runtime/routes/inference-send-routes.ts +115 -0
  817. package/src/runtime/routes/integrations/slack/share.ts +4 -52
  818. package/src/runtime/routes/integrations/slack/token.ts +43 -0
  819. package/src/runtime/routes/integrations/twilio.ts +7 -13
  820. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  821. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  822. package/src/runtime/routes/notification-routes.ts +3 -1
  823. package/src/runtime/routes/oauth-apps.ts +112 -7
  824. package/src/runtime/routes/oauth-commands-routes.ts +1097 -0
  825. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  826. package/src/runtime/routes/oauth-lifecycle-routes.ts +43 -0
  827. package/src/runtime/routes/oauth-providers.ts +298 -8
  828. package/src/runtime/routes/platform-routes.ts +336 -0
  829. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  830. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  831. package/src/runtime/routes/playground/state.ts +2 -1
  832. package/src/runtime/routes/publish-routes.ts +221 -0
  833. package/src/runtime/routes/question-routes.ts +259 -0
  834. package/src/runtime/routes/rename-conversation-routes.ts +2 -33
  835. package/src/runtime/routes/schedule-routes.ts +79 -0
  836. package/src/runtime/routes/sequence-routes.ts +291 -0
  837. package/src/runtime/routes/settings-routes.ts +2 -10
  838. package/src/runtime/routes/skills-routes.ts +31 -1
  839. package/src/runtime/routes/stt-routes.ts +240 -3
  840. package/src/runtime/routes/subagents-routes.ts +57 -18
  841. package/src/runtime/routes/surface-action-routes.ts +43 -7
  842. package/src/runtime/routes/telemetry-routes.ts +27 -0
  843. package/src/runtime/routes/tts-routes.ts +93 -1
  844. package/src/runtime/routes/types.ts +32 -0
  845. package/src/runtime/routes/user-routes-cli.ts +243 -0
  846. package/src/runtime/routes/webhook-routes.ts +165 -0
  847. package/src/runtime/routes/workspace-routes.test.ts +43 -0
  848. package/src/runtime/routes/workspace-routes.ts +28 -0
  849. package/src/runtime/services/conversation-serializer.ts +39 -7
  850. package/src/runtime/sync/resource-sync-events.ts +117 -0
  851. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  852. package/src/runtime/sync/sync-publisher.ts +21 -0
  853. package/src/schedule/schedule-store.ts +27 -2
  854. package/src/schedule/scheduler.ts +208 -123
  855. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  856. package/src/security/__tests__/untrusted-content.test.ts +86 -0
  857. package/src/security/secret-patterns.ts +3 -0
  858. package/src/security/untrusted-content.ts +93 -8
  859. package/src/sequence/engine.ts +38 -40
  860. package/src/skills/catalog-files.ts +1 -1
  861. package/src/skills/catalog-install.ts +233 -116
  862. package/src/skills/clawhub.ts +70 -13
  863. package/src/skills/managed-store.ts +4 -119
  864. package/src/skills/skillssh-registry.ts +27 -48
  865. package/src/subagent/manager.ts +28 -15
  866. package/src/telemetry/types.ts +113 -1
  867. package/src/telemetry/usage-telemetry-reporter.test.ts +312 -5
  868. package/src/telemetry/usage-telemetry-reporter.ts +113 -7
  869. package/src/tools/apps/executors.ts +58 -7
  870. package/src/tools/ask-question/ask-question-tool.test.ts +509 -0
  871. package/src/tools/ask-question/ask-question-tool.ts +304 -0
  872. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  873. package/src/tools/browser/browser-execution.ts +29 -14
  874. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  875. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  876. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  877. package/src/tools/browser/cdp-client/factory.ts +66 -5
  878. package/src/tools/browser/runtime-check.ts +77 -0
  879. package/src/tools/computer-use/definitions.ts +3 -3
  880. package/src/tools/credentials/vault.ts +1 -1
  881. package/src/tools/document/document-tool.ts +124 -1
  882. package/src/tools/filesystem/edit.ts +1 -1
  883. package/src/tools/filesystem/list.ts +1 -1
  884. package/src/tools/filesystem/read.ts +1 -1
  885. package/src/tools/filesystem/write.ts +5 -2
  886. package/src/tools/host-filesystem/transfer.ts +1 -1
  887. package/src/tools/host-terminal/host-shell.ts +1 -1
  888. package/src/tools/memory/register.test.ts +3 -3
  889. package/src/tools/memory/register.ts +9 -1
  890. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  891. package/src/tools/network/web-search.ts +280 -37
  892. package/src/tools/permission-checker.ts +14 -6
  893. package/src/tools/registry.ts +17 -7
  894. package/src/tools/schedule/create.ts +2 -2
  895. package/src/tools/schema-transforms.ts +7 -2
  896. package/src/tools/side-effects.ts +1 -0
  897. package/src/tools/skills/delete-managed.ts +4 -4
  898. package/src/tools/skills/execute.ts +1 -1
  899. package/src/tools/skills/scaffold-managed.ts +3 -2
  900. package/src/tools/subagent/notify-parent.ts +1 -1
  901. package/src/tools/subagent/spawn.ts +3 -3
  902. package/src/tools/system/request-permission.ts +2 -2
  903. package/src/tools/terminal/safe-env.ts +60 -1
  904. package/src/tools/terminal/shell.ts +44 -0
  905. package/src/tools/tool-manifest.ts +2 -0
  906. package/src/tools/types.ts +72 -21
  907. package/src/tools/ui-surface/definitions.ts +6 -5
  908. package/src/tts/__tests__/provider-adapters.test.ts +76 -2
  909. package/src/tts/providers/elevenlabs-provider.ts +75 -1
  910. package/src/types/onboarding-context.ts +2 -0
  911. package/src/usage/attribution.ts +3 -2
  912. package/src/util/errors.ts +17 -0
  913. package/src/util/platform.ts +10 -0
  914. package/src/util/pricing.ts +86 -160
  915. package/src/watcher/__tests__/engine.test.ts +323 -0
  916. package/src/watcher/constants.ts +7 -0
  917. package/src/watcher/engine.ts +94 -90
  918. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  919. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  920. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +94 -5
  921. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  922. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +117 -0
  923. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +95 -0
  924. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  925. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  926. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  927. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  928. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  929. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  930. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  931. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  932. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  933. package/src/workspace/migrations/083-system-prompt-prefix-to-file.ts +191 -0
  934. package/src/workspace/migrations/084-remove-legacy-skills-index.ts +276 -0
  935. package/src/workspace/migrations/085-memory-v2-bm25-b-reembed-disabled-v2-pages.ts +137 -0
  936. package/src/workspace/migrations/086-revert-stale-gemini-mis-rewrites.ts +198 -0
  937. package/src/workspace/migrations/registry.ts +30 -0
  938. package/src/workspace/migrations/runner.ts +46 -5
  939. package/src/workspace/migrations/types.ts +17 -3
  940. package/src/workspace/provider-commit-message-generator.ts +3 -2
  941. package/examples/plugins/echo/bun.lock +0 -25
  942. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  943. package/src/__tests__/context-window-manager.test.ts +0 -2093
  944. package/src/__tests__/credentials-cli.test.ts +0 -1225
  945. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  946. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  947. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  948. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  949. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  950. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  951. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  952. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  953. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  954. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  955. package/src/cli/commands/autonomy.ts +0 -365
  956. package/src/cli/commands/memory.ts +0 -424
  957. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  958. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  959. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  960. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  961. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  962. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  963. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  964. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  965. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  966. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  967. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  968. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  969. package/src/context/__tests__/compact-prompt.test.ts +0 -63
  970. package/src/context/prompts/compact.md +0 -26
  971. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  972. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  973. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  974. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  975. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  976. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  977. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  978. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  979. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  980. package/src/home/assistant-feed-authoring.ts +0 -135
  981. package/src/home/emit-feed-event.ts +0 -169
  982. package/src/home/feed-scheduler.ts +0 -281
  983. package/src/home/platform-gmail-digest.ts +0 -163
  984. package/src/home/rewrite-command-preview.ts +0 -66
  985. package/src/home/rewrite-feed-title.ts +0 -58
  986. package/src/home/rollup-producer.ts +0 -426
  987. package/src/memory/admin.ts +0 -326
  988. package/src/memory/context-search/sources/pkb.ts +0 -476
  989. package/src/memory/graph/compaction.ts +0 -299
  990. package/src/prompts/__tests__/build-cli-reference-section.test.ts +0 -37
  991. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -88,6 +88,7 @@ function mergeDefaultConfigAndSeedInferenceProfiles(): void {
88
88
  seedInferenceProfiles({
89
89
  preserveProfileNames: defaultConfigMerge.providedLlmProfileNames,
90
90
  preserveActiveProfile: defaultConfigMerge.providedLlmActiveProfile,
91
+ isHatch: defaultConfigMerge.hadOverlay,
91
92
  });
92
93
  }
93
94
 
@@ -309,12 +310,14 @@ describe("loadConfig startup behavior", () => {
309
310
  ensureTestDir();
310
311
  _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
311
312
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
313
+ delete process.env.IS_PLATFORM;
312
314
  invalidateConfigCache();
313
315
  });
314
316
 
315
317
  afterEach(() => {
316
318
  _setStorePath(null);
317
319
  delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
320
+ delete process.env.IS_PLATFORM;
318
321
  invalidateConfigCache();
319
322
  });
320
323
 
@@ -406,7 +409,7 @@ describe("loadConfig startup behavior", () => {
406
409
  expect(raw.dataDir).toBeUndefined();
407
410
  });
408
411
 
409
- test("hatch default overlay does not suppress first-load inference profiles", () => {
412
+ test("off-platform hatch seeds both managed and user anthropic profiles", () => {
410
413
  const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
411
414
  writeFileSync(
412
415
  overlayPath,
@@ -430,19 +433,30 @@ describe("loadConfig startup behavior", () => {
430
433
 
431
434
  expect(config.llm.default.provider).toBe("anthropic");
432
435
  expect(config.llm.default.model).toBe("claude-opus-4-7");
433
- expect(config.llm.activeProfile).toBe("balanced");
436
+ // Off-platform: user profiles are active, backed by the user's API key.
437
+ expect(config.llm.activeProfile).toBe("custom-balanced");
438
+ expect(config.llm.profiles["custom-balanced"]?.provider).toBe("anthropic");
439
+ expect(config.llm.profiles["custom-balanced"]?.provider_connection).toBe(
440
+ "anthropic-personal",
441
+ );
442
+ // Managed profiles exist as well.
434
443
  expect(config.llm.profiles.balanced?.model).toBe("claude-sonnet-4-6");
444
+ expect(config.llm.profiles.balanced?.provider_connection).toBe(
445
+ "anthropic-managed",
446
+ );
435
447
 
436
448
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
437
449
  expect(raw.llm.default).toEqual({
438
450
  provider: "anthropic",
439
451
  model: "claude-opus-4-7",
440
452
  });
441
- expect(raw.llm.activeProfile).toBe("balanced");
453
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
442
454
  expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
443
455
  });
444
456
 
445
- test("non-Anthropic hatch overlay seeds custom-* profiles and activates custom-balanced", () => {
457
+ test("on-platform hatch seeds only managed profiles", () => {
458
+ process.env.IS_PLATFORM = "true";
459
+
446
460
  const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
447
461
  writeFileSync(
448
462
  overlayPath,
@@ -450,7 +464,8 @@ describe("loadConfig startup behavior", () => {
450
464
  {
451
465
  llm: {
452
466
  default: {
453
- provider: "openai",
467
+ provider: "anthropic",
468
+ model: "claude-opus-4-7",
454
469
  },
455
470
  },
456
471
  },
@@ -462,43 +477,26 @@ describe("loadConfig startup behavior", () => {
462
477
 
463
478
  mergeDefaultConfigAndSeedInferenceProfiles();
464
479
  const config = loadConfig();
465
- const mainAgentConfig = resolveCallSiteConfig("mainAgent", config.llm);
466
480
 
467
- expect(config.llm.activeProfile).toBe("custom-balanced");
468
- expect(config.llm.profiles["custom-balanced"]?.provider).toBe("openai");
469
- expect(config.llm.profiles["custom-balanced"]?.model).toBe("gpt-5.4-mini");
470
- expect(config.llm.profiles["custom-quality-optimized"]?.provider).toBe(
471
- "openai",
472
- );
473
- expect(config.llm.profiles["custom-cost-optimized"]?.provider).toBe(
474
- "openai",
475
- );
476
- expect(config.llm.profiles.balanced?.provider).toBe("anthropic");
477
- expect(config.llm.profiles["quality-optimized"]?.provider).toBe(
478
- "anthropic",
479
- );
480
- expect(config.llm.profiles["cost-optimized"]?.provider).toBe("anthropic");
481
- expect(config.llm.default.provider).toBe("openai");
482
- expect(config.llm.default.model).toBe("gpt-5.4-mini");
483
- expect(mainAgentConfig.provider).toBe("openai");
484
- expect(mainAgentConfig.model).toBe("gpt-5.4-mini");
485
-
486
- const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
487
- expect(raw.llm.activeProfile).toBe("custom-balanced");
488
- expect(raw.llm.default.model).toBe(
489
- raw.llm.profiles["custom-balanced"].model,
481
+ expect(config.llm.activeProfile).toBe("balanced");
482
+ expect(config.llm.profiles.balanced?.model).toBe("claude-sonnet-4-6");
483
+ expect(config.llm.profiles.balanced?.provider_connection).toBe(
484
+ "anthropic-managed",
490
485
  );
486
+ // No user profiles created on platform.
487
+ expect(config.llm.profiles["custom-balanced"]).toBeUndefined();
491
488
  });
492
489
 
493
- test("re-hatch from openai to anthropic resets stale custom-balanced active profile", () => {
494
- // Pre-seed an OpenAI-style workspace: custom-balanced is active, default is
495
- // openai. Simulates a workspace that previously hatched against OpenAI.
490
+ test("re-hatch from openai to anthropic creates user anthropic profiles off-platform", () => {
491
+ // Pre-seed an OpenAI-style workspace: user-defined custom-balanced profile
492
+ // is active, default is openai. Simulates a workspace that hatched against
493
+ // OpenAI under the pre-1.2 model.
496
494
  writeConfig({
497
495
  llm: {
498
496
  default: { provider: "openai", model: "gpt-5.4-mini" },
499
497
  profiles: {
500
498
  "custom-balanced": {
501
- source: "managed",
499
+ source: "user",
502
500
  provider: "openai",
503
501
  model: "gpt-5.4-mini",
504
502
  },
@@ -518,41 +516,56 @@ describe("loadConfig startup behavior", () => {
518
516
  mergeDefaultConfigAndSeedInferenceProfiles();
519
517
 
520
518
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
521
- expect(raw.llm.activeProfile).toBe("balanced");
522
- expect(raw.llm.default.provider).toBe("anthropic");
523
- expect(raw.llm.default.model).toBe("claude-sonnet-4-6");
519
+ // Off-platform re-hatch: user profiles are overwritten for the new
520
+ // provider and custom-balanced becomes active.
521
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
522
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("anthropic");
523
+ expect(raw.llm.profiles["custom-balanced"].provider_connection).toBe(
524
+ "anthropic-personal",
525
+ );
526
+ // Managed profiles are also seeded for anthropic-managed.
527
+ expect(raw.llm.profiles.balanced.provider).toBe("anthropic");
528
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
529
+ "anthropic-managed",
530
+ );
524
531
  });
525
532
 
526
- test("unknown overlay provider falls back to Anthropic seeding", () => {
527
- const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
528
- writeFileSync(
529
- overlayPath,
530
- JSON.stringify(
531
- {
532
- llm: {
533
- default: {
534
- provider: "unknownprov",
535
- },
533
+ test("on-platform re-hatch resets active profile to balanced", () => {
534
+ process.env.IS_PLATFORM = "true";
535
+
536
+ writeConfig({
537
+ llm: {
538
+ default: { provider: "openai", model: "gpt-5.4-mini" },
539
+ profiles: {
540
+ "custom-balanced": {
541
+ source: "user",
542
+ provider: "openai",
543
+ model: "gpt-5.4-mini",
536
544
  },
537
545
  },
538
- null,
539
- 2,
540
- ) + "\n",
546
+ activeProfile: "custom-balanced",
547
+ },
548
+ });
549
+
550
+ const overlayPath = join(WORKSPACE_DIR, "rehatch-anthropic.json");
551
+ writeFileSync(
552
+ overlayPath,
553
+ JSON.stringify({ llm: { default: { provider: "anthropic" } } }, null, 2) +
554
+ "\n",
541
555
  );
542
556
  process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
543
557
 
544
558
  mergeDefaultConfigAndSeedInferenceProfiles();
545
559
 
546
560
  const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
561
+ // On-platform: no user profiles created, active resets to managed balanced.
547
562
  expect(raw.llm.activeProfile).toBe("balanced");
548
563
  expect(raw.llm.profiles.balanced.provider).toBe("anthropic");
549
- expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
550
- expect(raw.llm.profiles["custom-balanced"]).toBeUndefined();
551
- expect(raw.llm.profiles["custom-quality-optimized"]).toBeUndefined();
552
- expect(raw.llm.profiles["custom-cost-optimized"]).toBeUndefined();
553
- // The unrecognized provider should be rewritten on disk so subsequent
554
- // loads don't trip Zod's enum validation warning.
555
- expect(raw.llm.default.provider).toBe("anthropic");
564
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
565
+ "anthropic-managed",
566
+ );
567
+ // The old custom-balanced is preserved on disk but no longer active.
568
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("openai");
556
569
  });
557
570
 
558
571
  test("preserves user-supplied non-catalog model on every restart (ollama custom model)", () => {
@@ -572,69 +585,175 @@ describe("loadConfig startup behavior", () => {
572
585
  expect(raw.llm.default.model).toBe("codellama");
573
586
  });
574
587
 
575
- test("syncs llm.default.model to active profile when missing or inconsistent, respects explicit user values", () => {
576
- // 1. Missing on disk → write to active profile's model.
577
- const overlayMissing = join(WORKSPACE_DIR, "overlay-missing.json");
588
+ test("off-platform hatch with openai seeds user profiles and managed anthropic profiles", () => {
589
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
578
590
  writeFileSync(
579
- overlayMissing,
580
- JSON.stringify({ llm: { default: { provider: "openai" } } }, null, 2) +
581
- "\n",
591
+ overlayPath,
592
+ JSON.stringify(
593
+ { llm: { default: { provider: "openai" } } },
594
+ null,
595
+ 2,
596
+ ) + "\n",
582
597
  );
583
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayMissing;
598
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
599
+
584
600
  mergeDefaultConfigAndSeedInferenceProfiles();
585
- let raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
586
- expect(raw.llm.default.model).toBe(
587
- raw.llm.profiles["custom-balanced"].model,
601
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
602
+
603
+ // User profiles for the hatch provider (openai).
604
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
605
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("openai");
606
+ expect(raw.llm.profiles["custom-balanced"].model).toBe("gpt-5.4-mini");
607
+ expect(raw.llm.profiles["custom-balanced"].provider_connection).toBe(
608
+ "openai-personal",
609
+ );
610
+ expect(raw.llm.profiles["custom-balanced"].source).toBe("user");
611
+ expect(raw.llm.profiles["custom-quality-optimized"].provider).toBe(
612
+ "openai",
613
+ );
614
+ expect(raw.llm.profiles["custom-quality-optimized"].model).toBe("gpt-5.4");
615
+ expect(raw.llm.profiles["custom-cost-optimized"].provider).toBe("openai");
616
+ expect(raw.llm.profiles["custom-cost-optimized"].model).toBe(
617
+ "gpt-5.4-nano",
618
+ );
619
+
620
+ // Managed anthropic profiles are also seeded.
621
+ expect(raw.llm.profiles.balanced.provider).toBe("anthropic");
622
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
623
+ "anthropic-managed",
588
624
  );
625
+ expect(raw.llm.profiles.balanced.source).toBe("managed");
626
+ expect(raw.llm.profiles["quality-optimized"].provider).toBe("anthropic");
627
+ expect(raw.llm.profiles["cost-optimized"].provider).toBe("anthropic");
628
+ });
589
629
 
590
- // 2. Inconsistent (previous default model belongs to a different provider)
591
- // is overwritten on the next seed run.
592
- rmSync(CONFIG_PATH);
630
+ test("off-platform managed profiles are overwritten on every boot", () => {
631
+ // Simulate a previous boot that left managed profiles on disk.
593
632
  writeConfig({
594
633
  llm: {
595
- default: { provider: "openai", model: "claude-opus-4-7" },
634
+ profiles: {
635
+ balanced: {
636
+ source: "managed",
637
+ provider: "anthropic",
638
+ model: "old-model-from-previous-release",
639
+ provider_connection: "anthropic-managed",
640
+ },
641
+ },
642
+ activeProfile: "balanced",
596
643
  },
597
644
  });
598
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayMissing;
645
+
646
+ // Non-hatch boot (no overlay). Managed profiles should be overwritten
647
+ // with the latest templates.
599
648
  mergeDefaultConfigAndSeedInferenceProfiles();
600
- raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
601
- expect(raw.llm.default.model).toBe(
602
- raw.llm.profiles["custom-balanced"].model,
649
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
650
+
651
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
652
+ expect(raw.llm.profiles.balanced.provider_connection).toBe(
653
+ "anthropic-managed",
603
654
  );
655
+ expect(raw.llm.activeProfile).toBe("balanced");
656
+ });
604
657
 
605
- // 3. Platform overlay supplies an explicit, internally-coherent
606
- // profile/active/default the user's explicit choice is preserved.
607
- rmSync(CONFIG_PATH);
608
- const explicit = join(WORKSPACE_DIR, "overlay-explicit.json");
609
- writeFileSync(
610
- explicit,
611
- JSON.stringify(
612
- {
613
- llm: {
614
- default: { provider: "openai", model: "gpt-5.4" },
615
- profiles: {
616
- balanced: {
617
- source: "managed",
618
- provider: "openai",
619
- model: "gpt-5.4",
620
- label: "Platform Balanced",
621
- },
622
- },
623
- activeProfile: "balanced",
658
+ test("off-platform reseed preserves user-edited label on managed profiles (Codex P1 on PR #30362)", () => {
659
+ // Simulate a user who renamed the managed "balanced" profile via
660
+ // PUT /v1/config/llm/profiles/balanced { label: "My Default" }.
661
+ writeConfig({
662
+ llm: {
663
+ profiles: {
664
+ balanced: {
665
+ source: "managed",
666
+ provider: "anthropic",
667
+ model: "old-model-from-previous-release",
668
+ provider_connection: "anthropic-managed",
669
+ label: "My Default",
624
670
  },
625
671
  },
626
- null,
627
- 2,
628
- ) + "\n",
629
- );
630
- process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = explicit;
672
+ activeProfile: "balanced",
673
+ },
674
+ });
675
+
631
676
  mergeDefaultConfigAndSeedInferenceProfiles();
632
- raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
633
- expect(raw.llm.activeProfile).toBe("balanced");
634
- expect(raw.llm.default.model).toBe("gpt-5.4");
677
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
678
+
679
+ // Model still gets the new template value (provider-controlled).
680
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
681
+ // But the user's label override is preserved across the reseed.
682
+ expect(raw.llm.profiles.balanced.label).toBe("My Default");
683
+ });
684
+
685
+ test("off-platform reseed preserves user-toggled status on managed profiles", () => {
686
+ // Simulate a user who disabled the managed "balanced" profile via
687
+ // PUT /v1/config/llm/profiles/balanced { status: "disabled" }.
688
+ writeConfig({
689
+ llm: {
690
+ profiles: {
691
+ balanced: {
692
+ source: "managed",
693
+ provider: "anthropic",
694
+ model: "old-model-from-previous-release",
695
+ provider_connection: "anthropic-managed",
696
+ status: "disabled",
697
+ },
698
+ },
699
+ activeProfile: "balanced",
700
+ },
701
+ });
702
+
703
+ mergeDefaultConfigAndSeedInferenceProfiles();
704
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
705
+
706
+ expect(raw.llm.profiles.balanced.status).toBe("disabled");
707
+ // Model still refreshes — only label/status are user-owned.
708
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
709
+ });
710
+
711
+ test("off-platform reseed preserves an explicit null label (user cleared it)", () => {
712
+ // Setting label to null is the "clear" intent — must survive too,
713
+ // otherwise the next boot would re-stamp the template's default
714
+ // label and ignore the user's clear action.
715
+ writeConfig({
716
+ llm: {
717
+ profiles: {
718
+ balanced: {
719
+ source: "managed",
720
+ provider: "anthropic",
721
+ model: "old-model",
722
+ provider_connection: "anthropic-managed",
723
+ label: null,
724
+ },
725
+ },
726
+ activeProfile: "balanced",
727
+ },
728
+ });
729
+
730
+ mergeDefaultConfigAndSeedInferenceProfiles();
731
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
732
+
733
+ expect(raw.llm.profiles.balanced.label).toBeNull();
734
+ });
735
+
736
+ test("off-platform reseed materializes template defaults with the BYOK label suffix when no user overrides exist", () => {
737
+ // First boot, no prior config — template defaults must materialize
738
+ // exactly. Off-platform installs get the " (Managed)" suffix so the
739
+ // managed profile is distinguishable from the personal "custom-*"
740
+ // sibling that shares the base label. Guards against accidentally
741
+ // clobbering template values with `undefined` from a `"label" in
742
+ // previous` check when previous is an empty shell.
743
+ writeConfig({});
744
+
745
+ mergeDefaultConfigAndSeedInferenceProfiles();
746
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
747
+
748
+ expect(raw.llm.profiles.balanced.label).toBe("Balanced (Managed)");
749
+ expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
750
+ // Status is unset by default — must not appear as `undefined`.
751
+ expect("status" in raw.llm.profiles.balanced).toBe(false);
635
752
  });
636
753
 
637
754
  test("platform-provided profile fragments are not polluted by managed seeds", () => {
755
+ process.env.IS_PLATFORM = "true";
756
+
638
757
  writeConfig({
639
758
  llm: {
640
759
  default: {
@@ -751,7 +870,9 @@ describe("loadConfig startup behavior", () => {
751
870
  provider: "anthropic",
752
871
  model: "claude-opus-4-7",
753
872
  });
754
- expect(raw.llm.activeProfile).toBe("balanced");
873
+ // Off-platform hatch: user profiles are active.
874
+ expect(raw.llm.activeProfile).toBe("custom-balanced");
875
+ expect(raw.llm.profiles["custom-balanced"].provider).toBe("anthropic");
755
876
  expect(raw.llm.profiles.balanced.model).toBe("claude-sonnet-4-6");
756
877
  });
757
878
 
@@ -775,3 +896,306 @@ describe("loadConfig startup behavior", () => {
775
896
  expect(quarantined.length).toBeGreaterThan(0);
776
897
  });
777
898
  });
899
+
900
+ // ---------------------------------------------------------------------------
901
+ // Tests: BYOK-mode seed behavior (issues #2/#3/#4 of the May 12 provider UX
902
+ // queue). Off-platform managed profiles share base labels with the personal
903
+ // "custom-*" profiles (Balanced / Quality / Speed), so the seed function
904
+ // suffixes managed labels with " (Managed)" to disambiguate. Status is
905
+ // initialized to "disabled" ONLY at hatch on first materialization — a fresh
906
+ // BYOK user has no platform auth, so we don't want managed entries surfacing
907
+ // as enabled in the picker on day one. Post-hatch user toggles persist
908
+ // through every subsequent boot — the "never auto-disable BYOK connections"
909
+ // rule applies to RESTART, not to hatch. On-platform behavior is unchanged.
910
+ // ---------------------------------------------------------------------------
911
+
912
+ describe("seedInferenceProfiles BYOK-mode managed profile labels", () => {
913
+ beforeEach(() => {
914
+ ensureTestDir();
915
+ const resetPaths = [
916
+ CONFIG_PATH,
917
+ join(WORKSPACE_DIR, "default-config.json"),
918
+ join(WORKSPACE_DIR, "hatch-overlay.json"),
919
+ join(WORKSPACE_DIR, "keys.enc"),
920
+ join(WORKSPACE_DIR, "data"),
921
+ join(WORKSPACE_DIR, "data", "memory"),
922
+ ];
923
+ for (const path of resetPaths) {
924
+ if (existsSync(path)) {
925
+ rmSync(path, { recursive: true, force: true });
926
+ }
927
+ }
928
+ ensureTestDir();
929
+ _setStorePath(join(WORKSPACE_DIR, "keys.enc"));
930
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
931
+ delete process.env.IS_PLATFORM;
932
+ invalidateConfigCache();
933
+ });
934
+
935
+ afterEach(() => {
936
+ _setStorePath(null);
937
+ delete process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH;
938
+ delete process.env.IS_PLATFORM;
939
+ invalidateConfigCache();
940
+ });
941
+
942
+ test("off-platform hatch suffixes managed profile labels with ' (Managed)'", () => {
943
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
944
+ writeFileSync(
945
+ overlayPath,
946
+ JSON.stringify(
947
+ {
948
+ llm: {
949
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
950
+ },
951
+ },
952
+ null,
953
+ 2,
954
+ ) + "\n",
955
+ );
956
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
957
+
958
+ mergeDefaultConfigAndSeedInferenceProfiles();
959
+ const config = loadConfig();
960
+
961
+ // Managed profile labels carry the suffix so they're visibly distinct
962
+ // from the personal "custom-*" profiles (which retain bare labels).
963
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
964
+ expect(config.llm.profiles["quality-optimized"]?.label).toBe(
965
+ "Quality (Managed)",
966
+ );
967
+ expect(config.llm.profiles["cost-optimized"]?.label).toBe(
968
+ "Speed (Managed)",
969
+ );
970
+
971
+ // Personal profiles keep their bare labels — they're the daily driver.
972
+ expect(config.llm.profiles["custom-balanced"]?.label).toBe("Balanced");
973
+ });
974
+
975
+ test("off-platform hatch initializes managed profile status to 'disabled'", () => {
976
+ // On a fresh BYOK hatch the user has no platform auth, so managed
977
+ // profiles must not surface as enabled in the picker on day one. We
978
+ // flip the three canonical managed profiles to status="disabled"
979
+ // ONCE at hatch time. (The complementary "user re-enable persists
980
+ // across restarts" guarantee is covered by the test further down.)
981
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
982
+ writeFileSync(
983
+ overlayPath,
984
+ JSON.stringify(
985
+ { llm: { default: { provider: "anthropic" } } },
986
+ null,
987
+ 2,
988
+ ) + "\n",
989
+ );
990
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
991
+
992
+ mergeDefaultConfigAndSeedInferenceProfiles();
993
+ const config = loadConfig();
994
+
995
+ expect(config.llm.profiles.balanced?.status).toBe("disabled");
996
+ expect(config.llm.profiles["quality-optimized"]?.status).toBe("disabled");
997
+ expect(config.llm.profiles["cost-optimized"]?.status).toBe("disabled");
998
+ });
999
+
1000
+ test("non-hatch off-platform boot does NOT auto-disable freshly-materialized managed profiles", () => {
1001
+ // Existing installs that upgrade to a version where the managed
1002
+ // profile didn't previously exist (e.g. a new template added later)
1003
+ // must not be auto-disabled on a normal boot. The hatch-time disable
1004
+ // is gated on `isHatch && !previous`; without an overlay there's no
1005
+ // hatch signal, so the seeder leaves status unset (schema default
1006
+ // = "active"). This is the "we never want to auto-disable BYOK
1007
+ // connections on restart" guarantee.
1008
+ writeConfig({
1009
+ llm: {
1010
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1011
+ // Note: no `profiles` key — the managed profiles will be freshly
1012
+ // materialized by seedInferenceProfiles. !previous is true for all
1013
+ // three, but isHatch is false, so disable does NOT fire.
1014
+ },
1015
+ });
1016
+
1017
+ // No overlay → not a hatch.
1018
+ mergeDefaultConfigAndSeedInferenceProfiles();
1019
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1020
+
1021
+ expect("status" in raw.llm.profiles.balanced).toBe(false);
1022
+ expect("status" in raw.llm.profiles["quality-optimized"]).toBe(false);
1023
+ expect("status" in raw.llm.profiles["cost-optimized"]).toBe(false);
1024
+ });
1025
+
1026
+ test("on-platform hatch leaves managed labels untouched", () => {
1027
+ process.env.IS_PLATFORM = "true";
1028
+
1029
+ const overlayPath = join(WORKSPACE_DIR, "hatch-overlay.json");
1030
+ writeFileSync(
1031
+ overlayPath,
1032
+ JSON.stringify(
1033
+ { llm: { default: { provider: "anthropic" } } },
1034
+ null,
1035
+ 2,
1036
+ ) + "\n",
1037
+ );
1038
+ process.env.VELLUM_DEFAULT_WORKSPACE_CONFIG_PATH = overlayPath;
1039
+
1040
+ mergeDefaultConfigAndSeedInferenceProfiles();
1041
+ const config = loadConfig();
1042
+
1043
+ // No "(Managed)" suffix on platform — the personal profiles don't exist
1044
+ // here so there's nothing to disambiguate from.
1045
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced");
1046
+ expect(config.llm.profiles["quality-optimized"]?.label).toBe("Quality");
1047
+ expect(config.llm.profiles["cost-optimized"]?.label).toBe("Speed");
1048
+ });
1049
+
1050
+ test("upgrade boot rewrites legacy bare labels to suffixed form on off-platform", () => {
1051
+ // Existing off-platform install (pre-suffix-PR) has `label: "Balanced"`
1052
+ // on disk. The "label" in previous preservation would normally keep
1053
+ // the bare label and the picker would stay ambiguous forever — so the
1054
+ // seeder runs a one-shot upgrade migration when previous.label exactly
1055
+ // equals the bare template default. User-customized labels and
1056
+ // explicit nulls are NOT rewritten.
1057
+ writeConfig({
1058
+ llm: {
1059
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1060
+ profiles: {
1061
+ balanced: {
1062
+ source: "managed",
1063
+ provider: "anthropic",
1064
+ provider_connection: "anthropic-managed",
1065
+ model: "claude-sonnet-4-6",
1066
+ label: "Balanced",
1067
+ },
1068
+ "quality-optimized": {
1069
+ source: "managed",
1070
+ provider: "anthropic",
1071
+ provider_connection: "anthropic-managed",
1072
+ label: "Quality",
1073
+ },
1074
+ "cost-optimized": {
1075
+ source: "managed",
1076
+ provider: "anthropic",
1077
+ provider_connection: "anthropic-managed",
1078
+ label: "Speed",
1079
+ },
1080
+ },
1081
+ activeProfile: "balanced",
1082
+ },
1083
+ });
1084
+
1085
+ // No overlay → not a hatch. Still upgrades labels.
1086
+ mergeDefaultConfigAndSeedInferenceProfiles();
1087
+ const config = loadConfig();
1088
+
1089
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
1090
+ expect(config.llm.profiles["quality-optimized"]?.label).toBe(
1091
+ "Quality (Managed)",
1092
+ );
1093
+ expect(config.llm.profiles["cost-optimized"]?.label).toBe(
1094
+ "Speed (Managed)",
1095
+ );
1096
+ });
1097
+
1098
+ test("upgrade boot preserves user-customized labels and explicit null on off-platform", () => {
1099
+ // A user-set string that differs from the bare default must survive;
1100
+ // an explicit null (user cleared the label) must also survive. Only
1101
+ // exact matches against the bare template label trigger the upgrade.
1102
+ writeConfig({
1103
+ llm: {
1104
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1105
+ profiles: {
1106
+ balanced: {
1107
+ source: "managed",
1108
+ provider: "anthropic",
1109
+ provider_connection: "anthropic-managed",
1110
+ model: "claude-sonnet-4-6",
1111
+ label: "My Balanced",
1112
+ },
1113
+ "quality-optimized": {
1114
+ source: "managed",
1115
+ provider: "anthropic",
1116
+ provider_connection: "anthropic-managed",
1117
+ label: null,
1118
+ },
1119
+ // Already-suffixed labels are also preserved (idempotency).
1120
+ "cost-optimized": {
1121
+ source: "managed",
1122
+ provider: "anthropic",
1123
+ provider_connection: "anthropic-managed",
1124
+ label: "Speed (Managed)",
1125
+ },
1126
+ },
1127
+ activeProfile: "balanced",
1128
+ },
1129
+ });
1130
+
1131
+ mergeDefaultConfigAndSeedInferenceProfiles();
1132
+ const raw = JSON.parse(readFileSync(CONFIG_PATH, "utf-8"));
1133
+
1134
+ expect(raw.llm.profiles.balanced.label).toBe("My Balanced");
1135
+ expect(raw.llm.profiles["quality-optimized"].label).toBeNull();
1136
+ expect(raw.llm.profiles["cost-optimized"].label).toBe("Speed (Managed)");
1137
+ });
1138
+
1139
+ test("upgrade boot does NOT rewrite bare labels on platform", () => {
1140
+ // The migration is gated on isByokMode, so an on-platform install with
1141
+ // a bare "Balanced" label preserves it (no suffix on platform).
1142
+ process.env.IS_PLATFORM = "true";
1143
+ writeConfig({
1144
+ llm: {
1145
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1146
+ profiles: {
1147
+ balanced: {
1148
+ source: "managed",
1149
+ provider: "anthropic",
1150
+ provider_connection: "anthropic-managed",
1151
+ model: "claude-sonnet-4-6",
1152
+ label: "Balanced",
1153
+ },
1154
+ },
1155
+ activeProfile: "balanced",
1156
+ },
1157
+ });
1158
+
1159
+ mergeDefaultConfigAndSeedInferenceProfiles();
1160
+ const config = loadConfig();
1161
+
1162
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced");
1163
+ });
1164
+
1165
+ test("subsequent off-platform boot preserves user-set status on managed profiles", () => {
1166
+ // Simulate a user who hatched yesterday, then re-enabled the managed
1167
+ // Balanced profile (they have platform auth via a separate route).
1168
+ writeConfig({
1169
+ llm: {
1170
+ default: { provider: "anthropic", model: "claude-opus-4-7" },
1171
+ profiles: {
1172
+ balanced: {
1173
+ source: "managed",
1174
+ provider: "anthropic",
1175
+ provider_connection: "anthropic-managed",
1176
+ model: "claude-sonnet-4-6",
1177
+ label: "Balanced (Managed)",
1178
+ status: "active",
1179
+ },
1180
+ "custom-balanced": {
1181
+ source: "user",
1182
+ provider: "anthropic",
1183
+ provider_connection: "anthropic-personal",
1184
+ model: "claude-sonnet-4-6",
1185
+ label: "Balanced",
1186
+ },
1187
+ },
1188
+ activeProfile: "balanced",
1189
+ },
1190
+ });
1191
+
1192
+ // No overlay → this is a normal boot, not a hatch.
1193
+ mergeDefaultConfigAndSeedInferenceProfiles();
1194
+ const config = loadConfig();
1195
+
1196
+ // User's "active" decision survives the boot upsert.
1197
+ expect(config.llm.profiles.balanced?.status).toBe("active");
1198
+ // Label is still suffixed (Vellum can push label updates).
1199
+ expect(config.llm.profiles.balanced?.label).toBe("Balanced (Managed)");
1200
+ });
1201
+ });