@vellumai/assistant 0.7.3 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (778) hide show
  1. package/AGENTS.md +11 -0
  2. package/ARCHITECTURE.md +29 -28
  3. package/Dockerfile +6 -4
  4. package/README.md +2 -2
  5. package/__tests__/permissions/gateway-threshold-reader.test.ts +236 -9
  6. package/bun.lock +3 -0
  7. package/docker-entrypoint.sh +16 -0
  8. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  9. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  10. package/eslint.config.mjs +12 -0
  11. package/knip.json +3 -1
  12. package/node_modules/@vellumai/ipc-server-utils/bun.lock +24 -0
  13. package/node_modules/@vellumai/ipc-server-utils/package.json +18 -0
  14. package/node_modules/@vellumai/ipc-server-utils/src/index.ts +6 -0
  15. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.test.ts +430 -0
  16. package/node_modules/@vellumai/ipc-server-utils/src/socket-watchdog.ts +221 -0
  17. package/node_modules/@vellumai/ipc-server-utils/tsconfig.json +20 -0
  18. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  19. package/openapi.yaml +4126 -959
  20. package/package.json +5 -1
  21. package/scripts/generate-openapi.ts +52 -4
  22. package/scripts/sync-llm-catalog.ts +165 -0
  23. package/scripts/sync-web-search-catalog.ts +107 -0
  24. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  25. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  26. package/src/__tests__/annotate-risk-options.test.ts +291 -0
  27. package/src/__tests__/anthropic-provider.test.ts +92 -2
  28. package/src/__tests__/app-control-flow.test.ts +7 -0
  29. package/src/__tests__/approval-cascade.test.ts +8 -16
  30. package/src/__tests__/approval-routes-http.test.ts +6 -0
  31. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  32. package/src/__tests__/auto-analysis-end-to-end.test.ts +12 -25
  33. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  34. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  35. package/src/__tests__/btw-routes.test.ts +1 -0
  36. package/src/__tests__/call-constants.test.ts +10 -1
  37. package/src/__tests__/call-controller.test.ts +127 -0
  38. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  39. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  40. package/src/__tests__/channel-policy.test.ts +12 -0
  41. package/src/__tests__/checker.test.ts +89 -0
  42. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +88 -30
  43. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  44. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  45. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  46. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  47. package/src/__tests__/config-loader-platform-defaults.test.ts +345 -8
  48. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  49. package/src/__tests__/config-schema.test.ts +14 -3
  50. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  51. package/src/__tests__/config-set-route.test.ts +198 -0
  52. package/src/__tests__/config-watcher.test.ts +6 -0
  53. package/src/__tests__/contacts-tools.test.ts +51 -199
  54. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  55. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  56. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  57. package/src/__tests__/context-search-fanout.test.ts +20 -157
  58. package/src/__tests__/context-search-memory-source.test.ts +3 -26
  59. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  60. package/src/__tests__/context-search-types.test.ts +7 -2
  61. package/src/__tests__/context-window-manager.test.ts +389 -1
  62. package/src/__tests__/conversation-abort-tool-results.test.ts +1 -6
  63. package/src/__tests__/conversation-agent-loop-inference-profile.test.ts +1 -1
  64. package/src/__tests__/conversation-agent-loop-overflow.test.ts +2 -1
  65. package/src/__tests__/conversation-agent-loop.test.ts +3 -3
  66. package/src/__tests__/conversation-confirmation-signals.test.ts +5 -13
  67. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  68. package/src/__tests__/conversation-error.test.ts +38 -0
  69. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  70. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  71. package/src/__tests__/conversation-init.benchmark.test.ts +2 -1
  72. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  73. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  74. package/src/__tests__/conversation-process-callsite.test.ts +22 -7
  75. package/src/__tests__/conversation-provider-retry-repair.test.ts +1 -6
  76. package/src/__tests__/conversation-runtime-assembly.test.ts +19 -10
  77. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  78. package/src/__tests__/conversation-slash-unknown.test.ts +1 -6
  79. package/src/__tests__/conversation-surfaces-action-delivery.test.ts +170 -9
  80. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  81. package/src/__tests__/conversation-surfaces-data-persist.test.ts +73 -1
  82. package/src/__tests__/conversation-tool-setup-app-refresh.test.ts +59 -0
  83. package/src/__tests__/conversation-workspace-injection.test.ts +1 -7
  84. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +1 -7
  85. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  86. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  87. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  88. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  89. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  90. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  91. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  92. package/src/__tests__/filing-service.test.ts +25 -22
  93. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  94. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  95. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  96. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +10 -34
  97. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  98. package/src/__tests__/heartbeat-service.test.ts +50 -233
  99. package/src/__tests__/history-repair.test.ts +89 -0
  100. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  101. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  102. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  103. package/src/__tests__/host-browser-routes.test.ts +325 -33
  104. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  105. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  106. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  107. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  108. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  109. package/src/__tests__/injector-chain.test.ts +24 -16
  110. package/src/__tests__/injector-pkb-v2-silenced.test.ts +10 -7
  111. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  112. package/src/__tests__/install-skill-routing.test.ts +2 -2
  113. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +169 -67
  114. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  115. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  116. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  117. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  118. package/src/__tests__/llm-resolver.test.ts +46 -0
  119. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  120. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  121. package/src/__tests__/mcp-cli.test.ts +182 -220
  122. package/src/__tests__/mcp-health-check.test.ts +56 -27
  123. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  124. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  125. package/src/__tests__/notification-decision-fallback.test.ts +91 -0
  126. package/src/__tests__/notification-decision-strategy.test.ts +22 -0
  127. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  128. package/src/__tests__/oauth-cli.test.ts +38 -1888
  129. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  130. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  131. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  132. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  133. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  134. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  135. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  136. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  137. package/src/__tests__/plugin-types.test.ts +13 -11
  138. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  139. package/src/__tests__/profile-entry-status.test.ts +43 -0
  140. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  141. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  142. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  143. package/src/__tests__/relay-server.test.ts +164 -2
  144. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  145. package/src/__tests__/schedule-retry.test.ts +56 -4
  146. package/src/__tests__/schedule-routes.test.ts +104 -0
  147. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  148. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  149. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  150. package/src/__tests__/scheduler-wake.test.ts +0 -63
  151. package/src/__tests__/secret-allowlist.test.ts +1 -0
  152. package/src/__tests__/secret-prompt-log-hygiene.test.ts +7 -5
  153. package/src/__tests__/secret-prompter-channel-fallback.test.ts +7 -5
  154. package/src/__tests__/secret-response-routing.test.ts +7 -5
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  156. package/src/__tests__/server-history-render.test.ts +82 -0
  157. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  158. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  159. package/src/__tests__/skill-include-graph.test.ts +31 -0
  160. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  161. package/src/__tests__/skill-load-tool.test.ts +42 -16
  162. package/src/__tests__/skills.test.ts +39 -0
  163. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  164. package/src/__tests__/suggestion-routes.test.ts +3 -3
  165. package/src/__tests__/sync-message-contract.test.ts +63 -0
  166. package/src/__tests__/task-scheduler.test.ts +88 -23
  167. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +0 -42
  168. package/src/__tests__/tool-executor.test.ts +155 -0
  169. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  170. package/src/__tests__/usage-cli.test.ts +11 -73
  171. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  172. package/src/__tests__/vercel-config.test.ts +168 -0
  173. package/src/__tests__/voice-session-bridge.test.ts +3 -0
  174. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  175. package/src/__tests__/web-search.test.ts +303 -2
  176. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  177. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  178. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +153 -0
  179. package/src/__tests__/workspace-migration-071-remove-safe-storage-release-note.test.ts +206 -0
  180. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  181. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  182. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  183. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  184. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  185. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  186. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  187. package/src/__tests__/workspace-migration-safe-storage-limits-release.test.ts +15 -27
  188. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  189. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  190. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  191. package/src/acp/resolve-agent.test.ts +25 -0
  192. package/src/acp/resolve-agent.ts +13 -2
  193. package/src/acp/session-manager.ts +14 -0
  194. package/src/agent/loop.ts +11 -0
  195. package/src/approvals/guardian-decision-primitive.ts +0 -13
  196. package/src/approvals/guardian-request-resolvers.ts +19 -102
  197. package/src/calls/call-constants.ts +5 -8
  198. package/src/calls/call-controller.ts +130 -67
  199. package/src/calls/relay-server.ts +42 -1
  200. package/src/calls/relay-setup-router.ts +36 -0
  201. package/src/calls/types.ts +1 -0
  202. package/src/calls/voice-session-bridge.ts +24 -5
  203. package/src/channels/config.ts +14 -1
  204. package/src/channels/types.ts +1 -0
  205. package/src/cli/AGENTS.md +164 -4
  206. package/src/cli/__tests__/notifications.test.ts +54 -0
  207. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  208. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  209. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  210. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  211. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  212. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  213. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  214. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  215. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  216. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  217. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  218. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  219. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  220. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  221. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  222. package/src/cli/commands/__tests__/status.test.ts +249 -0
  223. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  224. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  225. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  226. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  227. package/src/cli/commands/attachment.ts +8 -3
  228. package/src/cli/commands/audit.ts +95 -64
  229. package/src/cli/commands/auth.ts +61 -58
  230. package/src/cli/commands/avatar.ts +276 -390
  231. package/src/cli/commands/backup.ts +409 -505
  232. package/src/cli/commands/bash.ts +9 -5
  233. package/src/cli/commands/browser.ts +28 -9
  234. package/src/cli/commands/cache.ts +9 -4
  235. package/src/cli/commands/changelog.ts +414 -0
  236. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  237. package/src/cli/commands/clients.ts +8 -3
  238. package/src/cli/commands/completions.ts +9 -9
  239. package/src/cli/commands/config.ts +102 -72
  240. package/src/cli/commands/contacts.ts +575 -696
  241. package/src/cli/commands/conversations-defer.ts +17 -69
  242. package/src/cli/commands/conversations-import.ts +90 -253
  243. package/src/cli/commands/conversations.ts +346 -436
  244. package/src/cli/commands/credential-execution.ts +9 -6
  245. package/src/cli/commands/credentials.ts +456 -736
  246. package/src/cli/commands/domain.ts +128 -206
  247. package/src/cli/commands/email.ts +606 -794
  248. package/src/cli/commands/gateway.ts +8 -1
  249. package/src/cli/commands/image-generation.ts +157 -205
  250. package/src/cli/commands/inference-providers.ts +352 -0
  251. package/src/cli/commands/inference-session.ts +415 -0
  252. package/src/cli/commands/inference.ts +87 -65
  253. package/src/cli/commands/keys.ts +8 -3
  254. package/src/cli/commands/mcp.ts +103 -287
  255. package/src/cli/commands/memory-v2.ts +163 -517
  256. package/src/cli/commands/notifications.ts +33 -7
  257. package/src/cli/commands/oauth/apps.ts +292 -261
  258. package/src/cli/commands/oauth/connect.ts +182 -345
  259. package/src/cli/commands/oauth/disconnect.ts +16 -215
  260. package/src/cli/commands/oauth/index.ts +49 -45
  261. package/src/cli/commands/oauth/mode.ts +43 -199
  262. package/src/cli/commands/oauth/ping.ts +17 -125
  263. package/src/cli/commands/oauth/providers.ts +732 -921
  264. package/src/cli/commands/oauth/request.ts +60 -350
  265. package/src/cli/commands/oauth/shared.ts +11 -121
  266. package/src/cli/commands/oauth/status.ts +31 -121
  267. package/src/cli/commands/oauth/token.ts +13 -55
  268. package/src/cli/commands/pending.ts +19 -10
  269. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  270. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  271. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  272. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  273. package/src/cli/commands/platform/connect.ts +16 -80
  274. package/src/cli/commands/platform/disconnect.ts +14 -112
  275. package/src/cli/commands/platform/index.ts +177 -246
  276. package/src/cli/commands/routes.ts +153 -336
  277. package/src/cli/commands/sequence.ts +316 -360
  278. package/src/cli/commands/skills.ts +449 -671
  279. package/src/cli/commands/status.ts +58 -37
  280. package/src/cli/commands/stt.ts +94 -262
  281. package/src/cli/commands/task.ts +14 -40
  282. package/src/cli/commands/trust.ts +8 -3
  283. package/src/cli/commands/tts.ts +162 -167
  284. package/src/cli/commands/ui.ts +35 -42
  285. package/src/cli/commands/usage.ts +188 -126
  286. package/src/cli/commands/watchers.ts +8 -3
  287. package/src/cli/commands/webhooks.ts +99 -193
  288. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  289. package/src/cli/lib/daemon-credential-client.ts +4 -5
  290. package/src/cli/lib/nested-value.ts +44 -0
  291. package/src/cli/lib/open-browser.ts +36 -0
  292. package/src/cli/lib/register-command.ts +19 -0
  293. package/src/cli/lib/time-ago.ts +34 -0
  294. package/src/cli/program.ts +2 -4
  295. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  296. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  297. package/src/cli/utils/conversation-id.ts +30 -0
  298. package/src/cli/utils/parse-duration.ts +41 -0
  299. package/src/config/acp-defaults.test.ts +5 -1
  300. package/src/config/acp-defaults.ts +11 -4
  301. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  302. package/src/config/bundled-skills/app-builder/SKILL.md +1 -3
  303. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  304. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  305. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  306. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  307. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  308. package/src/config/bundled-tool-registry.ts +0 -2
  309. package/src/config/feature-flag-registry.json +17 -17
  310. package/src/config/llm-resolver.ts +16 -1
  311. package/src/config/loader.ts +148 -33
  312. package/src/config/raw-config-utils.ts +2 -30
  313. package/src/config/schema.ts +4 -0
  314. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  315. package/src/config/schemas/call-site-catalog.ts +29 -7
  316. package/src/config/schemas/llm-request-logs.ts +57 -0
  317. package/src/config/schemas/llm.ts +52 -2
  318. package/src/config/schemas/memory-retrospective.ts +48 -0
  319. package/src/config/schemas/memory-v2.ts +33 -2
  320. package/src/config/schemas/memory.ts +4 -0
  321. package/src/config/schemas/services.ts +15 -12
  322. package/src/config/seed-inference-profiles.ts +195 -134
  323. package/src/contacts/contact-store.ts +0 -61
  324. package/src/context/window-manager.ts +191 -5
  325. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +111 -0
  326. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  327. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  328. package/src/daemon/approval-generators.ts +23 -29
  329. package/src/daemon/config-watcher.ts +2 -0
  330. package/src/daemon/conversation-agent-loop-handlers.ts +56 -0
  331. package/src/daemon/conversation-agent-loop.ts +140 -107
  332. package/src/daemon/conversation-error.ts +21 -0
  333. package/src/daemon/conversation-lifecycle.ts +68 -13
  334. package/src/daemon/conversation-process.ts +36 -19
  335. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  336. package/src/daemon/conversation-slash.ts +175 -23
  337. package/src/daemon/conversation-store.ts +17 -10
  338. package/src/daemon/conversation-surfaces.ts +92 -26
  339. package/src/daemon/conversation-tool-setup.ts +33 -19
  340. package/src/daemon/conversation.ts +49 -10
  341. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  342. package/src/daemon/guardian-action-generators.ts +7 -22
  343. package/src/daemon/handlers/config-model.ts +8 -126
  344. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  345. package/src/daemon/handlers/config-vercel.ts +3 -1
  346. package/src/daemon/handlers/shared.ts +26 -0
  347. package/src/daemon/handlers/skills.ts +84 -5
  348. package/src/daemon/history-repair.ts +33 -6
  349. package/src/daemon/host-app-control-proxy.ts +44 -19
  350. package/src/daemon/host-bash-proxy.ts +85 -158
  351. package/src/daemon/host-browser-proxy.ts +97 -36
  352. package/src/daemon/host-cu-proxy.ts +1 -1
  353. package/src/daemon/host-file-proxy.ts +1 -1
  354. package/src/daemon/host-proxy-base.ts +13 -1
  355. package/src/daemon/host-proxy-preactivation.ts +25 -1
  356. package/src/daemon/host-transfer-proxy.ts +2 -2
  357. package/src/daemon/identity-helpers.ts +19 -0
  358. package/src/daemon/lifecycle.ts +128 -114
  359. package/src/daemon/meet-host-supervisor.ts +15 -15
  360. package/src/daemon/memory-v2-startup.ts +62 -14
  361. package/src/daemon/message-protocol.ts +6 -0
  362. package/src/daemon/message-types/bookmarks.ts +18 -0
  363. package/src/daemon/message-types/conversations.ts +12 -9
  364. package/src/daemon/message-types/messages.ts +28 -2
  365. package/src/daemon/message-types/sync.ts +60 -0
  366. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  367. package/src/daemon/pkb-reminder-builder.ts +21 -7
  368. package/src/daemon/process-message.ts +56 -23
  369. package/src/daemon/server.ts +23 -18
  370. package/src/daemon/shutdown-handlers.ts +0 -2
  371. package/src/daemon/tool-setup-types.ts +9 -0
  372. package/src/daemon/tool-side-effects.ts +6 -4
  373. package/src/daemon/wake-target-adapter.ts +11 -0
  374. package/src/documents/document-store.ts +35 -1
  375. package/src/export/transcript-formatter.ts +61 -2
  376. package/src/filing/filing-service.ts +42 -56
  377. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  378. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  379. package/src/heartbeat/heartbeat-service.ts +149 -128
  380. package/src/home/__tests__/feed-types.test.ts +63 -131
  381. package/src/home/__tests__/feed-writer.test.ts +77 -278
  382. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  383. package/src/home/feed-types.ts +19 -73
  384. package/src/home/feed-writer.ts +25 -156
  385. package/src/home/post-connect-feed.ts +1 -3
  386. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  387. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  388. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  389. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  390. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  391. package/src/ipc/assistant-server.ts +148 -42
  392. package/src/ipc/cli-client.ts +370 -50
  393. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  394. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  395. package/src/ipc/skill-routes/events.ts +30 -3
  396. package/src/ipc/skill-server.ts +99 -42
  397. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  398. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  399. package/src/live-voice/live-voice-session-manager.ts +11 -4
  400. package/src/live-voice/live-voice-session.ts +14 -6
  401. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  402. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  403. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  404. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  405. package/src/memory/__tests__/jobs-worker-v2-schedule.test.ts +10 -57
  406. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  407. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  408. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  409. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  410. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  411. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  412. package/src/memory/bookmark-crud.ts +179 -0
  413. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  414. package/src/memory/context-search/agent-protocol.ts +5 -1
  415. package/src/memory/context-search/agent-runner.ts +60 -85
  416. package/src/memory/context-search/limits.ts +1 -4
  417. package/src/memory/context-search/search.ts +23 -113
  418. package/src/memory/context-search/sources/conversations.ts +18 -6
  419. package/src/memory/context-search/sources/memory-v2.ts +40 -31
  420. package/src/memory/context-search/sources/memory.ts +9 -2
  421. package/src/memory/context-search/sources/workspace.ts +13 -10
  422. package/src/memory/context-search/types.ts +1 -1
  423. package/src/memory/conversation-bootstrap.ts +11 -0
  424. package/src/memory/conversation-crud.ts +312 -10
  425. package/src/memory/conversation-queries.ts +9 -5
  426. package/src/memory/conversation-title-service.ts +1 -0
  427. package/src/memory/conversation-types.ts +16 -0
  428. package/src/memory/db-init.ts +14 -0
  429. package/src/memory/embedding-backend.ts +2 -1
  430. package/src/memory/embedding-runtime-manager.ts +1 -2
  431. package/src/memory/graph/__tests__/conversation-graph-memory-v2-routing.test.ts +104 -61
  432. package/src/memory/graph/__tests__/handle-remember-v2.test.ts +11 -26
  433. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  434. package/src/memory/graph/conversation-graph-memory.ts +108 -14
  435. package/src/memory/graph/extraction.ts +4 -0
  436. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  437. package/src/memory/graph/graph-search.test.ts +6 -5
  438. package/src/memory/graph/graph-search.ts +3 -4
  439. package/src/memory/graph/retriever.test.ts +12 -7
  440. package/src/memory/graph/retriever.ts +4 -5
  441. package/src/memory/graph/tool-handlers.ts +20 -11
  442. package/src/memory/graph/tools.ts +48 -9
  443. package/src/memory/indexer.ts +18 -2
  444. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +120 -6
  445. package/src/memory/jobs/embed-concept-page.ts +261 -89
  446. package/src/memory/jobs-store.ts +51 -1
  447. package/src/memory/jobs-worker.ts +60 -7
  448. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  449. package/src/memory/llm-request-log-source-local.ts +26 -0
  450. package/src/memory/llm-request-log-source.ts +97 -0
  451. package/src/memory/llm-request-log-store.ts +1 -1
  452. package/src/memory/memory-retrospective-constants.ts +13 -0
  453. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  454. package/src/memory/memory-retrospective-job.ts +351 -0
  455. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  456. package/src/memory/memory-retrospective-state.ts +162 -0
  457. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  458. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  459. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  460. package/src/memory/message-content.ts +38 -1
  461. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  462. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  463. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  464. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  465. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  466. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  467. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  468. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  469. package/src/memory/migrations/243-provider-connections.ts +68 -0
  470. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  471. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  472. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  473. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  474. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  475. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  476. package/src/memory/migrations/index.ts +7 -0
  477. package/src/memory/pkb/pkb-search.test.ts +6 -5
  478. package/src/memory/pkb/pkb-search.ts +4 -5
  479. package/src/memory/published-pages-store.ts +16 -0
  480. package/src/memory/qdrant-client.ts +3 -0
  481. package/src/memory/schema/bookmarks.ts +38 -0
  482. package/src/memory/schema/conversations.ts +2 -0
  483. package/src/memory/schema/index.ts +2 -0
  484. package/src/memory/schema/inference.ts +29 -0
  485. package/src/memory/schema/memory-core.ts +9 -0
  486. package/src/memory/search/semantic.ts +5 -9
  487. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  488. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  489. package/src/memory/v2/__tests__/activation.test.ts +46 -9
  490. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  491. package/src/memory/v2/__tests__/consolidation-job.test.ts +140 -163
  492. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  493. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  494. package/src/memory/v2/__tests__/injection.test.ts +768 -33
  495. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  496. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  497. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  498. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  499. package/src/memory/v2/__tests__/qdrant.test.ts +382 -9
  500. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  501. package/src/memory/v2/__tests__/router.test.ts +516 -0
  502. package/src/memory/v2/__tests__/sim.test.ts +163 -8
  503. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  504. package/src/memory/v2/__tests__/static-context.test.ts +8 -35
  505. package/src/memory/v2/__tests__/sweep-job.test.ts +114 -33
  506. package/src/memory/v2/activation-store.ts +34 -5
  507. package/src/memory/v2/activation.ts +40 -27
  508. package/src/memory/v2/backfill-jobs.ts +17 -84
  509. package/src/memory/v2/consolidation-job.ts +92 -86
  510. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  511. package/src/memory/v2/injection.ts +466 -115
  512. package/src/memory/v2/migration.ts +117 -20
  513. package/src/memory/v2/page-index.ts +191 -0
  514. package/src/memory/v2/page-store.ts +42 -0
  515. package/src/memory/v2/prompts/consolidation.ts +14 -7
  516. package/src/memory/v2/prompts/router.ts +192 -0
  517. package/src/memory/v2/qdrant.ts +307 -133
  518. package/src/memory/v2/reranker.ts +14 -7
  519. package/src/memory/v2/router.ts +322 -0
  520. package/src/memory/v2/sim.ts +88 -34
  521. package/src/memory/v2/skill-store.ts +118 -29
  522. package/src/memory/v2/static-context.ts +20 -17
  523. package/src/memory/v2/sweep-job.ts +127 -102
  524. package/src/memory/v2/types.ts +16 -5
  525. package/src/memory/validation.ts +13 -0
  526. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  527. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  528. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  529. package/src/notifications/adapters/platform.ts +171 -0
  530. package/src/notifications/conversation-pairing.ts +2 -2
  531. package/src/notifications/copy-composer.ts +61 -12
  532. package/src/notifications/decision-engine.ts +46 -0
  533. package/src/notifications/destination-resolver.ts +21 -0
  534. package/src/notifications/emit-signal.ts +28 -1
  535. package/src/notifications/home-feed-side-effect.ts +111 -0
  536. package/src/notifications/signal.ts +5 -0
  537. package/src/permissions/checker.ts +12 -0
  538. package/src/permissions/gateway-threshold-reader.ts +116 -8
  539. package/src/permissions/ipc-risk-types.ts +2 -0
  540. package/src/permissions/prompter.ts +86 -96
  541. package/src/permissions/secret-prompter.ts +31 -31
  542. package/src/plugin-api/index.ts +13 -0
  543. package/src/plugin-api/package.json +12 -0
  544. package/src/plugin-api/types.ts +62 -0
  545. package/src/plugins/defaults/injectors.ts +20 -5
  546. package/src/plugins/external-plugin-loader.ts +294 -0
  547. package/src/plugins/types.ts +46 -30
  548. package/src/plugins/user-loader.ts +64 -41
  549. package/src/proactive-artifact/job.test.ts +63 -8
  550. package/src/proactive-artifact/job.ts +20 -2
  551. package/src/proactive-artifact/message-copy.ts +18 -1
  552. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  553. package/src/proactive-artifact/trigger-state.ts +4 -0
  554. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  555. package/src/prompts/system-prompt.ts +22 -1
  556. package/src/prompts/templates/SOUL.md +13 -28
  557. package/src/prompts/update-bulletin-job.ts +61 -73
  558. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  559. package/src/providers/__tests__/inference.test.ts +288 -0
  560. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  561. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  562. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  563. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  564. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  565. package/src/providers/anthropic/client.ts +95 -26
  566. package/src/providers/call-site-routing.ts +94 -16
  567. package/src/providers/connection-resolution.ts +163 -0
  568. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  569. package/src/providers/inference/adapter-factory.ts +173 -0
  570. package/src/providers/inference/auth.ts +112 -0
  571. package/src/providers/inference/backfill.ts +196 -0
  572. package/src/providers/inference/connections.ts +356 -0
  573. package/src/providers/inference/resolve-auth.ts +65 -0
  574. package/src/providers/model-catalog.ts +104 -6
  575. package/src/providers/openai/responses-provider.ts +4 -2
  576. package/src/providers/provider-env-vars.ts +17 -7
  577. package/src/providers/provider-secret-catalog.ts +49 -30
  578. package/src/providers/provider-send-message.ts +41 -20
  579. package/src/providers/registry.ts +143 -159
  580. package/src/providers/retry.ts +18 -10
  581. package/src/providers/search-provider-catalog.ts +121 -0
  582. package/src/runtime/AGENTS.md +18 -5
  583. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  584. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  585. package/src/runtime/actor-trust-resolver.ts +32 -10
  586. package/src/runtime/agent-wake.ts +35 -6
  587. package/src/runtime/assistant-event-hub.ts +3 -85
  588. package/src/runtime/auth/route-policy.ts +304 -8
  589. package/src/runtime/auth/same-actor.ts +2 -0
  590. package/src/runtime/background-job-runner.ts +339 -0
  591. package/src/runtime/btw-sidechain.ts +1 -0
  592. package/src/runtime/channel-approvals.ts +3 -2
  593. package/src/runtime/guardian-reply-router.ts +0 -10
  594. package/src/runtime/http-router.ts +36 -1
  595. package/src/runtime/http-server.ts +31 -5
  596. package/src/runtime/http-types.ts +2 -0
  597. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  598. package/src/runtime/middleware/request-logger.ts +62 -1
  599. package/src/runtime/pending-interactions.ts +19 -15
  600. package/src/runtime/pre-first-message-gate.ts +83 -0
  601. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  602. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  603. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  604. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  605. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  606. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  607. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  608. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +147 -0
  609. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  610. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  611. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  612. package/src/runtime/routes/acp-routes.ts +10 -8
  613. package/src/runtime/routes/app-management-routes.ts +228 -3
  614. package/src/runtime/routes/approval-routes.ts +7 -21
  615. package/src/runtime/routes/audit-routes.ts +43 -0
  616. package/src/runtime/routes/auth-routes.ts +72 -0
  617. package/src/runtime/routes/avatar-routes.ts +273 -20
  618. package/src/runtime/routes/backup-routes.ts +406 -2
  619. package/src/runtime/routes/bookmark-routes.ts +154 -0
  620. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  621. package/src/runtime/routes/consolidation-routes.ts +8 -9
  622. package/src/runtime/routes/contact-routes.ts +0 -160
  623. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  624. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  625. package/src/runtime/routes/conversation-query-routes.ts +373 -82
  626. package/src/runtime/routes/conversation-routes.ts +31 -10
  627. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  628. package/src/runtime/routes/credential-routes.ts +540 -0
  629. package/src/runtime/routes/debug-bash-routes.ts +2 -0
  630. package/src/runtime/routes/debug-routes.ts +2 -2
  631. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  632. package/src/runtime/routes/domain-routes.ts +167 -0
  633. package/src/runtime/routes/email-routes.ts +603 -0
  634. package/src/runtime/routes/errors.ts +2 -2
  635. package/src/runtime/routes/events-routes.ts +192 -0
  636. package/src/runtime/routes/filing-routes.ts +2 -3
  637. package/src/runtime/routes/home-feed-routes.ts +6 -78
  638. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  639. package/src/runtime/routes/host-browser-routes.ts +103 -22
  640. package/src/runtime/routes/http-adapter.ts +2 -0
  641. package/src/runtime/routes/identity-routes.ts +5 -0
  642. package/src/runtime/routes/image-generation-routes.ts +99 -0
  643. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  644. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  645. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  646. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -7
  647. package/src/runtime/routes/index.ts +36 -0
  648. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  649. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  650. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  651. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  652. package/src/runtime/routes/inference-send-routes.ts +115 -0
  653. package/src/runtime/routes/integrations/twilio.ts +1 -0
  654. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  655. package/src/runtime/routes/memory-item-routes.test.ts +3 -9
  656. package/src/runtime/routes/memory-item-routes.ts +5 -6
  657. package/src/runtime/routes/memory-v2-routes.ts +105 -404
  658. package/src/runtime/routes/notification-routes.ts +2 -0
  659. package/src/runtime/routes/oauth-apps.ts +112 -7
  660. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  661. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  662. package/src/runtime/routes/oauth-providers.ts +298 -8
  663. package/src/runtime/routes/platform-routes.ts +336 -0
  664. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  665. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  666. package/src/runtime/routes/playground/state.ts +2 -1
  667. package/src/runtime/routes/publish-routes.ts +221 -0
  668. package/src/runtime/routes/schedule-routes.ts +82 -0
  669. package/src/runtime/routes/sequence-routes.ts +291 -0
  670. package/src/runtime/routes/settings-routes.ts +2 -10
  671. package/src/runtime/routes/skills-routes.ts +31 -1
  672. package/src/runtime/routes/stt-routes.ts +240 -3
  673. package/src/runtime/routes/surface-action-routes.ts +43 -7
  674. package/src/runtime/routes/tts-routes.ts +67 -0
  675. package/src/runtime/routes/types.ts +32 -0
  676. package/src/runtime/routes/user-routes-cli.ts +243 -0
  677. package/src/runtime/routes/webhook-routes.ts +165 -0
  678. package/src/runtime/sync/resource-sync-events.ts +25 -0
  679. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  680. package/src/runtime/sync/sync-publisher.ts +21 -0
  681. package/src/schedule/scheduler.ts +200 -123
  682. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  683. package/src/security/secret-patterns.ts +3 -0
  684. package/src/sequence/engine.ts +38 -40
  685. package/src/skills/include-graph.ts +35 -13
  686. package/src/subagent/manager.ts +20 -15
  687. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  688. package/src/tools/browser/browser-execution.ts +15 -4
  689. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  690. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  691. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  692. package/src/tools/browser/cdp-client/factory.ts +66 -5
  693. package/src/tools/browser/runtime-check.ts +77 -0
  694. package/src/tools/document/document-tool.ts +20 -0
  695. package/src/tools/executor.ts +18 -2
  696. package/src/tools/memory/register.test.ts +10 -8
  697. package/src/tools/memory/register.ts +9 -1
  698. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  699. package/src/tools/network/web-search.ts +280 -37
  700. package/src/tools/permission-checker.ts +28 -5
  701. package/src/tools/skills/load.ts +24 -20
  702. package/src/tools/subagent/spawn.ts +3 -3
  703. package/src/tools/terminal/shell.ts +44 -0
  704. package/src/tools/tool-name-aliases.ts +19 -0
  705. package/src/tools/types.ts +19 -1
  706. package/src/usage/attribution.ts +3 -2
  707. package/src/util/pricing.ts +86 -160
  708. package/src/watcher/__tests__/engine.test.ts +301 -0
  709. package/src/watcher/constants.ts +7 -0
  710. package/src/watcher/engine.ts +90 -90
  711. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  712. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  713. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  714. package/src/workspace/migrations/067-release-notes-safe-storage-limits.ts +4 -62
  715. package/src/workspace/migrations/069-seed-onboarding-threads.ts +34 -0
  716. package/src/workspace/migrations/070-memory-v2-summary-schema-rebuild.ts +31 -0
  717. package/src/workspace/migrations/071-remove-safe-storage-release-note.ts +111 -0
  718. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  719. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  720. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  721. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  722. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  723. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  724. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  725. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  726. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  727. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  728. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  729. package/src/workspace/migrations/registry.ts +28 -0
  730. package/src/workspace/migrations/runner.ts +13 -2
  731. package/src/workspace/migrations/types.ts +13 -3
  732. package/src/workspace/provider-commit-message-generator.ts +3 -2
  733. package/src/__tests__/context-search-pkb-source.test.ts +0 -492
  734. package/src/__tests__/credentials-cli.test.ts +0 -1225
  735. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  736. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  737. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  738. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  739. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  740. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  741. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  742. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  743. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  744. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  745. package/src/cli/commands/autonomy.ts +0 -365
  746. package/src/cli/commands/memory.ts +0 -424
  747. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -1201
  748. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  749. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  750. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  751. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  752. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  753. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  754. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  755. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  756. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  757. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  758. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  759. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  760. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  761. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  762. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  763. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  764. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  765. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  766. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  767. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  768. package/src/home/assistant-feed-authoring.ts +0 -135
  769. package/src/home/emit-feed-event.ts +0 -169
  770. package/src/home/feed-scheduler.ts +0 -281
  771. package/src/home/platform-gmail-digest.ts +0 -163
  772. package/src/home/rewrite-command-preview.ts +0 -66
  773. package/src/home/rewrite-feed-title.ts +0 -58
  774. package/src/home/rollup-producer.ts +0 -426
  775. package/src/memory/admin.ts +0 -326
  776. package/src/memory/context-search/sources/pkb.ts +0 -477
  777. package/src/memory/graph/compaction.ts +0 -299
  778. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -146,6 +146,42 @@ describe("loadConfig corrupt-file recovery", () => {
146
146
  /^config\.json\.corrupt-\d{4}-\d{2}-\d{2}T\d{2}-\d{2}-\d{2}\.\d{3}Z\.json$/,
147
147
  );
148
148
  });
