@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
@@ -1,33 +1,14 @@
1
1
  /**
2
- * `vellum backup` — manage automated backup configuration and list snapshots.
2
+ * `assistant backup` — manage automated backup configuration and list snapshots.
3
3
  *
4
- * All subcommands run in-process (they do not call the daemon HTTP port).
5
- * Config mutations go through `loadRawConfig` / `setNestedValue` / `saveRawConfig`
6
- * so the on-disk `config.json` is the single source of truth and the daemon's
7
- * config cache is invalidated via `saveRawConfig`.
4
+ * Thin IPC wrapper: each subcommand forwards its request to the daemon via
5
+ * cliIpcCall and never imports daemon-internal modules.
8
6
  */
9
7
 
10
- import { stat } from "node:fs/promises";
11
- import { dirname } from "node:path";
12
-
13
8
  import type { Command } from "commander";
14
9
 
15
- import {
16
- listSnapshotsInDir,
17
- type SnapshotEntry,
18
- } from "../../backup/list-snapshots.js";
19
- import {
20
- getLocalBackupsDir,
21
- resolveOffsiteDestinations,
22
- } from "../../backup/paths.js";
23
- import {
24
- getConfig,
25
- loadRawConfig,
26
- saveRawConfig,
27
- setNestedValue,
28
- } from "../../config/loader.js";
29
- import type { BackupDestination } from "../../config/schema.js";
30
- import { getMemoryCheckpoint } from "../../memory/checkpoints.js";
10
+ import { cliIpcCall, exitFromIpcResult } from "../../ipc/cli-client.js";
11
+ import { registerCommand } from "../lib/register-command.js";
31
12
  import { log } from "../logger.js";
32
13
 
33
14
  // ---------------------------------------------------------------------------
@@ -43,7 +24,7 @@ function formatBytes(bytes: number): string {
43
24
  return `${(bytes / (1024 * 1024 * 1024)).toFixed(2)} GB`;
44
25
  }
45
26
 
