@vellumai/assistant 0.6.4 → 0.6.5

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 (717) hide show
  1. package/.prettierignore +5 -0
  2. package/ARCHITECTURE.md +32 -36
  3. package/Dockerfile +12 -0
  4. package/README.md +3 -4
  5. package/bun.lock +8 -3
  6. package/docs/architecture/integrations.md +1 -20
  7. package/docs/architecture/security.md +16 -16
  8. package/docs/error-handling.md +111 -0
  9. package/docs/skills.md +10 -10
  10. package/docs/stt-provider-onboarding.md +2 -1
  11. package/knip.json +9 -2
  12. package/node_modules/@vellumai/ces-contracts/package.json +2 -1
  13. package/node_modules/@vellumai/ces-contracts/src/__tests__/trust-rules.test.ts +471 -0
  14. package/node_modules/@vellumai/ces-contracts/src/trust-rules.ts +398 -4
  15. package/node_modules/@vellumai/credential-storage/bun.lock +2 -2
  16. package/node_modules/@vellumai/credential-storage/package.json +2 -2
  17. package/node_modules/@vellumai/credential-storage/src/oauth-runtime.ts +20 -2
  18. package/node_modules/@vellumai/egress-proxy/bun.lock +2 -2
  19. package/node_modules/@vellumai/egress-proxy/package.json +2 -2
  20. package/openapi.yaml +123 -11
  21. package/package.json +6 -3
  22. package/scripts/generate-openapi.ts +50 -11
  23. package/src/__tests__/agent-loop-callsite-precedence.test.ts +318 -0
  24. package/src/__tests__/agent-loop-sentry-hygiene.test.ts +137 -0
  25. package/src/__tests__/agent-loop.test.ts +112 -1
  26. package/src/__tests__/anthropic-error-formatting.test.ts +98 -0
  27. package/src/__tests__/anthropic-provider.test.ts +171 -2
  28. package/src/__tests__/approval-cascade.test.ts +31 -10
  29. package/src/__tests__/approval-routes-http.test.ts +134 -10
  30. package/src/__tests__/assistant-attachments.test.ts +44 -0
  31. package/src/__tests__/assistant-feature-flags-integration.test.ts +29 -0
  32. package/src/__tests__/browser-fill-credential.test.ts +1 -1
  33. package/src/__tests__/browser-identifier-parity-guard.test.ts +53 -0
  34. package/src/__tests__/browser-skill-baseline-tool-payload.test.ts +23 -33
  35. package/src/__tests__/browser-skill-endstate.test.ts +51 -182
  36. package/src/__tests__/btw-routes.test.ts +47 -1
  37. package/src/__tests__/call-controller.test.ts +1 -2
  38. package/src/__tests__/call-site-routing-provider.test.ts +214 -0
  39. package/src/__tests__/catalog-cache.test.ts +27 -4
  40. package/src/__tests__/channel-approval-routes.test.ts +4 -4
  41. package/src/__tests__/channel-reply-delivery.test.ts +300 -2
  42. package/src/__tests__/checker.test.ts +428 -501
  43. package/src/__tests__/cli-command-risk-guard.test.ts +30 -33
  44. package/src/__tests__/compaction-circuit-breaker.test.ts +336 -0
  45. package/src/__tests__/compaction.benchmark.test.ts +1 -1
  46. package/src/__tests__/config-analysis.test.ts +11 -28
  47. package/src/__tests__/config-loader-backfill.test.ts +174 -0
  48. package/src/__tests__/config-loader-corrupt.test.ts +183 -0
  49. package/src/__tests__/config-loader-quarantine-bulletin.test.ts +202 -0
  50. package/src/__tests__/config-schema-cmd.test.ts +11 -5
  51. package/src/__tests__/config-schema.test.ts +427 -114
  52. package/src/__tests__/config-watcher.test.ts +2 -2
  53. package/src/__tests__/contact-store-user-file.test.ts +72 -73
  54. package/src/__tests__/contacts-write.test.ts +4 -4
  55. package/src/__tests__/context-token-estimator.test.ts +191 -1
  56. package/src/__tests__/context-window-manager.test.ts +530 -2
  57. package/src/__tests__/conversation-abort-tool-results.test.ts +30 -16
  58. package/src/__tests__/conversation-agent-loop-overflow.test.ts +61 -17
  59. package/src/__tests__/conversation-agent-loop.test.ts +412 -82
  60. package/src/__tests__/conversation-attachments.test.ts +1 -1
  61. package/src/__tests__/conversation-confirmation-signals.test.ts +30 -9
  62. package/src/__tests__/conversation-error.test.ts +37 -6
  63. package/src/__tests__/conversation-history-web-search.test.ts +6 -0
  64. package/src/__tests__/conversation-init.benchmark.test.ts +36 -0
  65. package/src/__tests__/conversation-lifecycle.test.ts +336 -0
  66. package/src/__tests__/conversation-load-history-repair.test.ts +27 -10
  67. package/src/__tests__/conversation-pre-run-repair.test.ts +30 -16
  68. package/src/__tests__/conversation-process-callsite.test.ts +306 -0
  69. package/src/__tests__/conversation-provider-retry-repair.test.ts +30 -16
  70. package/src/__tests__/conversation-queue.test.ts +41 -26
  71. package/src/__tests__/conversation-routes-disk-view.test.ts +29 -1
  72. package/src/__tests__/conversation-routes-slash-commands.test.ts +31 -3
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +2735 -55
  74. package/src/__tests__/conversation-runtime-workspace.test.ts +12 -12
  75. package/src/__tests__/conversation-skill-tools.test.ts +12 -146
  76. package/src/__tests__/conversation-slash-queue.test.ts +34 -19
  77. package/src/__tests__/conversation-slash-unknown.test.ts +30 -16
  78. package/src/__tests__/conversation-speed-override.test.ts +30 -11
  79. package/src/__tests__/conversation-surfaces-standalone-payloads.test.ts +1035 -0
  80. package/src/__tests__/conversation-surfaces-standalone.test.ts +630 -0
  81. package/src/__tests__/conversation-title-service.test.ts +2 -2
  82. package/src/__tests__/conversation-tool-setup-batch-authorized.test.ts +1 -1
  83. package/src/__tests__/conversation-unread-route.test.ts +2 -2
  84. package/src/__tests__/conversation-usage.test.ts +3 -1
  85. package/src/__tests__/conversation-workspace-cache-state.test.ts +31 -10
  86. package/src/__tests__/conversation-workspace-injection.test.ts +43 -15
  87. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +44 -16
  88. package/src/__tests__/credential-broker-browser-fill.test.ts +110 -0
  89. package/src/__tests__/credential-security-invariants.test.ts +3 -0
  90. package/src/__tests__/credential-storage-oauth-compat.test.ts +18 -0
  91. package/src/__tests__/credential-storage-static-compat.test.ts +28 -0
  92. package/src/__tests__/credential-vault-unit.test.ts +135 -19
  93. package/src/__tests__/credentials-cli.test.ts +1 -9
  94. package/src/__tests__/cross-provider-web-search.test.ts +84 -0
  95. package/src/__tests__/daemon-server-persist-and-process-callsite.test.ts +92 -0
  96. package/src/__tests__/delete-propagation.test.ts +437 -0
  97. package/src/__tests__/dm-backfill.test.ts +417 -0
  98. package/src/__tests__/dm-persistence.test.ts +227 -0
  99. package/src/__tests__/edit-propagation.test.ts +280 -0
  100. package/src/__tests__/ephemeral-permissions.test.ts +93 -3
  101. package/src/__tests__/estimator-calibration-integration.test.ts +208 -0
  102. package/src/__tests__/estimator-calibration.test.ts +213 -0
  103. package/src/__tests__/extension-id-sync-guard.test.ts +26 -7
  104. package/src/__tests__/file-write-tool.test.ts +151 -1
  105. package/src/__tests__/filing-service.test.ts +255 -0
  106. package/src/__tests__/gemini-provider.test.ts +0 -3
  107. package/src/__tests__/guardian-grant-minting.test.ts +8 -0
  108. package/src/__tests__/headless-browser-interactions.test.ts +1 -1
  109. package/src/__tests__/heartbeat-service.test.ts +96 -15
  110. package/src/__tests__/host-shell-tool.test.ts +124 -18
  111. package/src/__tests__/http-user-message-parity.test.ts +29 -1
  112. package/src/__tests__/inbound-slack-persistence.test.ts +340 -0
  113. package/src/__tests__/intent-routing.test.ts +1 -40
  114. package/src/__tests__/llm-catalog-parity.test.ts +174 -0
  115. package/src/__tests__/llm-context-normalization.test.ts +121 -0
  116. package/src/__tests__/llm-resolver.test.ts +214 -0
  117. package/src/__tests__/llm-schema.test.ts +223 -0
  118. package/src/__tests__/managed-proxy-context.test.ts +6 -2
  119. package/src/__tests__/messaging-skill-split.test.ts +3 -34
  120. package/src/__tests__/migration-import-from-url.test.ts +684 -0
  121. package/src/__tests__/model-intents.test.ts +9 -83
  122. package/src/__tests__/notification-decision-fallback.test.ts +0 -10
  123. package/src/__tests__/notification-decision-identity.test.ts +0 -9
  124. package/src/__tests__/notification-decision-recipient-context.test.ts +0 -9
  125. package/src/__tests__/oauth-store.test.ts +10 -7
  126. package/src/__tests__/oauth2-gateway-transport.test.ts +8 -3
  127. package/src/__tests__/oauth2-refresh-retry.test.ts +279 -0
  128. package/src/__tests__/openai-provider.test.ts +7 -0
  129. package/src/__tests__/openai-responses-provider.test.ts +396 -0
  130. package/src/__tests__/openrouter-provider-only.test.ts +135 -0
  131. package/src/__tests__/outbound-slack-persistence.test.ts +293 -0
  132. package/src/__tests__/permission-checker-host-gate.test.ts +1 -1
  133. package/src/__tests__/permission-mode.test.ts +16 -0
  134. package/src/__tests__/permission-types.test.ts +0 -1
  135. package/src/__tests__/persona-resolver.test.ts +13 -13
  136. package/src/__tests__/pkb-autoinject.test.ts +37 -1
  137. package/src/__tests__/platform-bash-auto-approve.test.ts +1 -1
  138. package/src/__tests__/pricing.test.ts +50 -3
  139. package/src/__tests__/profiler-routes.test.ts +1 -1
  140. package/src/__tests__/provider-commit-message-generator.test.ts +14 -84
  141. package/src/__tests__/provider-env-vars-scope.test.ts +52 -0
  142. package/src/__tests__/provider-error-scenarios.test.ts +135 -6
  143. package/src/__tests__/provider-managed-proxy-integration.test.ts +42 -11
  144. package/src/__tests__/provider-registry-ollama.test.ts +1 -2
  145. package/src/__tests__/proxy-approval-callback.test.ts +0 -1
  146. package/src/__tests__/reaction-persistence.test.ts +560 -0
  147. package/src/__tests__/relay-server.test.ts +1 -1
  148. package/src/__tests__/require-fresh-approval.test.ts +1 -1
  149. package/src/__tests__/retry-openrouter-only-normalization.test.ts +136 -0
  150. package/src/__tests__/retry-thinking-tool-choice.test.ts +226 -0
  151. package/src/__tests__/risk-classifier-parity.test.ts +230 -0
  152. package/src/__tests__/sanitize-config-for-transfer.test.ts +78 -1
  153. package/src/__tests__/secret-ingress-http.test.ts +28 -0
  154. package/src/__tests__/secret-prompter-channel-fallback.test.ts +125 -0
  155. package/src/__tests__/secret-routes-managed-proxy.test.ts +2 -3
  156. package/src/__tests__/secret-scanner-executor.test.ts +1 -1
  157. package/src/__tests__/send-endpoint-busy.test.ts +29 -1
  158. package/src/__tests__/server-history-render.test.ts +31 -0
  159. package/src/__tests__/shell-parser-property.test.ts +13 -13
  160. package/src/__tests__/skill-cache-store.test.ts +182 -0
  161. package/src/__tests__/skills.test.ts +19 -33
  162. package/src/__tests__/slack-app-setup-skill-regression.test.ts +3 -1
  163. package/src/__tests__/slack-skill.test.ts +3 -8
  164. package/src/__tests__/starter-bundle.test.ts +35 -0
  165. package/src/__tests__/subagent-call-site-routing.test.ts +280 -0
  166. package/src/__tests__/suggestion-routes.test.ts +160 -3
  167. package/src/__tests__/system-prompt.test.ts +22 -35
  168. package/src/__tests__/task-runner.test.ts +3 -1
  169. package/src/__tests__/tcc-sandbox-deny.test.ts +198 -0
  170. package/src/__tests__/terminal-tools.test.ts +8 -0
  171. package/src/__tests__/test-support/browser-skill-harness.ts +2 -52
  172. package/src/__tests__/thread-backfill.test.ts +941 -0
  173. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +2 -2
  174. package/src/__tests__/tool-executor-lifecycle-events.test.ts +2 -2
  175. package/src/__tests__/tool-executor.test.ts +60 -94
  176. package/src/__tests__/trust-store.test.ts +442 -109
  177. package/src/__tests__/update-bulletin-job.test.ts +389 -0
  178. package/src/__tests__/usage-cache-backfill-migration.test.ts +3 -1
  179. package/src/__tests__/verification-control-plane-policy.test.ts +1 -22
  180. package/src/__tests__/voice-session-bridge.test.ts +39 -0
  181. package/src/__tests__/volume-security-guard.test.ts +3 -2
  182. package/src/__tests__/web-search-history.test.ts +337 -0
  183. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +343 -0
  184. package/src/__tests__/workspace-migration-043-release-notes-latex-rendering.test.ts +202 -0
  185. package/src/__tests__/workspace-migration-045-release-notes-meet-avatar.test.ts +210 -0
  186. package/src/__tests__/workspace-migration-drop-user-md.test.ts +11 -11
  187. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +841 -0
  188. package/src/__tests__/workspace-policy.test.ts +1 -13
  189. package/src/acp/client-handler.ts +1 -2
  190. package/src/agent/loop.ts +209 -17
  191. package/src/avatar/resvg-lazy.test.ts +136 -0
  192. package/src/avatar/resvg-lazy.ts +82 -9
  193. package/src/avatar/traits-png-sync.ts +21 -1
  194. package/src/browser/__tests__/operations.test.ts +163 -0
  195. package/src/browser/identifiers.ts +51 -0
  196. package/src/browser/operations.ts +660 -0
  197. package/src/browser/types.ts +81 -0
  198. package/src/calls/guardian-question-copy.ts +2 -2
  199. package/src/calls/telephony-stt-routing.ts +1 -1
  200. package/src/calls/voice-session-bridge.ts +1 -0
  201. package/src/cli/AGENTS.md +1 -1
  202. package/src/cli/commands/__tests__/attachment.test.ts +438 -0
  203. package/src/cli/commands/__tests__/browser.test.ts +554 -0
  204. package/src/cli/commands/__tests__/cache.test.ts +623 -0
  205. package/src/cli/commands/__tests__/email-list.test.ts +6 -0
  206. package/src/cli/commands/__tests__/email-send.test.ts +93 -1
  207. package/src/cli/commands/__tests__/image-generation.test.ts +666 -0
  208. package/src/cli/commands/__tests__/inference-send.test.ts +451 -0
  209. package/src/cli/commands/__tests__/stt-transcribe.test.ts +454 -0
  210. package/src/cli/commands/__tests__/task.test.ts +913 -0
  211. package/src/cli/commands/__tests__/tts-synthesize.test.ts +594 -0
  212. package/src/cli/commands/__tests__/ui-confirm.test.ts +650 -0
  213. package/src/cli/commands/__tests__/ui.test.ts +1215 -0
  214. package/src/cli/commands/__tests__/watchers.test.ts +716 -0
  215. package/src/cli/commands/attachment.ts +182 -0
  216. package/src/cli/commands/browser.ts +350 -0
  217. package/src/cli/commands/cache.ts +341 -0
  218. package/src/cli/commands/completions.ts +0 -3
  219. package/src/cli/commands/config.ts +6 -6
  220. package/src/cli/commands/conversations-import.ts +347 -0
  221. package/src/cli/commands/conversations.ts +14 -1
  222. package/src/cli/commands/email.ts +234 -194
  223. package/src/cli/commands/image-generation.ts +300 -0
  224. package/src/cli/commands/inference.ts +200 -0
  225. package/src/cli/commands/memory.ts +127 -17
  226. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +0 -1
  227. package/src/cli/commands/platform/__tests__/connect.test.ts +0 -1
  228. package/src/cli/commands/platform/__tests__/disconnect.test.ts +0 -1
  229. package/src/cli/commands/platform/__tests__/status.test.ts +0 -1
  230. package/src/cli/commands/stt.ts +339 -0
  231. package/src/cli/commands/task.ts +795 -0
  232. package/src/cli/commands/trust.ts +50 -19
  233. package/src/cli/commands/tts.ts +273 -0
  234. package/src/cli/commands/ui.ts +670 -0
  235. package/src/cli/commands/watchers.ts +509 -0
  236. package/src/cli/lib/daemon-credential-client.ts +0 -19
  237. package/src/cli/program.ts +23 -4
  238. package/src/cli.ts +0 -37
  239. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +23 -1
  240. package/src/config/bundled-skills/media-processing/services/reduce.ts +1 -1
  241. package/src/config/bundled-skills/messaging/SKILL.md +2 -2
  242. package/src/config/bundled-skills/messaging/TOOLS.json +4 -0
  243. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +8 -1
  244. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +15 -1
  245. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +21 -1
  246. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +11 -12
  247. package/src/config/bundled-skills/phone-calls/references/CONFIG.md +9 -8
  248. package/src/config/bundled-skills/settings/TOOLS.json +3 -3
  249. package/src/config/bundled-tool-registry.ts +0 -175
  250. package/src/config/env.ts +7 -2
  251. package/src/config/feature-flag-registry.json +25 -9
  252. package/src/config/llm-resolver.ts +128 -0
  253. package/src/config/loader.ts +194 -10
  254. package/src/config/raw-config-utils.ts +30 -2
  255. package/src/config/sanitize-for-transfer.ts +35 -0
  256. package/src/config/schema.ts +30 -41
  257. package/src/config/schemas/analysis.ts +3 -22
  258. package/src/config/schemas/calls.ts +0 -4
  259. package/src/config/schemas/filing.ts +2 -7
  260. package/src/config/schemas/heartbeat.ts +0 -5
  261. package/src/config/schemas/inference.ts +3 -23
  262. package/src/config/schemas/llm.ts +318 -0
  263. package/src/config/schemas/memory-processing.ts +1 -9
  264. package/src/config/schemas/notifications.ts +4 -11
  265. package/src/config/schemas/platform.ts +3 -9
  266. package/src/config/schemas/security.ts +33 -0
  267. package/src/config/schemas/services.ts +9 -4
  268. package/src/config/schemas/stt.ts +1 -0
  269. package/src/config/schemas/tts.ts +53 -0
  270. package/src/config/schemas/updates.ts +1 -1
  271. package/src/config/schemas/workspace-git.ts +3 -40
  272. package/src/config/skills.ts +2 -2
  273. package/src/context/__tests__/compact-prompt.test.ts +45 -0
  274. package/src/context/__tests__/microcompact.test.ts +805 -0
  275. package/src/context/estimator-calibration.ts +136 -0
  276. package/src/context/microcompact.ts +443 -0
  277. package/src/context/prompts/compact.md +12 -0
  278. package/src/context/token-estimator.ts +61 -3
  279. package/src/context/window-manager.ts +229 -25
  280. package/src/credential-execution/approval-bridge.ts +0 -1
  281. package/src/credential-execution/executable-discovery.ts +19 -8
  282. package/src/credential-execution/process-manager.test.ts +109 -0
  283. package/src/credential-execution/process-manager.ts +65 -2
  284. package/src/daemon/approval-generators.ts +29 -4
  285. package/src/daemon/assistant-attachments.ts +24 -13
  286. package/src/daemon/classifier.ts +2 -2
  287. package/src/daemon/config-watcher.ts +0 -1
  288. package/src/daemon/context-overflow-reducer.ts +4 -1
  289. package/src/daemon/conversation-agent-loop-handlers.ts +79 -12
  290. package/src/daemon/conversation-agent-loop.ts +462 -80
  291. package/src/daemon/conversation-attachments.ts +2 -6
  292. package/src/daemon/conversation-error.ts +36 -1
  293. package/src/daemon/conversation-lifecycle.ts +30 -6
  294. package/src/daemon/conversation-messaging.ts +73 -4
  295. package/src/daemon/conversation-process.ts +10 -4
  296. package/src/daemon/conversation-queue-manager.ts +3 -0
  297. package/src/daemon/conversation-runtime-assembly.ts +760 -29
  298. package/src/daemon/conversation-slash.ts +2 -2
  299. package/src/daemon/conversation-surfaces.ts +389 -1
  300. package/src/daemon/conversation-tool-setup.ts +10 -5
  301. package/src/daemon/conversation-usage.ts +1 -1
  302. package/src/daemon/conversation.ts +118 -30
  303. package/src/daemon/external-skills-bootstrap.ts +41 -0
  304. package/src/daemon/guardian-action-generators.ts +34 -14
  305. package/src/daemon/handlers/config-model.test.ts +86 -0
  306. package/src/daemon/handlers/config-model.ts +54 -12
  307. package/src/daemon/handlers/conversations.ts +9 -2
  308. package/src/daemon/handlers/shared.ts +39 -11
  309. package/src/daemon/handlers/skills.ts +2 -2
  310. package/src/daemon/handlers/slack-channel-oauth-install.ts +197 -0
  311. package/src/daemon/lifecycle.ts +76 -14
  312. package/src/daemon/message-types/conversations.ts +14 -0
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/trust.ts +0 -2
  315. package/src/daemon/parse-actual-tokens-from-error.test.ts +57 -1
  316. package/src/daemon/parse-actual-tokens-from-error.ts +66 -0
  317. package/src/daemon/pkb-context-tracker.test.ts +169 -0
  318. package/src/daemon/pkb-context-tracker.ts +125 -0
  319. package/src/daemon/pkb-reminder-builder.test.ts +70 -0
  320. package/src/daemon/pkb-reminder-builder.ts +31 -0
  321. package/src/daemon/providers-setup.ts +6 -0
  322. package/src/daemon/server.ts +117 -9
  323. package/src/daemon/tool-side-effects.ts +0 -9
  324. package/src/daemon/watch-handler.ts +4 -4
  325. package/src/daemon/web-search-history.ts +126 -0
  326. package/src/events/domain-events.ts +0 -1
  327. package/src/filing/filing-service.ts +9 -10
  328. package/src/heartbeat/heartbeat-service.ts +76 -28
  329. package/src/home/__tests__/feed-scheduler.test.ts +39 -11
  330. package/src/home/__tests__/rollup-producer.test.ts +44 -0
  331. package/src/home/assistant-feed-authoring.ts +4 -0
  332. package/src/home/emit-feed-event.ts +4 -0
  333. package/src/home/feed-scheduler.ts +20 -4
  334. package/src/home/feed-types.ts +56 -2
  335. package/src/home/relationship-state-writer.ts +2 -2
  336. package/src/home/rollup-producer.ts +34 -5
  337. package/src/home/suggested-prompts.ts +101 -0
  338. package/src/ipc/__tests__/attachment-ipc.test.ts +213 -0
  339. package/src/ipc/__tests__/browser-ipc.test.ts +339 -0
  340. package/src/ipc/__tests__/cache-ipc.test.ts +266 -0
  341. package/src/ipc/__tests__/socket-path.test.ts +73 -0
  342. package/src/ipc/__tests__/task-ipc.test.ts +577 -0
  343. package/src/ipc/__tests__/ui-request-route.test.ts +495 -0
  344. package/src/ipc/__tests__/watcher-ipc.test.ts +295 -0
  345. package/src/ipc/cli-client.ts +2 -1
  346. package/src/ipc/cli-server.ts +26 -8
  347. package/src/ipc/gateway-client.ts +4 -4
  348. package/src/ipc/routes/attachment.ts +114 -0
  349. package/src/ipc/routes/browser-context.ts +61 -0
  350. package/src/ipc/routes/browser.ts +96 -0
  351. package/src/ipc/routes/cache.ts +96 -0
  352. package/src/ipc/routes/index.ts +17 -1
  353. package/src/ipc/routes/task-queue.ts +226 -0
  354. package/src/ipc/routes/task.ts +173 -0
  355. package/src/ipc/routes/ui-request.ts +50 -0
  356. package/src/ipc/routes/watcher.ts +203 -0
  357. package/src/ipc/socket-path.ts +100 -0
  358. package/src/memory/__tests__/conversation-analyze-job.test.ts +9 -8
  359. package/src/memory/__tests__/conversation-group-migration.test.ts +99 -0
  360. package/src/memory/admin.ts +18 -0
  361. package/src/memory/conversation-analyze-job.ts +14 -13
  362. package/src/memory/conversation-attention-store.ts +13 -6
  363. package/src/memory/conversation-crud.ts +103 -3
  364. package/src/memory/conversation-group-migration.ts +38 -6
  365. package/src/memory/conversation-title-service.ts +7 -4
  366. package/src/memory/db-init.ts +2 -0
  367. package/src/memory/embedding-backend.ts +1 -1
  368. package/src/memory/graph/compaction.ts +299 -0
  369. package/src/memory/graph/consolidation.ts +4 -4
  370. package/src/memory/graph/conversation-graph-memory.ts +89 -29
  371. package/src/memory/graph/extraction.test.ts +272 -2
  372. package/src/memory/graph/extraction.ts +173 -51
  373. package/src/memory/graph/graph-search.test.ts +92 -0
  374. package/src/memory/graph/graph-search.ts +4 -1
  375. package/src/memory/graph/narrative.ts +2 -2
  376. package/src/memory/graph/pattern-scan.ts +2 -2
  377. package/src/memory/graph/retriever.test.ts +459 -0
  378. package/src/memory/graph/retriever.ts +230 -48
  379. package/src/memory/graph/store.ts +41 -0
  380. package/src/memory/graph/tool-handlers.ts +27 -0
  381. package/src/memory/graph/tools.ts +6 -1
  382. package/src/memory/indexer.ts +5 -5
  383. package/src/memory/job-handlers/conversation-starters.ts +23 -20
  384. package/src/memory/job-handlers/summarization.ts +2 -2
  385. package/src/memory/job-utils.ts +7 -1
  386. package/src/memory/jobs/embed-pkb-file.test.ts +168 -0
  387. package/src/memory/jobs/embed-pkb-file.ts +54 -0
  388. package/src/memory/jobs-store.ts +44 -3
  389. package/src/memory/jobs-worker.ts +4 -0
  390. package/src/memory/migrations/140-backfill-usage-cache-accounting.ts +1 -1
  391. package/src/memory/migrations/220-normalize-user-file-by-principal.ts +2 -2
  392. package/src/memory/migrations/222-strip-placeholder-sentinels-from-messages.ts +82 -0
  393. package/src/memory/migrations/index.ts +1 -0
  394. package/src/memory/pkb/pkb-index.test.ts +368 -0
  395. package/src/memory/pkb/pkb-index.ts +255 -0
  396. package/src/memory/pkb/pkb-reconcile.test.ts +251 -0
  397. package/src/memory/pkb/pkb-reconcile.ts +148 -0
  398. package/src/memory/pkb/pkb-search.test.ts +438 -0
  399. package/src/memory/pkb/pkb-search.ts +137 -0
  400. package/src/memory/pkb/types.ts +53 -0
  401. package/src/memory/qdrant-client.ts +122 -1
  402. package/src/memory/slack-thread-store.ts +37 -0
  403. package/src/messaging/providers/gmail/adapter.ts +6 -16
  404. package/src/messaging/providers/gmail/client.ts +22 -0
  405. package/src/messaging/providers/gmail/types.ts +7 -0
  406. package/src/messaging/providers/slack/adapter.ts +14 -2
  407. package/src/messaging/providers/slack/backfill.test.ts +257 -0
  408. package/src/messaging/providers/slack/backfill.ts +101 -0
  409. package/src/messaging/providers/slack/message-metadata.test.ts +316 -0
  410. package/src/messaging/providers/slack/message-metadata.ts +123 -0
  411. package/src/messaging/providers/slack/render-transcript.test.ts +1373 -0
  412. package/src/messaging/providers/slack/render-transcript.ts +443 -0
  413. package/src/messaging/style-analyzer.ts +5 -2
  414. package/src/notifications/README.md +9 -5
  415. package/src/notifications/decision-engine.ts +3 -9
  416. package/src/notifications/preference-extractor.ts +2 -6
  417. package/src/oauth/oauth-store.ts +1 -0
  418. package/src/oauth/platform-connection.test.ts +47 -0
  419. package/src/oauth/platform-connection.ts +15 -5
  420. package/src/oauth/seed-providers.ts +4 -2
  421. package/src/permissions/approval-policy.test.ts +948 -0
  422. package/src/permissions/approval-policy.ts +257 -0
  423. package/src/permissions/bash-risk-classifier.test.ts +1208 -0
  424. package/src/permissions/bash-risk-classifier.ts +707 -0
  425. package/src/permissions/checker.ts +217 -708
  426. package/src/permissions/command-registry.test.ts +535 -0
  427. package/src/permissions/command-registry.ts +825 -0
  428. package/src/permissions/defaults.ts +26 -78
  429. package/src/permissions/file-risk-classifier.test.ts +535 -0
  430. package/src/permissions/file-risk-classifier.ts +274 -0
  431. package/src/permissions/risk-types.ts +205 -0
  432. package/src/permissions/secret-prompter.ts +53 -2
  433. package/src/permissions/skill-risk-classifier.test.ts +311 -0
  434. package/src/permissions/skill-risk-classifier.ts +214 -0
  435. package/src/permissions/trust-client.ts +52 -25
  436. package/src/permissions/trust-store-interface.ts +1 -6
  437. package/src/permissions/trust-store.ts +161 -62
  438. package/src/permissions/types.ts +23 -14
  439. package/src/permissions/web-risk-classifier.test.ts +170 -0
  440. package/src/permissions/web-risk-classifier.ts +89 -0
  441. package/src/permissions/workspace-policy.ts +1 -16
  442. package/src/platform/client.ts +19 -1
  443. package/src/prompts/persona-resolver.ts +3 -3
  444. package/src/prompts/system-prompt.ts +19 -20
  445. package/src/prompts/templates/SOUL.md +2 -2
  446. package/src/prompts/update-bulletin-job.ts +190 -0
  447. package/src/providers/__tests__/context-overflow-error.test.ts +328 -0
  448. package/src/providers/__tests__/provider-env-vars.test.ts +102 -0
  449. package/src/providers/__tests__/retry-callsite.test.ts +424 -0
  450. package/src/providers/anthropic/client.ts +183 -14
  451. package/src/providers/call-site-routing.ts +71 -0
  452. package/src/providers/gemini/client.ts +65 -2
  453. package/src/providers/managed-proxy/constants.ts +2 -1
  454. package/src/providers/model-catalog.ts +501 -33
  455. package/src/providers/model-intents.ts +4 -4
  456. package/src/providers/openai/chat-completions-provider.ts +57 -1
  457. package/src/providers/openai/responses-provider.ts +86 -9
  458. package/src/providers/openrouter/client.ts +76 -9
  459. package/src/providers/provider-env-vars.ts +56 -0
  460. package/src/providers/provider-send-message.ts +22 -5
  461. package/src/providers/ratelimit.ts +4 -0
  462. package/src/providers/registry.ts +19 -8
  463. package/src/providers/retry.ts +174 -39
  464. package/src/providers/speech-to-text/__tests__/resolve.test.ts +55 -0
  465. package/src/providers/speech-to-text/google-gemini-live-stream.ts +4 -4
  466. package/src/providers/speech-to-text/provider-catalog.ts +17 -0
  467. package/src/providers/speech-to-text/resolve.ts +7 -0
  468. package/src/providers/speech-to-text/xai-realtime.test.ts +578 -0
  469. package/src/providers/speech-to-text/xai-realtime.ts +796 -0
  470. package/src/providers/speech-to-text/xai.test.ts +155 -0
  471. package/src/providers/speech-to-text/xai.ts +97 -0
  472. package/src/providers/types.ts +93 -3
  473. package/src/runtime/AGENTS.md +2 -2
  474. package/src/runtime/__tests__/agent-wake.test.ts +43 -2
  475. package/src/runtime/__tests__/interactive-ui.test.ts +673 -0
  476. package/src/runtime/agent-wake.ts +63 -22
  477. package/src/runtime/auth/route-policy.ts +4 -0
  478. package/src/runtime/btw-sidechain.ts +13 -3
  479. package/src/runtime/channel-reply-delivery.ts +106 -2
  480. package/src/runtime/decision-token.ts +116 -0
  481. package/src/runtime/gateway-client.ts +2 -2
  482. package/src/runtime/http-router.ts +32 -0
  483. package/src/runtime/http-server.ts +52 -1
  484. package/src/runtime/http-types.ts +23 -1
  485. package/src/runtime/interactive-ui.ts +362 -0
  486. package/src/runtime/invite-instruction-generator.ts +2 -2
  487. package/src/runtime/migrations/__tests__/gcs-signed-url.test.ts +176 -0
  488. package/src/runtime/migrations/__tests__/vbundle-metadata-merge-integration.test.ts +390 -0
  489. package/src/runtime/migrations/__tests__/vbundle-metadata-merge.test.ts +221 -0
  490. package/src/runtime/migrations/__tests__/vbundle-streaming-importer.test.ts +1540 -0
  491. package/src/runtime/migrations/__tests__/vbundle-streaming-validator.test.ts +453 -0
  492. package/src/runtime/migrations/__tests__/vbundle-tar-stream.test.ts +222 -0
  493. package/src/runtime/migrations/gcs-signed-url.ts +162 -0
  494. package/src/runtime/migrations/vbundle-importer.ts +154 -9
  495. package/src/runtime/migrations/vbundle-metadata-merge.ts +124 -0
  496. package/src/runtime/migrations/vbundle-streaming-importer.ts +2522 -0
  497. package/src/runtime/migrations/vbundle-streaming-validator.ts +244 -0
  498. package/src/runtime/migrations/vbundle-tar-stream.ts +217 -0
  499. package/src/runtime/migrations/vbundle-validator.ts +15 -6
  500. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +111 -0
  501. package/src/runtime/routes/__tests__/migration-import-credential-filter.test.ts +114 -75
  502. package/src/runtime/routes/__tests__/migration-vellum-metadata-reconcile.test.ts +246 -0
  503. package/src/runtime/routes/approval-prompt-ts-tracker.ts +58 -0
  504. package/src/runtime/routes/approval-routes.ts +12 -17
  505. package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +9 -0
  506. package/src/runtime/routes/avatar-routes.ts +20 -4
  507. package/src/runtime/routes/btw-routes.ts +1 -4
  508. package/src/runtime/routes/conversation-management-routes.ts +20 -2
  509. package/src/runtime/routes/conversation-routes.ts +133 -27
  510. package/src/runtime/routes/debug-routes.ts +1 -1
  511. package/src/runtime/routes/diagnostics-routes.ts +6 -4
  512. package/src/runtime/routes/events-routes.ts +16 -0
  513. package/src/runtime/routes/guardian-approval-interception.ts +33 -3
  514. package/src/runtime/routes/guardian-approval-prompt.ts +13 -3
  515. package/src/runtime/routes/home-feed-routes.ts +120 -2
  516. package/src/runtime/routes/inbound-message-handler.ts +912 -2
  517. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +113 -2
  518. package/src/runtime/routes/inbound-stages/background-dispatch.ts +61 -3
  519. package/src/runtime/routes/inbound-stages/edit-intercept.ts +129 -6
  520. package/src/runtime/routes/integrations/slack/channel.ts +25 -3
  521. package/src/runtime/routes/llm-context-normalization.ts +23 -1
  522. package/src/runtime/routes/migration-routes.ts +720 -124
  523. package/src/runtime/routes/settings-routes.ts +4 -2
  524. package/src/runtime/routes/trust-rules-routes.ts +30 -14
  525. package/src/runtime/routes/work-items-routes.test.ts +1 -1
  526. package/src/runtime/routes/work-items-routes.ts +3 -2
  527. package/src/runtime/services/__tests__/analyze-conversation.test.ts +25 -43
  528. package/src/runtime/services/analyze-conversation.ts +12 -16
  529. package/src/runtime/skill-route-registry.ts +28 -6
  530. package/src/schedule/scheduler.ts +8 -0
  531. package/src/security/__tests__/provider-key-env-fallback.test.ts +119 -0
  532. package/src/security/__tests__/untrusted-content.test.ts +109 -0
  533. package/src/security/oauth2.ts +98 -35
  534. package/src/security/secure-keys.ts +7 -8
  535. package/src/security/token-manager.ts +27 -13
  536. package/src/security/untrusted-content.ts +102 -0
  537. package/src/skills/catalog-cache.ts +26 -7
  538. package/src/skills/catalog-install.ts +31 -3
  539. package/src/skills/skill-cache-store.ts +97 -0
  540. package/src/stt/__tests__/daemon-batch-transcriber.test.ts +76 -0
  541. package/src/stt/daemon-batch-transcriber.ts +33 -0
  542. package/src/stt/stt-stream-session.ts +8 -1
  543. package/src/stt/types.ts +5 -1
  544. package/src/subagent/manager.ts +41 -13
  545. package/src/tasks/ephemeral-permissions.ts +9 -4
  546. package/src/telemetry/usage-telemetry-reporter.ts +27 -5
  547. package/src/tools/browser/__tests__/browser-status.test.ts +45 -2
  548. package/src/tools/browser/browser-execution.ts +65 -38
  549. package/src/tools/browser/cdp-client/cdp-inspect/discovery.ts +22 -0
  550. package/src/tools/credentials/tool-policy.ts +39 -5
  551. package/src/tools/credentials/vault.ts +9 -4
  552. package/src/tools/executor.ts +4 -0
  553. package/src/tools/filesystem/write.ts +52 -0
  554. package/src/tools/host-terminal/host-shell.ts +45 -5
  555. package/src/tools/memory/register.test.ts +185 -0
  556. package/src/tools/memory/register.ts +3 -1
  557. package/src/tools/network/web-fetch.ts +20 -10
  558. package/src/tools/network/web-search.ts +19 -4
  559. package/src/tools/permission-checker.ts +36 -15
  560. package/src/tools/policy-context.ts +25 -8
  561. package/src/tools/registry.ts +55 -3
  562. package/src/tools/side-effects.ts +0 -11
  563. package/src/tools/skills/execute.ts +2 -2
  564. package/src/tools/skills/sandbox-runner.ts +5 -2
  565. package/src/tools/terminal/backends/native.ts +51 -2
  566. package/src/tools/terminal/safe-env.ts +3 -2
  567. package/src/tools/terminal/shell.ts +1 -0
  568. package/src/tools/tool-manifest.ts +6 -21
  569. package/src/tools/types.ts +12 -3
  570. package/src/tools/verification-control-plane-policy.ts +1 -1
  571. package/src/tts/__tests__/provider-adapters.test.ts +240 -13
  572. package/src/tts/provider-catalog.ts +18 -0
  573. package/src/tts/providers/index.ts +2 -0
  574. package/src/tts/providers/xai-provider.ts +224 -0
  575. package/src/tts/types.ts +46 -0
  576. package/src/types/tar-stream.d.ts +66 -0
  577. package/src/util/json.ts +17 -0
  578. package/src/util/platform.ts +2 -2
  579. package/src/util/pricing.ts +15 -5
  580. package/src/watcher/engine.ts +1 -1
  581. package/src/watcher/providers/google-calendar.ts +134 -8
  582. package/src/watcher/providers/outlook-calendar.ts +42 -2
  583. package/src/workspace/git-service.ts +23 -4
  584. package/src/workspace/migrations/038-unify-llm-callsite-configs.ts +516 -0
  585. package/src/workspace/migrations/039-drop-legacy-llm-keys.ts +171 -0
  586. package/src/workspace/migrations/040-seed-latency-callsite-defaults.ts +154 -0
  587. package/src/workspace/migrations/041-backfill-google-gmail-settings-scope.ts +57 -0
  588. package/src/workspace/migrations/042-fix-backfill-google-gmail-settings-scope.ts +70 -0
  589. package/src/workspace/migrations/043-release-notes-latex-rendering.ts +75 -0
  590. package/src/workspace/migrations/044-bump-stale-provider-stream-timeout.ts +51 -0
  591. package/src/workspace/migrations/045-release-notes-meet-avatar.ts +130 -0
  592. package/src/workspace/migrations/AGENTS.md +1 -1
  593. package/src/workspace/migrations/registry.ts +16 -0
  594. package/src/workspace/provider-commit-message-generator.ts +19 -38
  595. package/src/__tests__/gmail-archive-fallback.test.ts +0 -193
  596. package/src/__tests__/gmail-archive-gate.test.ts +0 -246
  597. package/src/__tests__/gmail-preferences.test.ts +0 -117
  598. package/src/__tests__/outlook-attachments.test.ts +0 -301
  599. package/src/__tests__/outlook-automation-tools.test.ts +0 -425
  600. package/src/__tests__/outlook-categories.test.ts +0 -212
  601. package/src/__tests__/outlook-compose-tools.test.ts +0 -325
  602. package/src/__tests__/outlook-declutter-tools.test.ts +0 -585
  603. package/src/__tests__/outlook-follow-up.test.ts +0 -196
  604. package/src/__tests__/outlook-trash.test.ts +0 -77
  605. package/src/__tests__/outlook-unsubscribe.test.ts +0 -279
  606. package/src/__tests__/update-bulletin-format.test.ts +0 -181
  607. package/src/__tests__/update-bulletin-state.test.ts +0 -135
  608. package/src/__tests__/update-bulletin.test.ts +0 -478
  609. package/src/__tests__/update-template-contract.test.ts +0 -29
  610. package/src/cli/commands/doctor.ts +0 -341
  611. package/src/config/bundled-skills/browser/SKILL.md +0 -88
  612. package/src/config/bundled-skills/browser/TOOLS.json +0 -516
  613. package/src/config/bundled-skills/browser/tools/browser-attach.ts +0 -12
  614. package/src/config/bundled-skills/browser/tools/browser-click.ts +0 -12
  615. package/src/config/bundled-skills/browser/tools/browser-close.ts +0 -12
  616. package/src/config/bundled-skills/browser/tools/browser-detach.ts +0 -12
  617. package/src/config/bundled-skills/browser/tools/browser-extract.ts +0 -12
  618. package/src/config/bundled-skills/browser/tools/browser-fill-credential.ts +0 -12
  619. package/src/config/bundled-skills/browser/tools/browser-hover.ts +0 -12
  620. package/src/config/bundled-skills/browser/tools/browser-navigate.ts +0 -12
  621. package/src/config/bundled-skills/browser/tools/browser-press-key.ts +0 -12
  622. package/src/config/bundled-skills/browser/tools/browser-screenshot.ts +0 -12
  623. package/src/config/bundled-skills/browser/tools/browser-scroll.ts +0 -12
  624. package/src/config/bundled-skills/browser/tools/browser-select-option.ts +0 -12
  625. package/src/config/bundled-skills/browser/tools/browser-snapshot.ts +0 -12
  626. package/src/config/bundled-skills/browser/tools/browser-status.ts +0 -12
  627. package/src/config/bundled-skills/browser/tools/browser-type.ts +0 -12
  628. package/src/config/bundled-skills/browser/tools/browser-wait-for-download.ts +0 -49
  629. package/src/config/bundled-skills/browser/tools/browser-wait-for.ts +0 -12
  630. package/src/config/bundled-skills/chatgpt-import/SKILL.md +0 -27
  631. package/src/config/bundled-skills/chatgpt-import/TOOLS.json +0 -27
  632. package/src/config/bundled-skills/chatgpt-import/tools/chatgpt-import.ts +0 -378
  633. package/src/config/bundled-skills/gmail/SKILL.md +0 -221
  634. package/src/config/bundled-skills/gmail/TOOLS.json +0 -588
  635. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +0 -256
  636. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +0 -112
  637. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +0 -44
  638. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +0 -81
  639. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +0 -108
  640. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +0 -146
  641. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +0 -53
  642. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +0 -347
  643. package/src/config/bundled-skills/gmail/tools/gmail-preferences-tool.ts +0 -59
  644. package/src/config/bundled-skills/gmail/tools/gmail-preferences.ts +0 -82
  645. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +0 -26
  646. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +0 -347
  647. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +0 -29
  648. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +0 -122
  649. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +0 -67
  650. package/src/config/bundled-skills/gmail/tools/scan-result-store.ts +0 -100
  651. package/src/config/bundled-skills/gmail/tools/shared.ts +0 -47
  652. package/src/config/bundled-skills/google-calendar/SKILL.md +0 -51
  653. package/src/config/bundled-skills/google-calendar/TOOLS.json +0 -226
  654. package/src/config/bundled-skills/google-calendar/calendar-client.ts +0 -223
  655. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +0 -27
  656. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +0 -48
  657. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +0 -19
  658. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +0 -36
  659. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +0 -58
  660. package/src/config/bundled-skills/google-calendar/tools/shared.ts +0 -17
  661. package/src/config/bundled-skills/google-calendar/types.ts +0 -97
  662. package/src/config/bundled-skills/outlook/SKILL.md +0 -196
  663. package/src/config/bundled-skills/outlook/TOOLS.json +0 -530
  664. package/src/config/bundled-skills/outlook/tools/outlook-attachments.ts +0 -85
  665. package/src/config/bundled-skills/outlook/tools/outlook-categories.ts +0 -77
  666. package/src/config/bundled-skills/outlook/tools/outlook-draft.ts +0 -84
  667. package/src/config/bundled-skills/outlook/tools/outlook-follow-up.ts +0 -94
  668. package/src/config/bundled-skills/outlook/tools/outlook-forward.ts +0 -49
  669. package/src/config/bundled-skills/outlook/tools/outlook-outreach-scan.ts +0 -237
  670. package/src/config/bundled-skills/outlook/tools/outlook-rules.ts +0 -161
  671. package/src/config/bundled-skills/outlook/tools/outlook-send-draft.ts +0 -32
  672. package/src/config/bundled-skills/outlook/tools/outlook-sender-digest.ts +0 -272
  673. package/src/config/bundled-skills/outlook/tools/outlook-trash.ts +0 -29
  674. package/src/config/bundled-skills/outlook/tools/outlook-unsubscribe.ts +0 -129
  675. package/src/config/bundled-skills/outlook/tools/outlook-vacation.ts +0 -87
  676. package/src/config/bundled-skills/outlook/tools/shared.ts +0 -20
  677. package/src/config/bundled-skills/outlook-calendar/SKILL.md +0 -51
  678. package/src/config/bundled-skills/outlook-calendar/TOOLS.json +0 -221
  679. package/src/config/bundled-skills/outlook-calendar/calendar-client.ts +0 -252
  680. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-check-availability.ts +0 -53
  681. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-create-event.ts +0 -74
  682. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-get-event.ts +0 -18
  683. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-list-events.ts +0 -46
  684. package/src/config/bundled-skills/outlook-calendar/tools/outlook-calendar-rsvp.ts +0 -36
  685. package/src/config/bundled-skills/outlook-calendar/tools/shared.ts +0 -17
  686. package/src/config/bundled-skills/outlook-calendar/types.ts +0 -120
  687. package/src/config/bundled-skills/slack/SKILL.md +0 -108
  688. package/src/config/bundled-skills/tasks/SKILL.md +0 -37
  689. package/src/config/bundled-skills/tasks/TOOLS.json +0 -353
  690. package/src/config/bundled-skills/tasks/icon.svg +0 -34
  691. package/src/config/bundled-skills/tasks/tools/task-delete.ts +0 -12
  692. package/src/config/bundled-skills/tasks/tools/task-list-add.ts +0 -12
  693. package/src/config/bundled-skills/tasks/tools/task-list-remove.ts +0 -12
  694. package/src/config/bundled-skills/tasks/tools/task-list-show.ts +0 -12
  695. package/src/config/bundled-skills/tasks/tools/task-list-update.ts +0 -12
  696. package/src/config/bundled-skills/tasks/tools/task-list.ts +0 -12
  697. package/src/config/bundled-skills/tasks/tools/task-queue-run.ts +0 -12
  698. package/src/config/bundled-skills/tasks/tools/task-run.ts +0 -12
  699. package/src/config/bundled-skills/tasks/tools/task-save.ts +0 -12
  700. package/src/config/bundled-skills/watcher/SKILL.md +0 -31
  701. package/src/config/bundled-skills/watcher/TOOLS.json +0 -167
  702. package/src/config/bundled-skills/watcher/tools/watcher-create.ts +0 -12
  703. package/src/config/bundled-skills/watcher/tools/watcher-delete.ts +0 -12
  704. package/src/config/bundled-skills/watcher/tools/watcher-digest.ts +0 -12
  705. package/src/config/bundled-skills/watcher/tools/watcher-list.ts +0 -12
  706. package/src/config/bundled-skills/watcher/tools/watcher-update.ts +0 -12
  707. package/src/prompts/templates/UPDATES.md +0 -50
  708. package/src/prompts/update-bulletin-format.ts +0 -85
  709. package/src/prompts/update-bulletin-state.ts +0 -58
  710. package/src/prompts/update-bulletin-template-path.ts +0 -13
  711. package/src/prompts/update-bulletin.ts +0 -139
  712. package/src/shared/provider-env-vars.ts +0 -19
  713. package/src/tools/watcher/create.ts +0 -86
  714. package/src/tools/watcher/delete.ts +0 -36
  715. package/src/tools/watcher/digest.ts +0 -54
  716. package/src/tools/watcher/list.ts +0 -83
  717. package/src/tools/watcher/update.ts +0 -71