149
+
150
+ // ---------------------------------------------------------------------------
151
+ // Shape-mismatch quarantine — same JSON.parse caveat as `loadRawConfig`.
152
+ // Without an `isPlainObject` check, downstream code (e.g. the managed-Gemini
153
+ // `setNestedValue` block in `loadConfig`) would TypeError on `null` or
154
+ // primitive `fileConfig`, and only the broad try/catch around the migration
155
+ // saved startup. Treating the wrong-shape case as a parse error here moves
156
+ // the boundary check to the loader so callers don't have to defend.
157
+ // ---------------------------------------------------------------------------
158
+
159
+ test.each([
160
+ ["null at the top level", "null"],
161
+ ["a JSON number", "42"],
162
+ ["a JSON string", '"hello"'],
163
+ ["a JSON boolean", "true"],
164
+ ["a JSON array", '["provider", "anthropic"]'],
165
+ ])(
166
+ "quarantines when config.json contains %s and returns defaults",
167
+ (_label, jsonText) => {
168
+ writeFileSync(CONFIG_PATH, jsonText);
169
+
170
+ // Must not throw — daemon startup contract.
171
+ const config = loadConfig();
172
+
173
+ // Defaults loaded — config is populated through the Zod schema.
174
+ expect(config).toBeDefined();
175
+ expect(config.memory).toBeDefined();
176
+
177
+ const quarantined = listQuarantinedFiles();
178
+ expect(quarantined).toHaveLength(1);
179
+ // Original wrong-shape content preserved for debugging.
180
+ expect(readFileSync(join(WORKSPACE_DIR, quarantined[0]), "utf-8")).toBe(
181
+ jsonText,
182
+ );
183
+ },
184
+ );
149
185
  });