46
- /** Format a Date as `YYYY-MM-DD HH:MM UTC`. */
27
+ /** Format an ISO date string as `YYYY-MM-DD HH:MM UTC`. */
47
28
  function formatDate(date: Date): string {
48
29
  const y = date.getUTCFullYear().toString().padStart(4, "0");
49
30
  const mo = (date.getUTCMonth() + 1).toString().padStart(2, "0");
@@ -72,348 +53,19 @@ function formatDurationShort(ms: number): string {
72
53
  return `${days}d ${remHours}h`;
73
54
  }
74
55
 
75
- // ---------------------------------------------------------------------------
76
- // Reachability probe
77
- // ---------------------------------------------------------------------------
78
-
79
- /**
80
- * Check whether an offsite destination's parent directory exists. Mirrors the
81
- * reachability check in the backup worker — if the parent is missing (e.g.
82
- * iCloud Drive not enabled, external SSD unplugged) the destination is
83
- * considered unreachable and we skip it at runtime.
84
- */
85
- async function isDestinationReachable(destPath: string): Promise<boolean> {
86
- try {
87
- await stat(dirname(destPath));
88
- return true;
89
- } catch {
90
- return false;
91
- }
92
- }
93
-
94
- // ---------------------------------------------------------------------------
95
- // Exported handlers — exported so tests can drive them directly.
96
- // ---------------------------------------------------------------------------
97
-
98
- export interface EnableOptions {
99
- interval?: string;
100
- retention?: string;
101
- offsite?: boolean;
102
- }
103
-
104
- export function handleEnable(opts: EnableOptions): void {
105
- const raw = loadRawConfig();
106
- setNestedValue(raw, "backup.enabled", true);
107
-
108
- if (opts.interval !== undefined) {
109
- const hours = Number.parseInt(opts.interval, 10);
110
- if (!Number.isFinite(hours) || hours < 1) {
111
- log.error(
112
- `Invalid --interval "${opts.interval}". Must be a positive integer (hours). ` +
113
- `Run 'vellum backup enable --help' for usage.`,
114
- );
115
- process.exitCode = 1;
116
- return;
117
- }
118
- setNestedValue(raw, "backup.intervalHours", hours);
119
- }
120
-
121
- if (opts.retention !== undefined) {
122
- const count = Number.parseInt(opts.retention, 10);
123
- if (!Number.isFinite(count) || count < 1) {
124
- log.error(
125
- `Invalid --retention "${opts.retention}". Must be a positive integer. ` +
126
- `Run 'vellum backup enable --help' for usage.`,
127
- );
128
- process.exitCode = 1;
129
- return;
130
- }
131
- setNestedValue(raw, "backup.retention", count);
132
- }
133
-
134
- // commander's `.option("--no-offsite", ...)` sets `opts.offsite = false`
135
- // when the flag is present and leaves it `undefined` otherwise. Only a
136
- // literal `false` flips the offsite switch — we never touch `destinations`.
137
- if (opts.offsite === false) {
138
- setNestedValue(raw, "backup.offsite.enabled", false);
139
- }
140
-
141
- saveRawConfig(raw);
142
-
143
- const cfg = getConfig().backup;
144
- log.info(
145
- `Automatic backups enabled (interval=${cfg.intervalHours}h, retention=${cfg.retention}, offsite=${cfg.offsite.enabled ? "on" : "off"})`,
146
- );
147
- }
148
-
149
- export function handleDisable(): void {
150
- const raw = loadRawConfig();
151
- setNestedValue(raw, "backup.enabled", false);
152
- saveRawConfig(raw);
153
- log.info("Automatic backups disabled");
154
- }
155
-
156
- // ---------------------------------------------------------------------------
157
- // destinations subgroup handlers
158
- // ---------------------------------------------------------------------------
159
-
160
- /**
161
- * Load the raw destinations array, materializing the iCloud default on first
162
- * touch. Returns the array plus the raw config so callers can mutate and
163
- * re-persist.
164
- *
165
- * When `backup.offsite.destinations` is `null` in config, the runtime uses the
166
- * iCloud default — but that default is implicit. On first `add`/`remove`/
167
- * `set-encrypt`, we need to make it explicit so subsequent mutations have
168
- * something to mutate.
169
- */
170
- function loadDestinationsForMutation(): {
171
- raw: Record<string, unknown>;
172
- destinations: BackupDestination[];
173
- } {
174
- const raw = loadRawConfig();
175
- const current = getConfig().backup.offsite.destinations;
176
- const destinations = resolveOffsiteDestinations(current);
177
- return { raw, destinations };
178
- }
179
-
180
- export async function handleDestinationsList(): Promise<void> {
181
- const cfg = getConfig().backup;
182
- const destinations = resolveOffsiteDestinations(cfg.offsite.destinations);
183
-
184
- if (destinations.length === 0) {
185
- log.info("No offsite destinations configured");
186
- return;
187
- }
188
-
189
- const pathW = Math.max(4, ...destinations.map((d) => d.path.length));
190
- log.info("Path".padEnd(pathW) + " " + "Encrypted");
191
- log.info("-".repeat(pathW + 2 + 9));
192
- for (const d of destinations) {
193
- log.info(d.path.padEnd(pathW) + " " + (d.encrypt ? "yes" : "no"));
194
- }
195
- }
196
-
197
- export interface DestinationAddOptions {
198
- plaintext?: boolean;
199
- }
200
-
201
- export function handleDestinationsAdd(
202
- path: string,
203
- opts: DestinationAddOptions,
204
- ): void {
205
- const { raw, destinations } = loadDestinationsForMutation();
206
-
207
- if (destinations.some((d) => d.path === path)) {
208
- log.error(
209
- `Destination "${path}" already exists. Run 'vellum backup destinations list' to see configured destinations.`,
210
- );
211
- process.exitCode = 1;
212
- return;
213
- }
214
-
215
- const next: BackupDestination[] = [
216
- ...destinations,
217
- { path, encrypt: !opts.plaintext },
218
- ];
219
- setNestedValue(raw, "backup.offsite.destinations", next);
220
- saveRawConfig(raw);
221
- log.info(
222
- `Added destination ${path} (${opts.plaintext ? "plaintext" : "encrypted"})`,
223
- );
224
- }
225
-
226
- export function handleDestinationsRemove(path: string): void {
227
- const { raw, destinations } = loadDestinationsForMutation();
228
-
229
- const filtered = destinations.filter((d) => d.path !== path);
230
- if (filtered.length === destinations.length) {
231
- log.error(
232
- `Destination "${path}" not found. Run 'vellum backup destinations list' to see configured destinations.`,
233
- );
234
- process.exitCode = 1;
235
- return;
236
- }
237
-
238
- setNestedValue(raw, "backup.offsite.destinations", filtered);
239
- saveRawConfig(raw);
240
- log.info(`Removed destination ${path}`);
241
- }
242
-
243
- export function handleDestinationsSetEncrypt(
244
- path: string,
245
- value: string,
246
- ): void {
247
- const normalized = value.toLowerCase();
248
- if (normalized !== "true" && normalized !== "false") {
249
- log.error(
250
- `Invalid encrypt value "${value}". Must be "true" or "false". ` +
251
- `Run 'vellum backup destinations set-encrypt --help' for usage.`,
252
- );
253
- process.exitCode = 1;
254
- return;
255
- }
256
- const encrypt = normalized === "true";
257
-
258
- const { raw, destinations } = loadDestinationsForMutation();
259
- const idx = destinations.findIndex((d) => d.path === path);
260
- if (idx === -1) {
261
- log.error(
262
- `Destination "${path}" not found. Run 'vellum backup destinations list' to see configured destinations.`,
263
- );
264
- process.exitCode = 1;
265
- return;
266
- }
267
-
268
- const next = destinations.map((d, i) => (i === idx ? { ...d, encrypt } : d));
269
- setNestedValue(raw, "backup.offsite.destinations", next);
270
- saveRawConfig(raw);
271
- log.info(`Set ${path} encrypt=${encrypt ? "true" : "false"}`);
272
- }
273
-
274
- // ---------------------------------------------------------------------------
275
- // status
276
- // ---------------------------------------------------------------------------
277
-
278
- export async function handleStatus(): Promise<void> {
279
- const cfg = getConfig().backup;
280
-
281
- log.info(`Automatic backups: ${cfg.enabled ? "enabled" : "disabled"}`);
282
- log.info(`Interval: every ${cfg.intervalHours}h`);
283
- log.info(`Retention: ${cfg.retention} snapshots per destination`);
284
-
285
- // Last / next run — both gated on a valid checkpoint. The daemon records
286
- // `backup:last_run_at` as a unix-millis string.
287
- const lastRunRaw = getMemoryCheckpoint("backup:last_run_at");
288
- const lastRunMs = lastRunRaw ? Number.parseInt(lastRunRaw, 10) : NaN;
289
- const now = Date.now();
290
- if (!Number.isNaN(lastRunMs)) {
291
- const lastRunDate = new Date(lastRunMs);
292
- log.info(
293
- `Last run: ${formatDate(lastRunDate)} (${formatDurationShort(now - lastRunMs)} ago)`,
294
- );
295
- if (cfg.enabled) {
296
- const intervalMs = cfg.intervalHours * 3600 * 1000;
297
- const nextMs = lastRunMs + intervalMs;
298
- const delta = nextMs - now;
299
- if (delta <= 0) {
300
- log.info(`Next run: due now`);
301
- } else {
302
- log.info(`Next run: in ${formatDurationShort(delta)}`);
303
- }
304
- }
305
- } else {
306
- log.info(`Last run: never`);
307
- if (cfg.enabled) {
308
- log.info(`Next run: on next tick`);
309
- }
310
- }
311
-
312
- // Local directory line — include snapshot count so users can confirm the
313
- // pool size matches retention.
314
- const localDir = getLocalBackupsDir(cfg.localDirectory);
315
- const localSnapshots = await listSnapshotsInDir(localDir);
316
- log.info(
317
- `Local directory: ${localDir} (${localSnapshots.length} snapshots)`,
318
- );
319
-
320
- // Offsite destinations — resolve the iCloud default, probe reachability
321
- // for each, and report snapshot counts.
322
- log.info(`Offsite:`);
323
- if (!cfg.offsite.enabled) {
324
- log.info(` (disabled)`);
325
- return;
326
- }
327
- const destinations = resolveOffsiteDestinations(cfg.offsite.destinations);
328
- if (destinations.length === 0) {
329
- log.info(` (no destinations configured)`);
330
- return;
331
- }
332
- for (const dest of destinations) {
333
- const reachable = await isDestinationReachable(dest.path);
334
- const tag = reachable ? "[OK]" : "[unreachable]";
335
- const enc = dest.encrypt ? "encrypted" : "plaintext";
336
- const snapshots = reachable ? await listSnapshotsInDir(dest.path) : [];
337
- const suffix = reachable ? "" : " -- parent directory not reachable";
338
- log.info(
339
- ` ${tag} ${dest.path} (${enc}, ${snapshots.length} snapshots)${suffix}`,
340
- );
341
- }
342
- }
343
-
344
- // ---------------------------------------------------------------------------
345
- // list
346
- // ---------------------------------------------------------------------------
347
-
348
- /** Print a snapshot table for a group of entries. */
349
- function printSnapshotGroup(heading: string, entries: SnapshotEntry[]): void {
350
- log.info(heading);
351
- if (entries.length === 0) {
352
- log.info(" (none)");
353
- return;
354
- }
355
- const tsW = 19;
356
- const sizeW = 10;
357
- const encW = 9;
358
- log.info(
359
- " " +
360
- "Timestamp".padEnd(tsW) +
361
- " " +
362
- "Size".padEnd(sizeW) +
363
- " " +
364
- "Encrypted".padEnd(encW) +
365
- " " +
366
- "Filename",
367
- );
368
- for (const e of entries) {
369
- log.info(
370
- " " +
371
- formatDate(e.createdAt).padEnd(tsW) +
372
- " " +
373
- formatBytes(e.sizeBytes).padEnd(sizeW) +
374
- " " +
375
- (e.encrypted ? "yes" : "no").padEnd(encW) +
376
- " " +
377
- e.filename,
378
- );
379
- }
380
- }
381
-
382
- export async function handleList(): Promise<void> {
383
- const cfg = getConfig().backup;
384
- const localDir = getLocalBackupsDir(cfg.localDirectory);
385
- const localSnapshots = await listSnapshotsInDir(localDir);
386
- printSnapshotGroup(`Local: ${localDir}`, localSnapshots);
387
-
388
- if (!cfg.offsite.enabled) return;
389
- const destinations = resolveOffsiteDestinations(cfg.offsite.destinations);
390
- for (const dest of destinations) {
391
- const entries = await listSnapshotsInDir(dest.path);
392
- const tag = dest.encrypt ? "encrypted" : "plaintext";
393
- log.info("");
394
- printSnapshotGroup(`Offsite: ${dest.path} (${tag})`, entries);
395
- }
396
- }
397
-
398
- // ---------------------------------------------------------------------------
399
- // ---------------------------------------------------------------------------
400
-
401
-
402
-
403
56
  // ---------------------------------------------------------------------------
404
57
  // Command wiring
405
58
  // ---------------------------------------------------------------------------
406
59
 
407
60
  export function registerBackupCommand(program: Command): void {
408
- const backup = program
409
- .command("backup")
410
- .description(
411
- "Manage automated backup configuration and list snapshots",
412
- );
413
-
414
- backup.addHelpText(
415
- "after",
416
- `
61
+ registerCommand(program, {
62
+ name: "backup",
63
+ transport: "ipc",
64
+ description: "Manage automated backup configuration and list snapshots",
65
+ build: (backup) => {
66
+ backup.addHelpText(
67
+ "after",
68
+ `
417
69
  Backups capture a snapshot of the assistant workspace (config, conversations,
418
70
  trust rules, hooks, the SQLite database) as a .vbundle file. Credentials are
419
71
  NOT included — they live in the OS keychain / CES and users re-authenticate
@@ -427,71 +79,105 @@ plaintext — plaintext only makes sense when the user owns physical access to
427
79
  the medium (e.g. an external SSD).
428
80
 
429
81
  Examples:
430
- $ vellum backup enable --interval 6 --retention 3
431
- $ vellum backup destinations add /Volumes/BackupSSD/vellum --plaintext
432
- $ vellum backup status
433
- $ vellum backup list`,
434
- );
82
+ $ assistant backup enable --interval 6 --retention 3
83
+ $ assistant backup destinations add /Volumes/BackupSSD/vellum --plaintext
84
+ $ assistant backup status
85
+ $ assistant backup list`,
86
+ );
435
87
 
436
- backup
437
- .command("enable")
438
- .description("Enable automated backups")
439
- .option(
440
- "--interval <hours>",
441
- "Hours between automated backups (1-168). Defaults to 6.",
442
- )
443
- .option(
444
- "--retention <n>",
445
- "Snapshots to retain per destination (1-100). Defaults to 3.",
446
- )
447
- .option(
448
- "--no-offsite",
449
- "Disable offsite backup (local only). Does not touch the destinations list.",
450
- )
451
- .addHelpText(
452
- "after",
453
- `
88
+ backup
89
+ .command("enable")
90
+ .description("Enable automated backups")
91
+ .option(
92
+ "--interval <hours>",
93
+ "Hours between automated backups (1-168). Defaults to 6.",
94
+ )
95
+ .option(
96
+ "--retention <n>",
97
+ "Snapshots to retain per destination (1-100). Defaults to 3.",
98
+ )
99
+ .option(
100
+ "--no-offsite",
101
+ "Disable offsite backup (local only). Does not touch the destinations list.",
102
+ )
103
+ .addHelpText(
104
+ "after",
105
+ `
454
106
  Sets backup.enabled = true in config.json. Optionally overrides intervalHours,
455
107
  retention, and the offsite.enabled flag. Does NOT modify
456
- backup.offsite.destinations — use 'vellum backup destinations add/remove' to
108
+ backup.offsite.destinations — use 'assistant backup destinations add/remove' to
457
109
  manage those.
458
110
 
459
111
  Examples:
460
- $ vellum backup enable
461
- $ vellum backup enable --interval 12 --retention 14
462
- $ vellum backup enable --no-offsite`,
463
- )
464
- .action((opts: EnableOptions) => {
465
- handleEnable(opts);
466
- });
467
-
468
- backup
469
- .command("disable")
470
- .description("Disable automated backups")
471
- .addHelpText(
472
- "after",
473
- `
112
+ $ assistant backup enable
113
+ $ assistant backup enable --interval 12 --retention 14
114
+ $ assistant backup enable --no-offsite`,
115
+ )
116
+ .action(
117
+ async (
118
+ opts: { interval?: string; retention?: string; offsite?: boolean },
119
+ cmd: Command,
120
+ ) => {
121
+ const r = await cliIpcCall("backup_enable", {
122
+ body: {
123
+ ...(opts.interval !== undefined && {
124
+ intervalHours: Number.parseInt(opts.interval, 10),
125
+ }),
126
+ ...(opts.retention !== undefined && {
127
+ retention: Number.parseInt(opts.retention, 10),
128
+ }),
129
+ ...(opts.offsite === false && { offsiteEnabled: false }),
130
+ },
131
+ });
132
+ if (!r.ok)
133
+ return exitFromIpcResult(
134
+ { ok: false, error: r.error, statusCode: r.statusCode },
135
+ cmd,
136
+ );
137
+ const cfg = r.result as {
138
+ intervalHours: number;
139
+ retention: number;
140
+ offsite: { enabled: boolean };
141
+ };
142
+ log.info(
143
+ `Automatic backups enabled (interval=${cfg.intervalHours}h, retention=${cfg.retention}, offsite=${cfg.offsite.enabled ? "on" : "off"})`,
144
+ );
145
+ },
146
+ );
147
+
148
+ backup
149
+ .command("disable")
150
+ .description("Disable automated backups")
151
+ .addHelpText(
152
+ "after",
153
+ `
474
154
  Sets backup.enabled = false in config.json. Existing snapshots are untouched;
475
155
  only the automated worker stops creating new ones.
476
156
 
477
157
  Examples:
478
- $ vellum backup disable`,
479
- )
480
- .action(() => {
481
- handleDisable();
482
- });
483
-
484
- // ---------------------------------------------------------------------------
485
- // destinations — subgroup
486
- // ---------------------------------------------------------------------------
487
-
488
- const destinations = backup
489
- .command("destinations")
490
- .description("Manage offsite backup destinations");
491
-
492
- destinations.addHelpText(
493
- "after",
494
- `
158
+ $ assistant backup disable`,
159
+ )
160
+ .action(async (_opts: unknown, cmd: Command) => {
161
+ const r = await cliIpcCall("backup_disable");
162
+ if (!r.ok)
163
+ return exitFromIpcResult(
164
+ { ok: false, error: r.error, statusCode: r.statusCode },
165
+ cmd,
166
+ );
167
+ log.info("Automatic backups disabled");
168
+ });
169
+
170
+ // -----------------------------------------------------------------------
171
+ // destinations — subgroup
172
+ // -----------------------------------------------------------------------
173
+
174
+ const destinations = backup
175
+ .command("destinations")
176
+ .description("Manage offsite backup destinations");
177
+
178
+ destinations.addHelpText(
179
+ "after",
180
+ `
495
181
  Offsite destinations are absolute paths the backup worker writes a copy of
496
182
  each snapshot to after the local write succeeds. The default destination is
497
183
  the iCloud Drive VellumAssistant folder, and it is used implicitly until an
@@ -504,39 +190,57 @@ are written as .vbundle.enc (AES-256-GCM). When false, snapshots are copied
504
190
  as plaintext .vbundle — only use this for media you control physically.
505
191
 
506
192
  Examples:
507
- $ vellum backup destinations list
508
- $ vellum backup destinations add /Volumes/BackupSSD/vellum --plaintext
509
- $ vellum backup destinations remove /Volumes/BackupSSD/vellum
510
- $ vellum backup destinations set-encrypt /Volumes/BackupSSD/vellum false`,
511
- );
193
+ $ assistant backup destinations list
194
+ $ assistant backup destinations add /Volumes/BackupSSD/vellum --plaintext
195
+ $ assistant backup destinations remove /Volumes/BackupSSD/vellum
196
+ $ assistant backup destinations set-encrypt /Volumes/BackupSSD/vellum false`,
197
+ );
512
198
 
513
- destinations
514
- .command("list")
515
- .description("List configured offsite destinations")
516
- .addHelpText(
517
- "after",
518
- `
199
+ destinations
200
+ .command("list")
201
+ .description("List configured offsite destinations")
202
+ .addHelpText(
203
+ "after",
204
+ `
519
205
  Resolves the current destinations array (materializing the iCloud default if
520
206
  no explicit array is configured) and prints a table with the path and
521
207
  encryption flag per row.
522
208
 
523
209
  Examples:
524
- $ vellum backup destinations list`,
525
- )
526
- .action(async () => {
527
- await handleDestinationsList();
528
- });
529
-
530
- destinations
531
- .command("add <path>")
532
- .description("Add an offsite backup destination")
533
- .option(
534
- "--plaintext",
535
- "Write snapshots as plaintext .vbundle (default is AES-256-GCM encrypted .vbundle.enc)",
536
- )
537
- .addHelpText(
538
- "after",
539
- `
210
+ $ assistant backup destinations list`,
211
+ )
212
+ .action(async (_opts: unknown, cmd: Command) => {
213
+ const r = await cliIpcCall<{
214
+ destinations: Array<{ path: string; encrypt: boolean }>;
215
+ }>("backup_destinations_list");
216
+ if (!r.ok)
217
+ return exitFromIpcResult(
218
+ { ok: false, error: r.error, statusCode: r.statusCode },
219
+ cmd,
220
+ );
221
+ const { destinations: dests } = r.result!;
222
+ if (dests.length === 0) {
223
+ log.info("No offsite destinations configured");
224
+ return;
225
+ }
226
+ const pathW = Math.max(4, ...dests.map((d) => d.path.length));
227
+ log.info("Path".padEnd(pathW) + " " + "Encrypted");
228
+ log.info("-".repeat(pathW + 2 + 9));
229
+ for (const d of dests) {
230
+ log.info(d.path.padEnd(pathW) + " " + (d.encrypt ? "yes" : "no"));
231
+ }
232
+ });
233
+
234
+ destinations
235
+ .command("add <path>")
236
+ .description("Add an offsite backup destination")
237
+ .option(
238
+ "--plaintext",
239
+ "Write snapshots as plaintext .vbundle (default is AES-256-GCM encrypted .vbundle.enc)",
240
+ )
241
+ .addHelpText(
242
+ "after",
243
+ `
540
244
  Arguments:
541
245
  path Absolute path to the destination directory. Must be on a mount the
542
246
  caller controls; the backup worker writes files inside this
@@ -547,64 +251,107 @@ the iCloud default is materialized first so the new entry appends to a
547
251
  2-element array rather than replacing the default.
548
252
 
549
253
  Examples:
550
- $ vellum backup destinations add /Volumes/BackupSSD/vellum --plaintext
551
- $ vellum backup destinations add ~/Dropbox/VellumAssistant/backups`,
552
- )
553
- .action((path: string, opts: DestinationAddOptions) => {
554
- handleDestinationsAdd(path, opts);
555
- });
556
-
557
- destinations
558
- .command("remove <path>")
559
- .description("Remove an offsite backup destination by path")
560
- .addHelpText(
561
- "after",
562
- `
254
+ $ assistant backup destinations add /Volumes/BackupSSD/vellum --plaintext
255
+ $ assistant backup destinations add ~/Dropbox/VellumAssistant/backups`,
256
+ )
257
+ .action(
258
+ async (path: string, opts: { plaintext?: boolean }, cmd: Command) => {
259
+ const r = await cliIpcCall("backup_destinations_add", {
260
+ body: {
261
+ path,
262
+ encrypt: !opts.plaintext,
263
+ },
264
+ });
265
+ if (!r.ok)
266
+ return exitFromIpcResult(
267
+ { ok: false, error: r.error, statusCode: r.statusCode },
268
+ cmd,
269
+ );
270
+ log.info(
271
+ `Added destination ${path} (${opts.plaintext ? "plaintext" : "encrypted"})`,
272
+ );
273
+ },
274
+ );
275
+
276
+ destinations
277
+ .command("remove <path>")
278
+ .description("Remove an offsite backup destination by path")
279
+ .addHelpText(
280
+ "after",
281
+ `
563
282
  Arguments:
564
283
  path Exact path match of the destination to remove. Run
565
- 'vellum backup destinations list' to see configured paths.
284
+ 'assistant backup destinations list' to see configured paths.
566
285
 
567
286
  Errors if no destination with the given path exists.
568
287
 
569
288
  Examples:
570
- $ vellum backup destinations remove /Volumes/BackupSSD/vellum`,
571
- )
572
- .action((path: string) => {
573
- handleDestinationsRemove(path);
574
- });
575
-
576
- destinations
577
- .command("set-encrypt <path> <value>")
578
- .description("Toggle encryption for an existing destination")
579
- .addHelpText(
580
- "after",
581
- `
289
+ $ assistant backup destinations remove /Volumes/BackupSSD/vellum`,
290
+ )
291
+ .action(async (path: string, _opts: unknown, cmd: Command) => {
292
+ const r = await cliIpcCall("backup_destinations_remove", { body: { path } });
293
+ if (!r.ok)
294
+ return exitFromIpcResult(
295
+ { ok: false, error: r.error, statusCode: r.statusCode },
296
+ cmd,
297
+ );
298
+ log.info(`Removed destination ${path}`);
299
+ });
300
+
301
+ destinations
302
+ .command("set-encrypt <path> <value>")
303
+ .description("Toggle encryption for an existing destination")
304
+ .addHelpText(
305
+ "after",
306
+ `
582
307
  Arguments:
583
308
  path Exact path match of an existing destination. Run
584
- 'vellum backup destinations list' to see configured paths.
309
+ 'assistant backup destinations list' to see configured paths.
585
310
  value "true" to encrypt, "false" for plaintext writes.
586
311
 
587
312
  Errors if no destination with the given path exists. Existing snapshot files
588
313
  are not modified; only future writes honour the new setting.
589
314
 
590
315
  Examples:
591
- $ vellum backup destinations set-encrypt /Volumes/BackupSSD/vellum false
592
- $ vellum backup destinations set-encrypt /Volumes/BackupSSD/vellum true`,
593
- )
594
- .action((path: string, value: string) => {
595
- handleDestinationsSetEncrypt(path, value);
596
- });
597
-
598
- // ---------------------------------------------------------------------------
599
- // status / list
600
- // ---------------------------------------------------------------------------
601
-
602
- backup
603
- .command("status")
604
- .description("Show backup status and next-run timing")
605
- .addHelpText(
606
- "after",
607
- `
316
+ $ assistant backup destinations set-encrypt /Volumes/BackupSSD/vellum false
317
+ $ assistant backup destinations set-encrypt /Volumes/BackupSSD/vellum true`,
318
+ )
319
+ .action(
320
+ async (path: string, value: string, _opts: unknown, cmd: Command) => {
321
+ const normalized = value.toLowerCase();
322
+ if (normalized !== "true" && normalized !== "false") {
323
+ log.error(
324
+ `Invalid encrypt value "${value}". Must be "true" or "false". ` +
325
+ `Run 'assistant backup destinations set-encrypt --help' for usage.`,
326
+ );
327
+ process.exitCode = 1;
328
+ return;
329
+ }
330
+ const r = await cliIpcCall("backup_destinations_set_encrypt", {
331
+ body: {
332
+ path,
333
+ encrypt: normalized === "true",
334
+ },
335
+ });
336
+ if (!r.ok)
337
+ return exitFromIpcResult(
338
+ { ok: false, error: r.error, statusCode: r.statusCode },
339
+ cmd,
340
+ );
341
+ log.info(`Set ${path} encrypt=${normalized}`);
342
+ },
343
+ );
344
+
345
+ // -----------------------------------------------------------------------
346
+ // status / list
347
+ // -----------------------------------------------------------------------
348
+
349
+ backup
350
+ .command("status")
351
+ .description("Show backup status and next-run timing")
352
+ .addHelpText(
353
+ "after",
354
+ `
608
355
  Reports enabled/disabled state, interval and retention, last-run and next-run
609
356
  timing (from the backup:last_run_at memory checkpoint), and a per-destination
610
357
  reachability probe. Unreachable destinations (parent directory missing, e.g.
@@ -612,27 +359,184 @@ iCloud Drive not enabled or external volume unplugged) are flagged
612
359
  [unreachable] and skipped by the worker.
613
360
 
614
361
  Examples:
615
- $ vellum backup status`,
616
- )
617
- .action(async () => {
618
- await handleStatus();
619
- });
620
-
621
- backup
622
- .command("list")
623
- .description("List all backup snapshots, grouped by destination")
624
- .addHelpText(
625
- "after",
626
- `
362
+ $ assistant backup status`,
363
+ )
364
+ .action(async (_opts: unknown, cmd: Command) => {
365
+ const r = await cliIpcCall<{
366
+ enabled: boolean;
367
+ intervalHours: number;
368
+ retention: number;
369
+ lastRunAt: string | null;
370
+ nextRunAt: string | null;
371
+ localDir: string;
372
+ localSnapshotCount: number;
373
+ offsiteEnabled: boolean;
374
+ offsite: Array<{
375
+ path: string;
376
+ encrypt: boolean;
377
+ reachable: boolean;
378
+ snapshotCount: number;
379
+ }>;
380
+ }>("backup_status");
381
+ if (!r.ok)
382
+ return exitFromIpcResult(
383
+ { ok: false, error: r.error, statusCode: r.statusCode },
384
+ cmd,
385
+ );
386
+ const s = r.result!;
387
+ const now = Date.now();
388
+
389
+ log.info(`Automatic backups: ${s.enabled ? "enabled" : "disabled"}`);
390
+ log.info(`Interval: every ${s.intervalHours}h`);
391
+ log.info(
392
+ `Retention: ${s.retention} snapshots per destination`,
393
+ );
394
+
395
+ if (s.lastRunAt) {
396
+ const lastRunMs = new Date(s.lastRunAt).getTime();
397
+ log.info(
398
+ `Last run: ${formatDate(new Date(s.lastRunAt))} (${formatDurationShort(now - lastRunMs)} ago)`,
399
+ );
400
+ if (s.enabled && s.nextRunAt) {
401
+ const nextMs = new Date(s.nextRunAt).getTime();
402
+ const delta = nextMs - now;
403
+ if (delta <= 0) {
404
+ log.info(`Next run: due now`);
405
+ } else {
406
+ log.info(`Next run: in ${formatDurationShort(delta)}`);
407
+ }
408
+ }
409
+ } else {
410
+ log.info(`Last run: never`);
411
+ if (s.enabled) {
412
+ log.info(`Next run: on next tick`);
413
+ }
414
+ }
415
+
416
+ log.info(
417
+ `Local directory: ${s.localDir} (${s.localSnapshotCount} snapshots)`,
418
+ );
419
+
420
+ log.info(
421
+ `Offsite: ${s.offsiteEnabled ? "enabled" : "disabled"}`,
422
+ );
423
+ if (!s.offsiteEnabled) {
424
+ return;
425
+ }
426
+ if (s.offsite.length === 0) {
427
+ log.info(` (no destinations configured)`);
428
+ return;
429
+ }
430
+ for (const dest of s.offsite) {
431
+ const tag = dest.reachable ? "[OK]" : "[unreachable]";
432
+ const enc = dest.encrypt ? "encrypted" : "plaintext";
433
+ const suffix = dest.reachable
434
+ ? ""
435
+ : " -- parent directory not reachable";
436
+ log.info(
437
+ ` ${tag} ${dest.path} (${enc}, ${dest.snapshotCount} snapshots)${suffix}`,
438
+ );
439
+ }
440
+ });
441
+
442
+ backup
443
+ .command("list")
444
+ .description("List all backup snapshots, grouped by destination")
445
+ .addHelpText(
446
+ "after",
447
+ `
627
448
  Prints a per-destination table of snapshots with timestamp, size, and
628
449
  encryption flag. Local destination is listed first, followed by each offsite
629
450
  destination. Unreachable destinations are listed with an empty snapshot set.
630
451
 
631
452
  Examples:
632
- $ vellum backup list`,
633
- )
634
- .action(async () => {
635
- await handleList();
636
- });
453
+ $ assistant backup list`,
454
+ )
455
+ .action(async (_opts: unknown, cmd: Command) => {
456
+ const r = await cliIpcCall<{
457
+ local: Array<{
458
+ filename: string;
459
+ createdAt: string;
460
+ sizeBytes: number;
461
+ encrypted: boolean;
462
+ }>;
463
+ offsite: Array<{
464
+ destination: { path: string; encrypt: boolean };
465
+ snapshots: Array<{
466
+ filename: string;
467
+ createdAt: string;
468
+ sizeBytes: number;
469
+ encrypted: boolean;
470
+ }>;
471
+ reachable: boolean;
472
+ }>;
473
+ offsiteEnabled: boolean;
474
+ nextRunAt: string | null;
475
+ }>("backups_list");
476
+ if (!r.ok)
477
+ return exitFromIpcResult(
478
+ { ok: false, error: r.error, statusCode: r.statusCode },
479
+ cmd,
480
+ );
481
+ const data = r.result!;
482
+
483
+ printSnapshotGroup(`Local:`, data.local);
484
+
485
+ if (!data.offsiteEnabled) return;
486
+ for (const dest of data.offsite) {
487
+ const tag = dest.destination.encrypt ? "encrypted" : "plaintext";
488
+ log.info("");
489
+ printSnapshotGroup(
490
+ `Offsite: ${dest.destination.path} (${tag})`,
491
+ dest.snapshots,
492
+ );
493
+ }
494
+ });
495
+ },
496
+ });
497
+ }
637
498
 