@@ -0,0 +1,516 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { WorkspaceMigration } from "./types.js";
5
+
6
+ /**
7
+ * Consolidate scattered LLM-related config keys into the unified `llm` block
8
+ * introduced in PR 1 of the LLM call-site unification plan.
9
+ *
10
+ * What this migration writes (under `llm.*`):
11
+ * - `llm.default` — provider/model/maxTokens/effort/speed/thinking/contextWindow
12
+ * pulled from `services.inference.{provider,model}` and the legacy
13
+ * top-level `maxTokens`/`effort`/`speed`/`thinking`/`contextWindow` keys.
14
+ * `temperature` is seeded as `null` because no current config source maps to
15
+ * it.
16
+ * - `llm.callSites.<id>` — per-call-site overrides derived from the existing
17
+ * scattered config (`heartbeat.speed`, `filing.speed`,
18
+ * `analysis.modelIntent`/`modelOverride`,
19
+ * `memory.summarization.modelIntent`,
20
+ * `workspaceGit.commitMessageLLM.{maxTokens,temperature}`,
21
+ * `ui.greetingModelIntent`, `notifications.decisionModelIntent` (which
22
+ * drives both `notificationDecision` and `preferenceExtraction`),
23
+ * `calls.model`).
24
+ * - `llm.pricingOverrides` — copied from the top-level `pricingOverrides`.
25
+ *
26
+ * What this migration does NOT do:
27
+ * - Delete any of the source keys. The legacy keys remain on disk so
28
+ * existing readers continue to work. PR 19 of the plan removes them from
29
+ * the schema once every call site has been switched over to read through
30
+ * the resolver.
31
+ *
32
+ * Idempotency:
33
+ * - Early-returns when `config.llm.default` is already present, so re-runs
34
+ * and runs against an already-migrated workspace are no-ops.
35
+ * - Early-returns on missing/malformed `config.json`.
36
+ *
37
+ * Rollback (`down`):
38
+ * - Reverses the mapping best-effort by extracting `llm.default.*` back to
39
+ * top-level + `services.inference`, extracting `llm.callSites.*` back to
40
+ * scattered keys, copying `llm.pricingOverrides` back to top-level
41
+ * `pricingOverrides`, and finally removing `llm`. After PRs 7-18 land and
42
+ * callers stop reading the old keys, rollback fidelity will degrade
43
+ * (callers will only see what `down` writes back), which is acceptable
44
+ * for a development rollback path.
45
+ */
46
+ export const unifyLlmCallSiteConfigsMigration: WorkspaceMigration = {
47
+ id: "038-unify-llm-callsite-configs",
48
+ description:
49
+ "Consolidate scattered LLM config keys into unified llm.{default,profiles,callSites} structure",
50
+ run(workspaceDir: string): void {
51
+ const configPath = join(workspaceDir, "config.json");
52
+ if (!existsSync(configPath)) return;
53
+
54
+ let config: Record<string, unknown>;
55
+ try {
56
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
57
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
58
+ config = raw as Record<string, unknown>;
59
+ } catch {
60
+ return;
61
+ }
62
+
63
+ // Idempotency: skip only when `llm.default` is present AND no legacy
64
+ // source key remains on disk. The `&& !hasLegacyData` clause matters
65
+ // because `AssistantConfigSchema` wires `llm: LLMSchema.default(LLMSchema
66
+ // .parse({}))`, which makes `loadConfig()` inject a full schema-default
67
+ // `llm.default` block to disk on first daemon boot under the new schema.
68
+ // If that boot happened before this migration was added (or before the
69
+ // daemon binary that includes it landed on the user's machine),
70
+ // `llm.default` will be present BUT will hold schema defaults rather
71
+ // than the user's actual `services.inference.{provider, model}` values.
72
+ // Returning early here would let migration 039 strip the legacy keys
73
+ // silently, dropping the user's real configuration.
74
+ const existingLlm = readObject(config.llm);
75
+ const existingDefault = existingLlm
76
+ ? readObject(existingLlm.default)
77
+ : null;
78
+ const hasLegacyData =
79
+ hasLegacyLlmDefaultSource(config) || hasLegacyCallSiteSource(config);
80
+ if (existingDefault !== null && !hasLegacyData) {
81
+ return;
82
+ }
83
+
84
+ // ── Build llm.default ──────────────────────────────────────────────
85
+ // Precedence (highest wins): legacy source key → existing `llm.default`
86
+ // value → migration fallback. Existing values come second so that on a
87
+ // re-run AFTER legacy keys are stripped, user-set `llm.default.*` values
88
+ // survive untouched (the early-return above handles the common no-op
89
+ // path; this ordering covers the partial-state case).
90
+ const services = readObject(config.services) ?? {};
91
+ const inference = readObject(services.inference) ?? {};
92
+
93
+ const defaultBlock: Record<string, unknown> = {
94
+ provider:
95
+ readString(inference.provider) ??
96
+ readString(config.provider) ??
97
+ readString(existingDefault?.provider) ??
98
+ "anthropic",
99
+ model:
100
+ readString(inference.model) ??
101
+ readString(config.model) ??
102
+ readString(existingDefault?.model) ??
103
+ "claude-opus-4-6",
104
+ maxTokens:
105
+ readPositiveInt(config.maxTokens) ??
106
+ readPositiveInt(existingDefault?.maxTokens) ??
107
+ 64000,
108
+ effort:
109
+ readEnum(config.effort, EFFORT_VALUES) ??
110
+ readEnum(existingDefault?.effort, EFFORT_VALUES) ??
111
+ "max",
112
+ speed:
113
+ readEnum(config.speed, SPEED_VALUES) ??
114
+ readEnum(existingDefault?.speed, SPEED_VALUES) ??
115
+ "standard",
116
+ // No current legacy key maps to temperature; preserve existing
117
+ // `llm.default.temperature` if a user set one, else seed null to
118
+ // match `LLMConfigBase` defaults.
119
+ temperature:
120
+ existingDefault && "temperature" in existingDefault
121
+ ? (existingDefault.temperature as number | null)
122
+ : null,
123
+ };
124
+ const thinking =
125
+ readObject(config.thinking) ??
126
+ (existingDefault ? readObject(existingDefault.thinking) : null);
127
+ if (thinking !== null) {
128
+ defaultBlock.thinking = thinking;
129
+ }
130
+ const contextWindow =
131
+ readObject(config.contextWindow) ??
132
+ (existingDefault ? readObject(existingDefault.contextWindow) : null);
133
+ if (contextWindow !== null) {
134
+ defaultBlock.contextWindow = contextWindow;
135
+ }
136
+
137
+ // ── Build llm.callSites ────────────────────────────────────────────
138
+ const callSites: Record<string, Record<string, unknown>> = {};
139
+
140
+ const heartbeat = readObject(config.heartbeat);
141
+ const heartbeatSpeed = heartbeat
142
+ ? readEnum(heartbeat.speed, SPEED_VALUES)
143
+ : undefined;
144
+ if (heartbeatSpeed !== undefined && heartbeatSpeed !== defaultBlock.speed) {
145
+ callSites.heartbeatAgent = { speed: heartbeatSpeed };
146
+ }
147
+
148
+ const filing = readObject(config.filing);
149
+ const filingSpeed = filing
150
+ ? readEnum(filing.speed, SPEED_VALUES)
151
+ : undefined;
152
+ if (filingSpeed !== undefined && filingSpeed !== defaultBlock.speed) {
153
+ callSites.filingAgent = { speed: filingSpeed };
154
+ }
155
+
156
+ const analysis = readObject(config.analysis);
157
+ if (analysis !== null) {
158
+ const analysisOverride = readString(analysis.modelOverride);
159
+ const analysisIntent = readModelIntent(analysis.modelIntent);
160
+ const analysisCallSite: Record<string, unknown> = {};
161
+ // `modelOverride` is shaped as `"provider/model"` — explode into the
162
+ // resolver's separate provider/model fields. If the string lacks a
163
+ // slash, treat the whole value as the model and inherit the active
164
+ // provider implicitly via the resolver's default merge.
165
+ if (analysisOverride !== undefined) {
166
+ const [providerPart, ...modelParts] = analysisOverride.split("/");
167
+ if (modelParts.length > 0 && providerPart.length > 0) {
168
+ analysisCallSite.provider = providerPart;
169
+ analysisCallSite.model = modelParts.join("/");
170
+ } else {
171
+ analysisCallSite.model = analysisOverride;
172
+ }
173
+ } else if (analysisIntent !== undefined) {
174
+ // Resolve intent to provider/model using the same lookup the runtime
175
+ // uses (mirrors `providers/model-intents.ts` PROVIDER_MODEL_INTENTS).
176
+ const provider = String(defaultBlock.provider);
177
+ const resolvedModel = resolveModelIntentForProvider(
178
+ provider,
179
+ analysisIntent,
180
+ );
181
+ if (resolvedModel !== undefined) {
182
+ analysisCallSite.model = resolvedModel;
183
+ }
184
+ }
185
+ if (Object.keys(analysisCallSite).length > 0) {
186
+ callSites.analyzeConversation = analysisCallSite;
187
+ }
188
+ }
189
+
190
+ const memory = readObject(config.memory);
191
+ const summarization = memory ? readObject(memory.summarization) : null;
192
+ const summarizationIntent = summarization
193
+ ? readModelIntent(summarization.modelIntent)
194
+ : undefined;
195
+ if (summarizationIntent !== undefined) {
196
+ const provider = String(defaultBlock.provider);
197
+ const resolvedModel = resolveModelIntentForProvider(
198
+ provider,
199
+ summarizationIntent,
200
+ );
201
+ if (resolvedModel !== undefined) {
202
+ callSites.conversationSummarization = { model: resolvedModel };
203
+ }
204
+ }
205
+
206
+ const workspaceGit = readObject(config.workspaceGit);
207
+ const commitMessageLLM = workspaceGit
208
+ ? readObject(workspaceGit.commitMessageLLM)
209
+ : null;
210
+ if (commitMessageLLM !== null) {
211
+ const commitOverride: Record<string, unknown> = {};
212
+ const cmMaxTokens = readPositiveInt(commitMessageLLM.maxTokens);
213
+ if (cmMaxTokens !== undefined) {
214
+ commitOverride.maxTokens = cmMaxTokens;
215
+ }
216
+ const cmTemperature = readTemperature(commitMessageLLM.temperature);
217
+ if (cmTemperature !== undefined) {
218
+ commitOverride.temperature = cmTemperature;
219
+ }
220
+ if (Object.keys(commitOverride).length > 0) {
221
+ callSites.commitMessage = commitOverride;
222
+ }
223
+ }
224
+
225
+ const ui = readObject(config.ui);
226
+ const greetingIntent = ui
227
+ ? readModelIntent(ui.greetingModelIntent)
228
+ : undefined;
229
+ if (greetingIntent !== undefined) {
230
+ const provider = String(defaultBlock.provider);
231
+ const resolvedModel = resolveModelIntentForProvider(
232
+ provider,
233
+ greetingIntent,
234
+ );
235
+ if (resolvedModel !== undefined) {
236
+ callSites.emptyStateGreeting = { model: resolvedModel };
237
+ }
238
+ }
239
+
240
+ const notifications = readObject(config.notifications);
241
+ const notificationIntent = notifications
242
+ ? readModelIntent(notifications.decisionModelIntent)
243
+ : undefined;
244
+ if (notificationIntent !== undefined) {
245
+ const provider = String(defaultBlock.provider);
246
+ const resolvedModel = resolveModelIntentForProvider(
247
+ provider,
248
+ notificationIntent,
249
+ );
250
+ if (resolvedModel !== undefined) {
251
+ // `notifications.decisionModelIntent` drives BOTH the notification
252
+ // decision engine (`notifications/decision-engine.ts`) AND the
253
+ // preference extractor (`notifications/preference-extractor.ts`), so
254
+ // seed both call sites from the same source intent. Confirmed via
255
+ // grep — those are the only two readers of the legacy key.
256
+ callSites.notificationDecision = { model: resolvedModel };
257
+ callSites.preferenceExtraction = { model: resolvedModel };
258
+ }
259
+ }
260
+
261
+ const calls = readObject(config.calls);
262
+ const callsModel = calls ? readString(calls.model) : undefined;
263
+ if (callsModel !== undefined) {
264
+ callSites.callAgent = { model: callsModel };
265
+ }
266
+
267
+ // ── Build llm block ────────────────────────────────────────────────
268
+ //
269
+ // Preserve any pre-existing `llm` subtree. Reaching this point means
270
+ // `llm.default` was absent (idempotency check at the top), but a user
271
+ // may still have defined `llm.callSites`, `llm.profiles`, or
272
+ // `llm.pricingOverrides` directly. Wholesale-replacing `config.llm`
273
+ // would silently drop those user overrides, so deep-merge instead:
274
+ // - `default`: always taken from this migration (we just synthesized
275
+ // it from legacy keys).
276
+ // - `callSites`: per-key merge, with migration-derived entries
277
+ // overwriting pre-existing entries that share the same key.
278
+ // - `profiles`: preserved verbatim from existing `llm.profiles`.
279
+ // - `pricingOverrides`: prefer the migration-derived value (legacy
280
+ // top-level `pricingOverrides`); fall back to existing
281
+ // `llm.pricingOverrides` if the legacy key is absent.
282
+ const llmBlock: Record<string, unknown> = {
283
+ default: defaultBlock,
284
+ };
285
+ const existingProfiles = existingLlm
286
+ ? readObject(existingLlm.profiles)
287
+ : null;
288
+ if (existingProfiles !== null) {
289
+ llmBlock.profiles = existingProfiles;
290
+ }
291
+ const existingCallSites = existingLlm
292
+ ? readObject(existingLlm.callSites)
293
+ : null;
294
+ const mergedCallSites: Record<string, Record<string, unknown>> = {};
295
+ if (existingCallSites !== null) {
296
+ for (const [key, value] of Object.entries(existingCallSites)) {
297
+ const obj = readObject(value);
298
+ if (obj !== null) {
299
+ mergedCallSites[key] = obj;
300
+ }
301
+ }
302
+ }
303
+ for (const [key, value] of Object.entries(callSites)) {
304
+ mergedCallSites[key] = value;
305
+ }
306
+ if (Object.keys(mergedCallSites).length > 0) {
307
+ llmBlock.callSites = mergedCallSites;
308
+ }
309
+ const pricingOverrides = config.pricingOverrides;
310
+ if (Array.isArray(pricingOverrides)) {
311
+ llmBlock.pricingOverrides = pricingOverrides;
312
+ } else if (existingLlm && Array.isArray(existingLlm.pricingOverrides)) {
313
+ llmBlock.pricingOverrides = existingLlm.pricingOverrides;
314
+ }
315
+
316
+ config.llm = llmBlock;
317
+
318
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
319
+ },
320
+ /**
321
+ * Documented no-op since PR 19 of the unify-llm-callsites plan.
322
+ *
323
+ * The legacy keys that this migration consolidates (`services.inference.
324
+ * {provider,model}`, top-level `maxTokens`/`effort`/`speed`/`thinking`/
325
+ * `contextWindow`/`pricingOverrides`, `heartbeat.speed`, `filing.speed`,
326
+ * `analysis.modelIntent`/`modelOverride`, `memory.summarization.modelIntent`,
327
+ * `notifications.decisionModelIntent`, `ui.greetingModelIntent`,
328
+ * `calls.model`, and `workspaceGit.commitMessageLLM.{maxTokens,temperature}`)
329
+ * were removed from `AssistantConfigSchema` in PR 19. Re-creating them in
330
+ * `down()` would have no effect on the running daemon (no code reads them
331
+ * any more), so a rollback that needs to undo this migration must instead
332
+ * roll back the application binary to a build that predates PR 19.
333
+ */
334
+ down(_workspaceDir: string): void {
335
+ // Forward-only after PR 19. See comment above.
336
+ },
337
+ };
338
+
339
+ // ---------------------------------------------------------------------------
340
+ // Helpers — self-contained per workspace migrations AGENTS.md
341
+ // ---------------------------------------------------------------------------
342
+
343
+ // `xhigh` was added to the runtime enum in main PR #26117 after this
344
+ // migration was authored. Widening the validation set is safe (it can only
345
+ // admit MORE legitimate values, never narrow them) and prevents an `effort:
346
+ // "xhigh"` legacy value from being silently downgraded to "max" during the
347
+ // consolidation below.
348
+ const EFFORT_VALUES = new Set(["low", "medium", "high", "xhigh", "max"]);
349
+ const SPEED_VALUES = new Set(["standard", "fast"]);
350
+ const MODEL_INTENT_VALUES = new Set([
351
+ "latency-optimized",
352
+ "quality-optimized",
353
+ "vision-optimized",
354
+ ]);
355
+
356
+ /**
357
+ * Mirror of `providers/model-intents.ts:PROVIDER_MODEL_INTENTS` snapshotted at
358
+ * the time this migration was authored. Migrations are write-once and must be
359
+ * self-contained — duplicating the table here means the migration's behavior
360
+ * is frozen against the catalog as it existed when users upgraded across this
361
+ * boundary, even if the runtime catalog evolves later.
362
+ */
363
+ const PROVIDER_MODEL_INTENTS_SNAPSHOT: Record<
364
+ string,
365
+ Record<string, string>
366
+ > = {
367
+ anthropic: {
368
+ "latency-optimized": "claude-haiku-4-5-20251001",
369
+ "quality-optimized": "claude-opus-4-7",
370
+ "vision-optimized": "claude-opus-4-6",
371
+ },
372
+ openai: {
373
+ "latency-optimized": "gpt-5.4-nano",
374
+ "quality-optimized": "gpt-5.4",
375
+ "vision-optimized": "gpt-5.4",
376
+ },
377
+ gemini: {
378
+ "latency-optimized": "gemini-3-flash",
379
+ "quality-optimized": "gemini-3-flash",
380
+ "vision-optimized": "gemini-3-flash",
381
+ },
382
+ ollama: {
383
+ "latency-optimized": "llama3.2",
384
+ "quality-optimized": "llama3.2",
385
+ "vision-optimized": "llama3.2",
386
+ },
387
+ fireworks: {
388
+ "latency-optimized": "accounts/fireworks/models/kimi-k2p5",
389
+ "quality-optimized": "accounts/fireworks/models/kimi-k2p5",
390
+ "vision-optimized": "accounts/fireworks/models/kimi-k2p5",
391
+ },
392
+ openrouter: {
393
+ "latency-optimized": "anthropic/claude-haiku-4.5",
394
+ "quality-optimized": "anthropic/claude-opus-4.7",
395
+ "vision-optimized": "anthropic/claude-opus-4.6",
396
+ },
397
+ };
398
+
399
+ function resolveModelIntentForProvider(
400
+ provider: string,
401
+ intent: string,
402
+ ): string | undefined {
403
+ return PROVIDER_MODEL_INTENTS_SNAPSHOT[provider]?.[intent];
404
+ }
405
+
406
+ function readObject(value: unknown): Record<string, unknown> | null {
407
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
408
+ return null;
409
+ }
410
+ return value as Record<string, unknown>;
411
+ }
412
+
413
+ function readString(value: unknown): string | undefined {
414
+ return typeof value === "string" && value.length > 0 ? value : undefined;
415
+ }
416
+
417
+ function readPositiveInt(value: unknown): number | undefined {
418
+ return typeof value === "number" && Number.isInteger(value) && value > 0
419
+ ? value
420
+ : undefined;
421
+ }
422
+
423
+ function readEnum<T extends string>(
424
+ value: unknown,
425
+ allowed: Set<string>,
426
+ ): T | undefined {
427
+ return typeof value === "string" && allowed.has(value)
428
+ ? (value as T)
429
+ : undefined;
430
+ }
431
+
432
+ function readModelIntent(value: unknown): string | undefined {
433
+ return typeof value === "string" && MODEL_INTENT_VALUES.has(value)
434
+ ? value
435
+ : undefined;
436
+ }
437
+
438
+ function readTemperature(value: unknown): number | undefined {
439
+ return typeof value === "number" &&
440
+ Number.isFinite(value) &&
441
+ value >= 0 &&
442
+ value <= 2
443
+ ? value
444
+ : undefined;
445
+ }
446
+
447
+ /**
448
+ * Returns true if any source key that this migration consolidates into
449
+ * `llm.default` is still present on disk. The `provider`/`model`/etc. checks
450
+ * cover the `services.inference` and top-level legacy locations; their
451
+ * presence proves migration 039 hasn't yet stripped them, which means we
452
+ * MUST re-process even if `llm.default` already exists (it may have been
453
+ * injected by `loadConfig()`'s schema-default backfill rather than by a
454
+ * previous run of this migration).
455
+ */
456
+ function hasLegacyLlmDefaultSource(config: Record<string, unknown>): boolean {
457
+ const services = readObject(config.services);
458
+ const inference = services ? readObject(services.inference) : null;
459
+ if (
460
+ inference &&
461
+ (readString(inference.provider) !== undefined ||
462
+ readString(inference.model) !== undefined)
463
+ ) {
464
+ return true;
465
+ }
466
+ for (const key of [
467
+ "provider",
468
+ "model",
469
+ "maxTokens",
470
+ "effort",
471
+ "speed",
472
+ "thinking",
473
+ "contextWindow",
474
+ "pricingOverrides",
475
+ ]) {
476
+ if (key in config) return true;
477
+ }
478
+ return false;
479
+ }
480
+
481
+ /**
482
+ * Returns true if any source key that this migration consolidates into
483
+ * `llm.callSites` is still present on disk. Same idempotency justification
484
+ * as `hasLegacyLlmDefaultSource`: their presence proves migration 039
485
+ * hasn't yet stripped them and re-processing is required.
486
+ */
487
+ function hasLegacyCallSiteSource(config: Record<string, unknown>): boolean {
488
+ const heartbeat = readObject(config.heartbeat);
489
+ if (heartbeat && "speed" in heartbeat) return true;
490
+ const filing = readObject(config.filing);
491
+ if (filing && "speed" in filing) return true;
492
+ const analysis = readObject(config.analysis);
493
+ if (analysis && ("modelIntent" in analysis || "modelOverride" in analysis)) {
494
+ return true;
495
+ }
496
+ const memory = readObject(config.memory);
497
+ const summarization = memory ? readObject(memory.summarization) : null;
498
+ if (summarization && "modelIntent" in summarization) return true;
499
+ const notifications = readObject(config.notifications);
500
+ if (notifications && "decisionModelIntent" in notifications) return true;
501
+ const ui = readObject(config.ui);
502
+ if (ui && "greetingModelIntent" in ui) return true;
503
+ const calls = readObject(config.calls);
504
+ if (calls && "model" in calls) return true;
505
+ const workspaceGit = readObject(config.workspaceGit);
506
+ const commitMessageLLM = workspaceGit
507
+ ? readObject(workspaceGit.commitMessageLLM)
508
+ : null;
509
+ if (
510
+ commitMessageLLM &&
511
+ ("maxTokens" in commitMessageLLM || "temperature" in commitMessageLLM)
512
+ ) {
513
+ return true;
514
+ }
515
+ return false;
516
+ }
@@ -0,0 +1,171 @@
1
+ import { existsSync, readFileSync, writeFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+
4
+ import type { WorkspaceMigration } from "./types.js";
5
+
6
+ /**
7
+ * Strip the now-removed legacy LLM-related keys from existing `config.json`
8
+ * files. PR 19 of the unify-llm-callsites plan removed these keys from
9
+ * `AssistantConfigSchema`; Zod silently strips unknown fields when re-parsing,
10
+ * but the keys would otherwise persist on disk forever and re-appear in any
11
+ * exported config snapshot. Erasing them keeps `config.json` lean and matches
12
+ * the schema that the in-memory loader sees.
13
+ *
14
+ * Keys removed:
15
+ * - Top level: `maxTokens`, `effort`, `speed`, `thinking`, `contextWindow`,
16
+ * `pricingOverrides`.
17
+ * - `services.inference.{provider, model}` (the `mode` field stays — it
18
+ * governs `managed` vs `your-own` routing, which is orthogonal to LLM
19
+ * model selection).
20
+ * - `heartbeat.speed`, `filing.speed`.
21
+ * - `analysis.modelIntent`, `analysis.modelOverride`.
22
+ * - `memory.summarization.modelIntent`.
23
+ * - `notifications.decisionModelIntent`.
24
+ * - `ui.greetingModelIntent`.
25
+ * - `calls.model`.
26
+ * - `workspaceGit.commitMessageLLM.{maxTokens, temperature,
27
+ * useConfiguredProvider, providerFastModelOverrides}`.
28
+ *
29
+ * Preconditions: this migration depends on
30
+ * `038-unify-llm-callsite-configs` having already populated `llm.default` /
31
+ * `llm.callSites` / `llm.pricingOverrides` from these legacy keys. The
32
+ * registry guarantees ordering.
33
+ *
34
+ * Idempotency: each delete is wrapped in a key-exists check so re-runs are
35
+ * no-ops. Empty objects are left in place rather than recursively pruned —
36
+ * that matches Zod's default behavior of treating an absent value the same
37
+ * as an empty `{}` for nested schemas.
38
+ */
39
+ export const dropLegacyLlmKeysMigration: WorkspaceMigration = {
40
+ id: "039-drop-legacy-llm-keys",
41
+ description:
42
+ "Strip deprecated scattered LLM-related keys from config.json (post-PR-19 cleanup)",
43
+ run(workspaceDir: string): void {
44
+ const configPath = join(workspaceDir, "config.json");
45
+ if (!existsSync(configPath)) return;
46
+
47
+ let config: Record<string, unknown>;
48
+ try {
49
+ const raw = JSON.parse(readFileSync(configPath, "utf-8"));
50
+ if (!raw || typeof raw !== "object" || Array.isArray(raw)) return;
51
+ config = raw as Record<string, unknown>;
52
+ } catch {
53
+ return;
54
+ }
55
+
56
+ let mutated = false;
57
+
58
+ for (const key of [
59
+ "maxTokens",
60
+ "effort",
61
+ "speed",
62
+ "thinking",
63
+ "contextWindow",
64
+ "pricingOverrides",
65
+ ]) {
66
+ if (key in config) {
67
+ delete config[key];
68
+ mutated = true;
69
+ }
70
+ }
71
+
72
+ const services = readObject(config.services);
73
+ if (services !== null) {
74
+ const inference = readObject(services.inference);
75
+ if (inference !== null) {
76
+ for (const key of ["provider", "model"]) {
77
+ if (key in inference) {
78
+ delete inference[key];
79
+ mutated = true;
80
+ }
81
+ }
82
+ }
83
+ }
84
+
85
+ const heartbeat = readObject(config.heartbeat);
86
+ if (heartbeat !== null && "speed" in heartbeat) {
87
+ delete heartbeat.speed;
88
+ mutated = true;
89
+ }
90
+
91
+ const filing = readObject(config.filing);
92
+ if (filing !== null && "speed" in filing) {
93
+ delete filing.speed;
94
+ mutated = true;
95
+ }
96
+
97
+ const analysis = readObject(config.analysis);
98
+ if (analysis !== null) {
99
+ for (const key of ["modelIntent", "modelOverride"]) {
100
+ if (key in analysis) {
101
+ delete analysis[key];
102
+ mutated = true;
103
+ }
104
+ }
105
+ }
106
+
107
+ const memory = readObject(config.memory);
108
+ if (memory !== null) {
109
+ const summarization = readObject(memory.summarization);
110
+ if (summarization !== null && "modelIntent" in summarization) {
111
+ delete summarization.modelIntent;
112
+ mutated = true;
113
+ }
114
+ }
115
+
116
+ const notifications = readObject(config.notifications);
117
+ if (notifications !== null && "decisionModelIntent" in notifications) {
118
+ delete notifications.decisionModelIntent;
119
+ mutated = true;
120
+ }
121
+
122
+ const ui = readObject(config.ui);
123
+ if (ui !== null && "greetingModelIntent" in ui) {
124
+ delete ui.greetingModelIntent;
125
+ mutated = true;
126
+ }
127
+
128
+ const calls = readObject(config.calls);
129
+ if (calls !== null && "model" in calls) {
130
+ delete calls.model;
131
+ mutated = true;
132
+ }
133
+
134
+ const workspaceGit = readObject(config.workspaceGit);
135
+ if (workspaceGit !== null) {
136
+ const commitMessageLLM = readObject(workspaceGit.commitMessageLLM);
137
+ if (commitMessageLLM !== null) {
138
+ for (const key of [
139
+ "maxTokens",
140
+ "temperature",
141
+ "useConfiguredProvider",
142
+ "providerFastModelOverrides",
143
+ ]) {
144
+ if (key in commitMessageLLM) {
145
+ delete commitMessageLLM[key];
146
+ mutated = true;
147
+ }
148
+ }
149
+ }
150
+ }
151
+
152
+ if (!mutated) return;
153
+
154
+ writeFileSync(configPath, JSON.stringify(config, null, 2) + "\n");
155
+ },
156
+ /**
157
+ * Forward-only. Restoring the deleted keys would re-introduce schema-validation
158
+ * warnings and have no runtime effect — every reader migrated to `llm.default`
159
+ * / `llm.callSites` in PR 19.
160
+ */
161
+ down(_workspaceDir: string): void {
162
+ // no-op
163
+ },
164
+ };
165
+
166
+ function readObject(value: unknown): Record<string, unknown> | null {
167
+ if (value === null || typeof value !== "object" || Array.isArray(value)) {
168
+ return null;
169
+ }
170
+ return value as Record<string, unknown>;
171
+ }