150
186
 
151
187
  describe("loadRawConfig corrupt-file recovery", () => {
@@ -180,4 +216,36 @@ describe("loadRawConfig corrupt-file recovery", () => {
180
216
  expect(raw).toEqual({ foo: "bar", nested: { k: 1 } });
181
217
  expect(listQuarantinedFiles()).toHaveLength(0);
182
218
  });
219
+
220
+ // ---------------------------------------------------------------------------
221
+ // Shape-mismatch quarantine — JSON.parse can succeed on `null`, primitives,
222
+ // and arrays, all of which violate the function's `Record<string, unknown>`
223
+ // return-type contract. These cases must be quarantined the same way as a
224
+ // syntax error so callers (e.g. /v1/config handlers) can iterate the result
225
+ // safely without runtime shape checks.
226
+ // ---------------------------------------------------------------------------
227
+
228
+ test.each([
229
+ ["null at the top level", "null"],
230
+ ["a JSON number", "42"],
231
+ ["a JSON string", '"hello"'],
232
+ ["a JSON boolean", "true"],
233
+ ["a JSON array", '["provider", "anthropic"]'],
234
+ ])(
235
+ "quarantines when config.json contains %s and returns {}",
236
+ (_label, jsonText) => {
237
+ writeFileSync(CONFIG_PATH, jsonText);
238
+
239
+ // Must not throw — same contract as the syntax-error path.
240
+ const raw = loadRawConfig();
241
+
242
+ expect(raw).toEqual({});
243
+ const quarantined = listQuarantinedFiles();
244
+ expect(quarantined).toHaveLength(1);
245
+ // Original wrong-shape content is preserved for debugging.
246
+ expect(readFileSync(join(WORKSPACE_DIR, quarantined[0]), "utf-8")).toBe(
247
+ jsonText,
248
+ );
249
+ },
250
+ );
183
251
  });