499
+ // ---------------------------------------------------------------------------
500
+ // Snapshot table printer
501
+ // ---------------------------------------------------------------------------
502
+
503
+ function printSnapshotGroup(
504
+ heading: string,
505
+ entries: Array<{
506
+ filename: string;
507
+ createdAt: string;
508
+ sizeBytes: number;
509
+ encrypted: boolean;
510
+ }>,
511
+ ): void {
512
+ log.info(heading);
513
+ if (entries.length === 0) {
514
+ log.info(" (none)");
515
+ return;
516
+ }
517
+ const tsW = 19;
518
+ const sizeW = 10;
519
+ const encW = 9;
520
+ log.info(
521
+ " " +
522
+ "Timestamp".padEnd(tsW) +
523
+ " " +
524
+ "Size".padEnd(sizeW) +
525
+ " " +
526
+ "Encrypted".padEnd(encW) +
527
+ " " +
528
+ "Filename",
529
+ );
530
+ for (const e of entries) {
531
+ log.info(
532
+ " " +
533
+ formatDate(new Date(e.createdAt)).padEnd(tsW) +
534
+ " " +
535
+ formatBytes(e.sizeBytes).padEnd(sizeW) +
536
+ " " +
537
+ (e.encrypted ? "yes" : "no").padEnd(encW) +
538
+ " " +
539
+ e.filename,
540
+ );
541
+ }
638
542
  }