@@ -58,6 +58,7 @@ afterAll(() => {
58
58
  });
59
59
 
60
60
  import { invalidateConfigCache, loadConfig } from "../config/loader.js";
61
+ import { applyContextDefaultsToRawConfig } from "../runtime/routes/conversation-query-routes.js";
61
62
  import { _setStorePath } from "../security/encrypted-store.js";
62
63
 
63
64
  // ---------------------------------------------------------------------------
@@ -91,7 +92,6 @@ function readConfig(): Record<string, unknown> {
91
92
  }
92
93
 
93
94
  const MANAGED_SERVICES = [
94
- "inference",
95
95
  "image-generation",
96
96
  "web-search",
97
97
  "google-oauth",
@@ -125,7 +125,7 @@ describe("platform-managed config defaults", () => {
125
125
  }
126
126
  });
127
127
 
128
- test("IS_PLATFORM=true, no config file → all 8 service modes written as 'managed'", () => {
128
+ test("IS_PLATFORM=true, no config file → all 7 managed service modes written as 'managed'", () => {
129
129
  process.env.IS_PLATFORM = "true";
130
130
 
131
131
  loadConfig();
@@ -139,7 +139,7 @@ describe("platform-managed config defaults", () => {
139
139
  }
140
140
  });
141
141
 
142
- test("IS_PLATFORM=false, no config file → service modes default to 'your-own'", () => {
142
+ test("IS_PLATFORM=false, no config file → managed service modes default to 'your-own'", () => {
143
143
  process.env.IS_PLATFORM = "false";
144
144
 
145
145
  loadConfig();
@@ -153,7 +153,7 @@ describe("platform-managed config defaults", () => {
153
153
  }
154
154
  });
155
155
 
156
- test("IS_PLATFORM unset, no config file → service modes default to 'your-own'", () => {
156
+ test("IS_PLATFORM unset, no config file → managed service modes default to 'your-own'", () => {
157
157
  delete process.env.IS_PLATFORM;
158
158
 
159
159
  loadConfig();
@@ -170,13 +170,13 @@ describe("platform-managed config defaults", () => {
170
170
  test("IS_PLATFORM=true, config file already exists → existing service mode values are preserved", () => {
171
171
  process.env.IS_PLATFORM = "true";
172
172
 
173
- // Write an existing config with inference mode explicitly set to "your-own"
173
+ // Write an existing config with image-generation mode explicitly set to "your-own"
174
174
  writeFileSync(
175
175
  CONFIG_PATH,
176
176
  JSON.stringify(
177
177
  {
178
178
  services: {
179
- inference: { mode: "your-own" },
179
+ "image-generation": { mode: "your-own" },
180
180
  },
181
181
  },
182
182
  null,
@@ -184,13 +184,350 @@ describe("platform-managed config defaults", () => {
184
184
  ) + "\n",
185
185
  );
186
186
 
187
- loadConfig();
187
+ const config = loadConfig();
188
188
 
189
189
  const written = readConfig() as { services?: Record<string, unknown> };
190
190
  expect(written.services).toBeDefined();
191
191
  // The existing value must be preserved — backfill path, not fresh-write path
192
192
  expect(
193
- (written.services!["inference"] as { mode?: string })?.mode,
193
+ (written.services!["image-generation"] as { mode?: string })?.mode,
194
194
  ).toBe("your-own");
195
+ // ...and the in-memory config must mirror the explicit user choice (the
196
+ // fill-defaults pass must not override an explicit "your-own").
197
+ expect(config.services["image-generation"].mode).toBe("your-own");
198
+ });
199
+
200
+ test("IS_PLATFORM=true, config file exists without a services key → in-memory config has all managed modes", () => {
201
+ // Regression guard for the platform-managed boot order: by the time
202
+ // `loadConfig()` runs, lifecycle steps such as `seedInferenceProfiles`
203
+ // have already written `config.json` (with `llm.profiles` etc.), so
204
+ // `configFileExisted` is true even on a brand-new platform-managed
205
+ // assistant. Deployment-context defaults must still be applied to the
206
+ // in-memory config for any leaf keys that are absent from disk.
207
+ process.env.IS_PLATFORM = "true";
208
+
209
+ writeFileSync(
210
+ CONFIG_PATH,
211
+ JSON.stringify(
212
+ {
213
+ llm: {
214
+ profiles: {
215
+ balanced: { provider: "anthropic", model: "claude-sonnet-4.5" },
216
+ },
217
+ activeProfile: "balanced",
218
+ },
219
+ },
220
+ null,
221
+ 2,
222
+ ) + "\n",
223
+ );
224
+
225
+ const config = loadConfig();
226
+
227
+ // In-memory config has the deployment-context defaults applied for the
228
+ // missing service-mode fields.
229
+ for (const svc of MANAGED_SERVICES) {
230
+ expect(
231
+ (
232
+ config.services as unknown as Record<
233
+ string,
234
+ { mode: string }
235
+ >
236
+ )[svc]!.mode,
237
+ ).toBe("managed");
238
+ }
239
+
240
+ // The on-disk file is NOT modified by the fill pass — disk reflects only
241
+ // what was already there. Existing-file branch never re-writes config.json.
242
+ const onDisk = readConfig() as Record<string, unknown>;
243
+ expect(onDisk["services"]).toBeUndefined();
244
+ });
245
+
246
+ test("IS_PLATFORM=true, config file exists with a partial service subtree → preserves user fields, fills missing mode", () => {
247
+ process.env.IS_PLATFORM = "true";
248
+
249
+ // User has an image-generation provider configured but never explicitly
250
+ // chose a mode for that service. The fill pass must apply
251
+ // `mode: "managed"` without clobbering the user-supplied provider.
252
+ // (The inference schema dropped per-service model/provider in
253
+ // migration 039 — image-generation still carries them, so it's the
254
+ // right schema to exercise the partial-subtree case.)
255
+ writeFileSync(
256
+ CONFIG_PATH,
257
+ JSON.stringify(
258
+ {
259
+ services: {
260
+ "image-generation": { provider: "openai" },
261
+ },
262
+ },
263
+ null,
264
+ 2,
265
+ ) + "\n",
266
+ );
267
+
268
+ const config = loadConfig();
269
+
270
+ const imageGen = (
271
+ config.services as unknown as Record<
272
+ string,
273
+ { mode: string; provider?: string }
274
+ >
275
+ )["image-generation"]!;
276
+ expect(imageGen.mode).toBe("managed");
277
+ expect(imageGen.provider).toBe("openai");
278
+ });
279
+
280
+ test("IS_PLATFORM=false, config file exists without services key → in-memory config keeps schema your-own defaults", () => {
281
+ // Sanity guard: deployment-context defaults are a no-op when IS_PLATFORM
282
+ // is not enabled, regardless of whether config.json existed.
283
+ process.env.IS_PLATFORM = "false";
284
+
285
+ writeFileSync(
286
+ CONFIG_PATH,
287
+ JSON.stringify(
288
+ {
289
+ llm: {
290
+ profiles: {
291
+ balanced: { provider: "anthropic", model: "claude-sonnet-4.5" },
292
+ },
293
+ activeProfile: "balanced",
294
+ },
295
+ },
296
+ null,
297
+ 2,
298
+ ) + "\n",
299
+ );
300
+
301
+ const config = loadConfig();
302
+
303
+ for (const svc of MANAGED_SERVICES) {
304
+ expect(
305
+ (
306
+ config.services as unknown as Record<
307
+ string,
308
+ { mode: string }
309
+ >
310
+ )[svc]!.mode,
311
+ ).toBe("your-own");
312
+ }
313
+ });
314
+ });
315
+
316
+ /**
317
+ * Regression guard for the `handleGetConfig` route handler in
318
+ * `assistant/src/runtime/routes/conversation-query-routes.ts`. That handler
319
+ * returns the raw on-disk JSON to clients (macOS, web, CLI) via
320
+ * `GET /v1/config`, but first layers deployment-context defaults on top
321
+ * via the `applyContextDefaultsToRawConfig` helper.
322
+ *
323
+ * macOS's `loadServiceModes(config:)` only updates `inferenceMode` when
324
+ * `services.inference.mode` is present in the response — without the fill
325
+ * pass, freshly-hatched platform-managed assistants would have no `services`
326
+ * key on disk (only `llm.profiles` from `seedInferenceProfiles`) and macOS
327
+ * would fall back to its `@Published` default of "your-own". The helper is
328
+ * also responsible for guarding against `loadRawConfig()` returning a
329
+ * non-object payload from a malformed-but-parseable `config.json`.
330
+ */
331
+ describe("GET /v1/config handler — context-default fill on raw response", () => {
332
+ const originalIsPlatform = process.env.IS_PLATFORM;
333
+
334
+ afterEach(() => {
335
+ if (originalIsPlatform === undefined) {
336
+ delete process.env.IS_PLATFORM;
337
+ } else {
338
+ process.env.IS_PLATFORM = originalIsPlatform;
339
+ }
340
+ });
341
+
342
+ test("IS_PLATFORM=true, raw config has no services key → response includes managed defaults", () => {
343
+ process.env.IS_PLATFORM = "true";
344
+
345
+ // Mirrors the real-world fresh-hatch state: lifecycle wrote
346
+ // `llm.profiles` to disk, but never persisted any service modes.
347
+ const raw: Record<string, unknown> = {
348
+ llm: {
349
+ profiles: {
350
+ balanced: { provider: "anthropic", model: "claude-sonnet-4.5" },
351
+ },
352
+ activeProfile: "balanced",
353
+ },
354
+ };
355
+
356
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
357
+ string,
358
+ unknown
359
+ >;
360
+ const services = result["services"] as Record<string, { mode: string }>;
361
+ expect(services).toBeDefined();
362
+ for (const svc of MANAGED_SERVICES) {
363
+ expect(services[svc]!.mode).toBe("managed");
364
+ }
365
+ });
366
+
367
+ test("IS_PLATFORM=true, raw config has explicit services.image-generation.mode='your-own' → preserved", () => {
368
+ process.env.IS_PLATFORM = "true";
369
+
370
+ // User has explicitly chosen "your-own" for image-generation via the macOS
371
+ // Save flow. The patch handler persisted that to disk; the fill pass must
372
+ // not override an explicit user choice.
373
+ const raw: Record<string, unknown> = {
374
+ services: {
375
+ "image-generation": { mode: "your-own" },
376
+ },
377
+ };
378
+
379
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
380
+ string,
381
+ unknown
382
+ >;
383
+ const services = result["services"] as Record<string, { mode: string }>;
384
+ expect(services["image-generation"]!.mode).toBe("your-own");
385
+ // web-search was missing → fill.
386
+ expect(services["web-search"]!.mode).toBe("managed");
387
+ // inference.mode is a legacy backwards-compat wire field — synthesized
388
+ // here for old macOS clients (SettingsStore.swift) that still read it.
389
+ expect(services["inference"]!.mode).toBe("managed");
390
+ });
391
+
392
+ test("IS_PLATFORM=false, raw config has no services key → response is unchanged", () => {
393
+ process.env.IS_PLATFORM = "false";
394
+
395
+ const raw: Record<string, unknown> = {
396
+ llm: {
397
+ profiles: {
398
+ balanced: { provider: "anthropic", model: "claude-sonnet-4.5" },
399
+ },
400
+ },
401
+ };
402
+
403
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
404
+ string,
405
+ unknown
406
+ >;
407
+ expect(result["services"]).toBeUndefined();
408
+ });
409
+
410
+ test("IS_PLATFORM=true, raw config has partial services subtree → preserves user fields, fills missing mode", () => {
411
+ process.env.IS_PLATFORM = "true";
412
+
413
+ // User set image-generation.provider but never chose a mode.
414
+ // The fill pass adds the missing mode without clobbering the user-supplied
415
+ // provider.
416
+ const raw: Record<string, unknown> = {
417
+ services: {
418
+ "image-generation": { provider: "openai" },
419
+ },
420
+ };
421
+
422
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
423
+ string,
424
+ unknown
425
+ >;
426
+ const services = result["services"] as Record<
427
+ string,
428
+ { mode: string; provider?: string }
429
+ >;
430
+ expect(services["image-generation"]!.mode).toBe("managed");
431
+ expect(services["image-generation"]!.provider).toBe("openai");
432
+ // services.inference.mode is synthesized as a legacy wire-only field for
433
+ // older macOS clients during the rollout window (Phase 1.2 schema removal
434
+ // landed before the macOS Providers UI ships).
435
+ expect(services["inference"]!.mode).toBe("managed");
436
+ });
437
+
438
+ test("IS_PLATFORM=true, raw config has no inference subtree → synthesizes legacy mode='managed'", () => {
439
+ process.env.IS_PLATFORM = "true";
440
+
441
+ const raw: Record<string, unknown> = {
442
+ llm: {
443
+ profiles: {
444
+ balanced: { provider: "anthropic", model: "claude-sonnet-4.5" },
445
+ },
446
+ },
447
+ };
448
+
449
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
450
+ string,
451
+ unknown
452
+ >;
453
+ const services = result["services"] as Record<string, { mode: string }>;
454
+ expect(services["inference"]!.mode).toBe("managed");
455
+ });
456
+
457
+ test("IS_PLATFORM=true, raw config has explicit services.inference.mode='your-own' → preserved (legacy override)", () => {
458
+ process.env.IS_PLATFORM = "true";
459
+
460
+ // Pre-migration upgrade: workspace config still carries the legacy
461
+ // mode value. The synthesis only fills when absent, so an explicit
462
+ // disk value wins until migration 076 strips it.
463
+ const raw: Record<string, unknown> = {
464
+ services: {
465
+ inference: { mode: "your-own" },
466
+ },
467
+ };
468
+
469
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
470
+ string,
471
+ unknown
472
+ >;
473
+ const services = result["services"] as Record<string, { mode: string }>;
474
+ expect(services["inference"]!.mode).toBe("your-own");
475
+ });
476
+
477
+ test("IS_PLATFORM=false, raw config has no inference subtree → no synthesis", () => {
478
+ process.env.IS_PLATFORM = "false";
479
+
480
+ const raw: Record<string, unknown> = {
481
+ llm: {},
482
+ };
483
+
484
+ const result = applyContextDefaultsToRawConfig(raw) as Record<
485
+ string,
486
+ unknown
487
+ >;
488
+ expect(result["services"]).toBeUndefined();
489
+ });
490
+
491
+ // -------------------------------------------------------------------------
492
+ // Malformed-but-parseable config.json — must not 500 the GET endpoint.
493
+ //
494
+ // `loadRawConfig()` is typed `Record<string, unknown>` but `JSON.parse`
495
+ // will happily return `null`, primitives, or arrays for a syntactically
496
+ // valid file like `null` / `42` / `[]`. The helper must return those
497
+ // payloads unchanged rather than throwing inside
498
+ // `fillContextDefaultsForMissingKeys`.
499
+ // -------------------------------------------------------------------------
500
+
501
+ test("IS_PLATFORM=true, raw config is null → returned unchanged (no throw)", () => {
502
+ process.env.IS_PLATFORM = "true";
503
+ expect(applyContextDefaultsToRawConfig(null)).toBe(null);
504
+ });
505
+
506
+ test("IS_PLATFORM=true, raw config is a primitive number → returned unchanged (no throw)", () => {
507
+ process.env.IS_PLATFORM = "true";
508
+ expect(applyContextDefaultsToRawConfig(42)).toBe(42);
509
+ });
510
+
511
+ test("IS_PLATFORM=true, raw config is an array → returned unchanged (no throw)", () => {
512
+ process.env.IS_PLATFORM = "true";
513
+ const raw: unknown[] = [{ foo: "bar" }];
514
+ const result = applyContextDefaultsToRawConfig(raw);
515
+ expect(result).toBe(raw);
516
+ // No `services` key was synthesized onto the array.
517
+ expect((result as { services?: unknown }).services).toBeUndefined();
518
+ });
519
+
520
+ test("IS_PLATFORM=true, raw config is a string → returned unchanged (no throw)", () => {
521
+ process.env.IS_PLATFORM = "true";
522
+ expect(applyContextDefaultsToRawConfig("not-an-object")).toBe(
523
+ "not-an-object",
524
+ );
525
+ });
526
+
527
+ test("IS_PLATFORM=false, raw config is null → returned unchanged (no throw)", () => {
528
+ // Sanity check: when there are no context defaults to apply, the helper
529
+ // also short-circuits cleanly on non-object payloads.
530
+ process.env.IS_PLATFORM = "false";
531
+ expect(applyContextDefaultsToRawConfig(null)).toBe(null);
195
532
  });
196
533
  });
@@ -3,7 +3,7 @@ import { join } from "node:path";
3
3
  import { describe, expect, mock, test } from "bun:test";
4
4
 
5
5
  // ---------------------------------------------------------------------------
6
- // Mocks declared before imports that depend on platform/logger
6
+ // Mocks - declared before imports that depend on platform/logger/ipc
7
7
  // ---------------------------------------------------------------------------
8
8
 
9
9
  const WORKSPACE_DIR = process.env.VELLUM_WORKSPACE_DIR!;
@@ -45,28 +45,38 @@ mock.module("../util/logger.js", () => ({
45
45
  getCliLogger: () => makeLoggerStub(),
46
46
  }));
47
47
 
48
- mock.module("../config/loader.js", () => ({
49
- getConfig: () => ({
50
- services: {
51
- inference: {
52
- mode: "your-own",
53
- provider: "anthropic",
54
- model: "claude-opus-4-6",
55
- },
56
- "image-generation": {
57
- mode: "your-own",
58
- provider: "gemini",
59
- model: "gemini-3.1-flash-image-preview",
60
- },
61
- "web-search": { mode: "your-own", provider: "inference-provider-native" },
62
- },
63
- }),
64
- loadConfig: () => ({}),
65
- loadRawConfig: () => ({}),
66
- saveRawConfig: () => {},
67
- invalidateConfigCache: () => {},
68
- getNestedValue: () => undefined,
69
- setNestedValue: () => {},
48
+ // ---------------------------------------------------------------------------
49
+ // Mocks - ipc/cli-client
50
+ //
51
+ // The `config` CLI is IPC-tagged, so all schema lookups go through the
52
+ // daemon. Mock cliIpcCall so we can drive the response in each test and
53
+ // assert on exit behavior without spinning up a daemon socket.
54
+ // ---------------------------------------------------------------------------
55
+
56
+ let mockIpcResult: {
57
+ ok: boolean;
58
+ result?: unknown;
59
+ error?: string;
60
+ statusCode?: number;
61
+ } = { ok: true, result: { schema: {} } };
62
+
63
+ mock.module("../ipc/cli-client.js", () => ({
64
+ cliIpcCall: async () => mockIpcResult,
65
+ exitFromIpcResult: (r: {
66
+ error?: string;
67
+ statusCode?: number;
68
+ }) => {
69
+ process.stderr.write((r.error ?? "Unknown error") + "\n");
70
+ if (r.statusCode === undefined) {
71
+ process.exit(10);
72
+ } else if (r.statusCode >= 500) {
73
+ process.exit(3);
74
+ } else if (r.statusCode >= 400) {
75
+ process.exit(2);
76
+ } else {
77
+ process.exit(1);
78
+ }
79
+ },
70
80
  }));
71
81
 
72
82
  import { Command } from "commander";
@@ -259,30 +269,54 @@ describe("z.toJSONSchema integration", () => {
259
269
 
260
270
  // ---------------------------------------------------------------------------
261
271
  // Tests: CLI schema command error path
272
+ //
273
+ // The CLI now routes `config schema <path>` through the daemon. When the
274
+ // daemon throws a BadRequestError for an unknown path, the IPC layer
275
+ // returns statusCode=400, and exitFromIpcResult maps that to process exit
276
+ // code 2 (per the matrix in cli-client.ts:exitFromIpcResult).
262
277
  // ---------------------------------------------------------------------------
263
278
 
264
279
  describe("CLI schema command", () => {
265
- test("nonexistent path prints error and exits with code 1", () => {
280
+ test("daemon error for nonexistent path surfaces via exitFromIpcResult", async () => {
281
+ // Drive the IPC mock to return a BadRequest as the daemon would
282
+ mockIpcResult = {
283
+ ok: false,
284
+ error: "No schema found at path: nonexistent",
285
+ statusCode: 400,
286
+ };
287
+
266
288
  const program = new Command();
267
- program.exitOverride(); // throw instead of calling process.exit
289
+ program.exitOverride();
268
290
  registerConfigCommand(program);
269
291
 
270
292
  const origExit = process.exit;
271
- // Replace process.exit to capture the exit code without killing the test
293
+ const origStderrWrite = process.stderr.write.bind(process.stderr);
272
294
  let exitCode: number | undefined;
273
295
  process.exit = ((code?: number) => {
274
296
  exitCode = code;
275
297
  throw new Error(`process.exit(${code})`);
276
298
  }) as never;
299
+ process.stderr.write = (() => true) as typeof process.stderr.write;
277
300
 
278
301
  try {
279
- program.parse(["node", "test", "config", "schema", "nonexistent"]);
302
+ await program.parseAsync([
303
+ "node",
304
+ "test",
305
+ "config",
306
+ "schema",
307
+ "nonexistent",
308
+ ]);
280
309
  } catch {
281
- // Expected: either Commander's exitOverride or our process.exit stub throws
310
+ // Expected: process.exit stub throws
282
311
  } finally {
283
312
  process.exit = origExit;
313
+ process.stderr.write = origStderrWrite;
284
314
  }
285
315
 
286
- expect(exitCode).toBe(1);
316
+ // 400 → exit 2 (per exitFromIpcResult matrix)
317
+ expect(exitCode).toBe(2);
318
+
319
+ // Restore default
320
+ mockIpcResult = { ok: true, result: { schema: {} } };
287
321
  });
288
322
  });
@@ -83,9 +83,9 @@ function writeConfig(obj: unknown): void {
83
83
  describe("AssistantConfigSchema", () => {
84
84
  test("parses empty object with full defaults", () => {
85
85
  const result = AssistantConfigSchema.parse({});
86
- // services.inference now carries only `mode`; provider/model live under
87
- // llm.default.{provider,model} (see PR 19 of unify-llm-callsites).
88
- expect(result.services.inference.mode).toBe("your-own");
86
+ // services.inference is now an empty object; provider/model live under
87
+ // llm.default.{provider,model}, auth routing via provider_connections.
88
+ expect(result.services.inference).toEqual({});
89
89
  expect(result.llm.default.provider).toBe("anthropic");
90
90
  expect(result.llm.default.model).toBe("claude-opus-4-7");
91
91
  expect(result.services["image-generation"].provider).toBe("gemini");
@@ -134,6 +134,17 @@ describe("AssistantConfigSchema", () => {
134
134
  expect(result.auditLog).toEqual({ retentionDays: 0 });
135
135
  });
136
136
 
137
+ test("accepts Tavily as a web search provider", () => {
138
+ const result = AssistantConfigSchema.parse({
139
+ services: {
140
+ "web-search": { mode: "your-own", provider: "tavily" },
141
+ },
142
+ });
143
+
144
+ expect(result.services["web-search"].provider).toBe("tavily");
145
+ expect(result.services["web-search"].mode).toBe("your-own");
146
+ });
147
+
137
148
  test("accepts valid complete config", () => {
138
149
  const input = {
139
150
  llm: {