@vellumai/assistant 0.8.0 → 0.8.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (692) hide show
  1. package/AGENTS.md +11 -0
  2. package/Dockerfile +5 -4
  3. package/README.md +2 -2
  4. package/docker-entrypoint.sh +16 -0
  5. package/eslint-rules/__tests__/cli-no-daemon-internals.test.ts +420 -0
  6. package/eslint-rules/cli-no-daemon-internals.js +283 -0
  7. package/eslint.config.mjs +12 -0
  8. package/knip.json +2 -1
  9. package/node_modules/@vellumai/skill-host-contracts/src/client.ts +10 -1
  10. package/openapi.yaml +4847 -1698
  11. package/package.json +3 -1
  12. package/scripts/generate-openapi.ts +52 -4
  13. package/scripts/sync-llm-catalog.ts +165 -0
  14. package/scripts/sync-web-search-catalog.ts +107 -0
  15. package/src/__tests__/actor-trust-resolver-address-fallback.test.ts +169 -0
  16. package/src/__tests__/agent-loop-override-profile.test.ts +26 -1
  17. package/src/__tests__/anthropic-provider.test.ts +92 -2
  18. package/src/__tests__/app-control-flow.test.ts +7 -0
  19. package/src/__tests__/assistant-events-sse-shed.test.ts +232 -0
  20. package/src/__tests__/avatar-identity-sync.test.ts +87 -0
  21. package/src/__tests__/background-workers-disk-pressure.test.ts +11 -22
  22. package/src/__tests__/btw-routes.test.ts +1 -0
  23. package/src/__tests__/call-site-routing-provider.test.ts +172 -45
  24. package/src/__tests__/cancel-resolves-conversation-key.test.ts +44 -3
  25. package/src/__tests__/channel-policy.test.ts +12 -0
  26. package/src/__tests__/checker.test.ts +89 -0
  27. package/src/__tests__/cli-memory-v2-reembed-skills.test.ts +35 -7
  28. package/src/__tests__/compact-event-conversation-id-guard.test.ts +33 -5
  29. package/src/__tests__/compaction-strip-metadata-clear.test.ts +26 -1
  30. package/src/__tests__/config-loader-backfill.test.ts +526 -102
  31. package/src/__tests__/config-loader-corrupt.test.ts +68 -0
  32. package/src/__tests__/config-loader-platform-defaults.test.ts +77 -23
  33. package/src/__tests__/config-schema-cmd.test.ts +63 -29
  34. package/src/__tests__/config-schema.test.ts +14 -3
  35. package/src/__tests__/config-set-platform-guard.test.ts +75 -152
  36. package/src/__tests__/config-set-route.test.ts +198 -0
  37. package/src/__tests__/config-watcher.test.ts +6 -0
  38. package/src/__tests__/contacts-tools.test.ts +51 -199
  39. package/src/__tests__/context-search-agent-protocol.test.ts +21 -2
  40. package/src/__tests__/context-search-agent-runner.test.ts +22 -138
  41. package/src/__tests__/context-search-conversations-source.test.ts +42 -16
  42. package/src/__tests__/context-search-fanout.test.ts +20 -157
  43. package/src/__tests__/context-search-memory-v2-source.test.ts +3 -3
  44. package/src/__tests__/context-search-types.test.ts +7 -2
  45. package/src/__tests__/context-window-manager.test.ts +389 -1
  46. package/src/__tests__/conversation-agent-loop-overflow.test.ts +1 -0
  47. package/src/__tests__/conversation-crud-inference-profile.test.ts +100 -0
  48. package/src/__tests__/conversation-error.test.ts +38 -0
  49. package/src/__tests__/conversation-fork-crud.test.ts +241 -1
  50. package/src/__tests__/conversation-inference-profile-route.test.ts +14 -14
  51. package/src/__tests__/conversation-init.benchmark.test.ts +1 -0
  52. package/src/__tests__/conversation-lifecycle.test.ts +124 -0
  53. package/src/__tests__/conversation-process-app-control-preactivation.test.ts +100 -1
  54. package/src/__tests__/conversation-process-callsite.test.ts +21 -1
  55. package/src/__tests__/conversation-runtime-assembly.test.ts +4 -4
  56. package/src/__tests__/conversation-slash-commands.test.ts +194 -2
  57. package/src/__tests__/conversation-surfaces-app-control.test.ts +323 -3
  58. package/src/__tests__/credential-security-invariants.test.ts +5 -6
  59. package/src/__tests__/daemon-credential-client.test.ts +56 -1
  60. package/src/__tests__/db-activation-state-fk-cascade.test.ts +132 -0
  61. package/src/__tests__/db-conversation-inference-profile-migration.test.ts +37 -0
  62. package/src/__tests__/db-memory-graph-event-date-repair.test.ts +43 -20
  63. package/src/__tests__/db-proxy-transaction.test.ts +206 -0
  64. package/src/__tests__/external-plugin-loader.test.ts +458 -0
  65. package/src/__tests__/filing-service.test.ts +23 -3
  66. package/src/__tests__/fixtures/mock-chrome-extension.ts +5 -0
  67. package/src/__tests__/gateway-only-guard.test.ts +0 -1
  68. package/src/__tests__/graph-extraction-event-date.test.ts +34 -0
  69. package/src/__tests__/handlers-skills-memory-v2-reseed.test.ts +0 -8
  70. package/src/__tests__/heartbeat-disk-pressure.test.ts +21 -8
  71. package/src/__tests__/heartbeat-service.test.ts +50 -233
  72. package/src/__tests__/history-repair.test.ts +89 -0
  73. package/src/__tests__/host-app-control-proxy.test.ts +109 -1
  74. package/src/__tests__/host-app-control-routes.test.ts +247 -1
  75. package/src/__tests__/host-browser-proxy.test.ts +416 -20
  76. package/src/__tests__/host-browser-routes.test.ts +325 -33
  77. package/src/__tests__/host-proxy-preactivation.test.ts +211 -0
  78. package/src/__tests__/inference-no-mode-boot-e2e.test.ts +246 -0
  79. package/src/__tests__/inference-profile-reaper.test.ts +154 -0
  80. package/src/__tests__/inference-profile-session-handler.test.ts +398 -0
  81. package/src/__tests__/inference-profile-session-ipc.test.ts +236 -0
  82. package/src/__tests__/inline-skill-load-permissions.test.ts +6 -1
  83. package/src/__tests__/install-skill-routing.test.ts +2 -2
  84. package/src/__tests__/lifecycle-memory-v2-seed.test.ts +15 -0
  85. package/src/__tests__/llm-callsite-catalog.test.ts +20 -1
  86. package/src/__tests__/llm-catalog-parity.test.ts +146 -0
  87. package/src/__tests__/llm-request-log-source-clickhouse.test.ts +188 -0
  88. package/src/__tests__/llm-request-log-source-factory.test.ts +124 -0
  89. package/src/__tests__/llm-resolver.test.ts +46 -0
  90. package/src/__tests__/managed-profile-guard.test.ts +131 -2
  91. package/src/__tests__/mcp-auth-routes.test.ts +1 -0
  92. package/src/__tests__/mcp-cli.test.ts +182 -220
  93. package/src/__tests__/mcp-health-check.test.ts +56 -27
  94. package/src/__tests__/memory-jobs-worker-lanes.test.ts +18 -11
  95. package/src/__tests__/message-complete-display-id.test.ts +175 -0
  96. package/src/__tests__/notification-platform-adapter.test.ts +229 -0
  97. package/src/__tests__/oauth-cli.test.ts +38 -2009
  98. package/src/__tests__/oauth-commands-routes.test.ts +711 -0
  99. package/src/__tests__/oauth-connect-routes.test.ts +174 -11
  100. package/src/__tests__/oauth-providers-routes.test.ts +14 -10
  101. package/src/__tests__/openai-responses-cutover-guard.test.ts +33 -12
  102. package/src/__tests__/openai-responses-provider.test.ts +17 -0
  103. package/src/__tests__/plugin-bootstrap.test.ts +31 -2
  104. package/src/__tests__/plugin-route-contribution.test.ts +31 -3
  105. package/src/__tests__/plugin-tool-contribution.test.ts +31 -3
  106. package/src/__tests__/plugin-types.test.ts +13 -11
  107. package/src/__tests__/process-message-background-slack.test.ts +46 -0
  108. package/src/__tests__/profile-entry-status.test.ts +43 -0
  109. package/src/__tests__/provider-managed-proxy-integration.test.ts +12 -4
  110. package/src/__tests__/provider-registry-ollama.test.ts +12 -4
  111. package/src/__tests__/provider-send-message-override-profile.test.ts +10 -4
  112. package/src/__tests__/relay-server.test.ts +118 -0
  113. package/src/__tests__/retry-thinking-tool-choice.test.ts +15 -0
  114. package/src/__tests__/schedule-retry.test.ts +56 -4
  115. package/src/__tests__/schedule-routes.test.ts +104 -0
  116. package/src/__tests__/scheduler-disk-pressure.test.ts +0 -4
  117. package/src/__tests__/scheduler-recurrence.test.ts +87 -34
  118. package/src/__tests__/scheduler-reuse-conversation.test.ts +161 -5
  119. package/src/__tests__/scheduler-wake.test.ts +0 -63
  120. package/src/__tests__/secret-allowlist.test.ts +1 -0
  121. package/src/__tests__/secret-routes-managed-proxy.test.ts +12 -4
  122. package/src/__tests__/shell-credential-ref.test.ts +95 -3
  123. package/src/__tests__/shell-tool-proxy-mode.test.ts +14 -0
  124. package/src/__tests__/skill-load-feature-flag.test.ts +1 -0
  125. package/src/__tests__/skill-load-tool.test.ts +2 -4
  126. package/src/__tests__/subagent-call-site-routing.test.ts +78 -16
  127. package/src/__tests__/suggestion-routes.test.ts +3 -3
  128. package/src/__tests__/sync-message-contract.test.ts +63 -0
  129. package/src/__tests__/task-scheduler.test.ts +88 -23
  130. package/src/__tests__/update-bulletin-job.test.ts +96 -193
  131. package/src/__tests__/usage-cli.test.ts +11 -73
  132. package/src/__tests__/user-plugin-loader.test.ts +145 -0
  133. package/src/__tests__/vercel-config.test.ts +168 -0
  134. package/src/__tests__/web-search-catalog-parity.test.ts +86 -0
  135. package/src/__tests__/web-search.test.ts +303 -2
  136. package/src/__tests__/workspace-migration-039-drop-legacy-llm-keys.test.ts +1 -21
  137. package/src/__tests__/workspace-migration-057-repair-stale-gemini-model-ids.test.ts +58 -0
  138. package/src/__tests__/workspace-migration-069-seed-onboarding-threads.test.ts +53 -20
  139. package/src/__tests__/workspace-migration-072-seed-reply-suggestion-callsite.test.ts +191 -0
  140. package/src/__tests__/workspace-migration-076-drop-services-inference-mode.test.ts +211 -0
  141. package/src/__tests__/workspace-migration-077-seed-memory-router-callsite.test.ts +174 -0
  142. package/src/__tests__/workspace-migration-079-home-feed-notification-only.test.ts +323 -0
  143. package/src/__tests__/workspace-migration-080-restrict-vercel-api-token-metadata.test.ts +299 -0
  144. package/src/__tests__/workspace-migration-081-backfill-bash-allowed-tools.test.ts +410 -0
  145. package/src/__tests__/workspace-migration-082-backfill-managed-profile-labels.test.ts +268 -0
  146. package/src/__tests__/workspace-migration-unify-llm-callsite-configs.test.ts +3 -3
  147. package/src/__tests__/workspace-release-notes-feature-flag-guard.test.ts +115 -0
  148. package/src/acp/__tests__/helpers/which-stub.ts +4 -2
  149. package/src/acp/resolve-agent.test.ts +25 -0
  150. package/src/acp/resolve-agent.ts +13 -2
  151. package/src/acp/session-manager.ts +14 -0
  152. package/src/approvals/guardian-request-resolvers.ts +32 -87
  153. package/src/calls/relay-server.ts +35 -0
  154. package/src/calls/relay-setup-router.ts +36 -0
  155. package/src/calls/types.ts +1 -0
  156. package/src/calls/voice-session-bridge.ts +23 -4
  157. package/src/channels/config.ts +14 -1
  158. package/src/channels/types.ts +1 -0
  159. package/src/cli/AGENTS.md +164 -4
  160. package/src/cli/__tests__/notifications.test.ts +54 -0
  161. package/src/cli/commands/__tests__/avatar.test.ts +540 -0
  162. package/src/cli/commands/__tests__/backup.test.ts +236 -776
  163. package/src/cli/commands/__tests__/cache.test.ts +1 -1
  164. package/src/cli/commands/__tests__/changelog.test.ts +593 -0
  165. package/src/cli/commands/__tests__/channel-verification-sessions.test.ts +503 -0
  166. package/src/cli/commands/__tests__/conversations-import.test.ts +515 -0
  167. package/src/cli/commands/__tests__/domain-register.test.ts +140 -167
  168. package/src/cli/commands/__tests__/domain-status.test.ts +137 -76
  169. package/src/cli/commands/__tests__/email-attachment.test.ts +314 -337
  170. package/src/cli/commands/__tests__/email-core.test.ts +579 -0
  171. package/src/cli/commands/__tests__/image-generation.test.ts +87 -824
  172. package/src/cli/commands/__tests__/inference-send.test.ts +30 -266
  173. package/src/cli/commands/__tests__/inference-session.test.ts +423 -0
  174. package/src/cli/commands/__tests__/memory-v2.test.ts +81 -110
  175. package/src/cli/commands/__tests__/skills.test.ts +563 -0
  176. package/src/cli/commands/__tests__/status.test.ts +249 -0
  177. package/src/cli/commands/__tests__/stt.test.ts +320 -0
  178. package/src/cli/commands/__tests__/tts-synthesize.test.ts +4 -603
  179. package/src/cli/commands/__tests__/tts.test.ts +321 -0
  180. package/src/cli/commands/__tests__/webhooks.test.ts +86 -511
  181. package/src/cli/commands/attachment.ts +8 -3
  182. package/src/cli/commands/audit.ts +95 -64
  183. package/src/cli/commands/auth.ts +61 -58
  184. package/src/cli/commands/avatar.ts +276 -390
  185. package/src/cli/commands/backup.ts +409 -505
  186. package/src/cli/commands/bash.ts +9 -5
  187. package/src/cli/commands/browser.ts +28 -9
  188. package/src/cli/commands/cache.ts +9 -4
  189. package/src/cli/commands/changelog.ts +414 -0
  190. package/src/cli/commands/channel-verification-sessions.ts +238 -317
  191. package/src/cli/commands/clients.ts +8 -3
  192. package/src/cli/commands/completions.ts +9 -9
  193. package/src/cli/commands/config.ts +102 -72
  194. package/src/cli/commands/contacts.ts +575 -696
  195. package/src/cli/commands/conversations-defer.ts +17 -69
  196. package/src/cli/commands/conversations-import.ts +90 -253
  197. package/src/cli/commands/conversations.ts +346 -436
  198. package/src/cli/commands/credential-execution.ts +9 -6
  199. package/src/cli/commands/credentials.ts +456 -736
  200. package/src/cli/commands/domain.ts +128 -206
  201. package/src/cli/commands/email.ts +606 -794
  202. package/src/cli/commands/gateway.ts +8 -1
  203. package/src/cli/commands/image-generation.ts +157 -205
  204. package/src/cli/commands/inference-providers.ts +352 -0
  205. package/src/cli/commands/inference-session.ts +415 -0
  206. package/src/cli/commands/inference.ts +87 -65
  207. package/src/cli/commands/keys.ts +8 -3
  208. package/src/cli/commands/mcp.ts +103 -287
  209. package/src/cli/commands/memory-v2.ts +162 -516
  210. package/src/cli/commands/notifications.ts +33 -7
  211. package/src/cli/commands/oauth/apps.ts +292 -261
  212. package/src/cli/commands/oauth/connect.ts +176 -297
  213. package/src/cli/commands/oauth/disconnect.ts +16 -215
  214. package/src/cli/commands/oauth/index.ts +49 -45
  215. package/src/cli/commands/oauth/mode.ts +43 -199
  216. package/src/cli/commands/oauth/ping.ts +17 -125
  217. package/src/cli/commands/oauth/providers.ts +732 -921
  218. package/src/cli/commands/oauth/request.ts +60 -350
  219. package/src/cli/commands/oauth/shared.ts +11 -121
  220. package/src/cli/commands/oauth/status.ts +31 -121
  221. package/src/cli/commands/oauth/token.ts +13 -55
  222. package/src/cli/commands/pending.ts +19 -10
  223. package/src/cli/commands/platform/__tests__/callback-routes-list.test.ts +133 -183
  224. package/src/cli/commands/platform/__tests__/connect.test.ts +66 -181
  225. package/src/cli/commands/platform/__tests__/disconnect.test.ts +71 -227
  226. package/src/cli/commands/platform/__tests__/status.test.ts +169 -287
  227. package/src/cli/commands/platform/connect.ts +16 -80
  228. package/src/cli/commands/platform/disconnect.ts +14 -112
  229. package/src/cli/commands/platform/index.ts +177 -246
  230. package/src/cli/commands/routes.ts +153 -336
  231. package/src/cli/commands/sequence.ts +316 -360
  232. package/src/cli/commands/skills.ts +449 -671
  233. package/src/cli/commands/status.ts +58 -37
  234. package/src/cli/commands/stt.ts +94 -262
  235. package/src/cli/commands/task.ts +14 -40
  236. package/src/cli/commands/trust.ts +8 -3
  237. package/src/cli/commands/tts.ts +162 -167
  238. package/src/cli/commands/ui.ts +35 -42
  239. package/src/cli/commands/usage.ts +188 -126
  240. package/src/cli/commands/watchers.ts +8 -3
  241. package/src/cli/commands/webhooks.ts +99 -193
  242. package/src/cli/lib/__tests__/register-command.test.ts +85 -0
  243. package/src/cli/lib/daemon-credential-client.ts +4 -5
  244. package/src/cli/lib/nested-value.ts +44 -0
  245. package/src/cli/lib/open-browser.ts +36 -0
  246. package/src/cli/lib/register-command.ts +19 -0
  247. package/src/cli/lib/time-ago.ts +34 -0
  248. package/src/cli/program.ts +2 -4
  249. package/src/cli/utils/__tests__/conversation-id.test.ts +66 -0
  250. package/src/cli/utils/__tests__/parse-duration.test.ts +49 -0
  251. package/src/cli/utils/conversation-id.ts +30 -0
  252. package/src/cli/utils/parse-duration.ts +41 -0
  253. package/src/config/acp-defaults.test.ts +5 -1
  254. package/src/config/acp-defaults.ts +11 -4
  255. package/src/config/bundled-skills/acp/TOOLS.json +2 -2
  256. package/src/config/bundled-skills/app-control/TOOLS.json +32 -0
  257. package/src/config/bundled-skills/contacts/SKILL.md +12 -45
  258. package/src/config/bundled-skills/contacts/TOOLS.json +0 -57
  259. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +0 -12
  260. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +0 -58
  261. package/src/config/bundled-tool-registry.ts +0 -2
  262. package/src/config/feature-flag-registry.json +16 -0
  263. package/src/config/llm-resolver.ts +16 -1
  264. package/src/config/loader.ts +76 -14
  265. package/src/config/raw-config-utils.ts +2 -30
  266. package/src/config/schema.ts +4 -0
  267. package/src/config/schemas/__tests__/memory-v2.test.ts +49 -0
  268. package/src/config/schemas/call-site-catalog.ts +29 -7
  269. package/src/config/schemas/llm-request-logs.ts +57 -0
  270. package/src/config/schemas/llm.ts +52 -2
  271. package/src/config/schemas/memory-retrospective.ts +48 -0
  272. package/src/config/schemas/memory-v2.ts +32 -1
  273. package/src/config/schemas/memory.ts +4 -0
  274. package/src/config/schemas/services.ts +15 -12
  275. package/src/config/seed-inference-profiles.ts +195 -134
  276. package/src/contacts/contact-store.ts +0 -61
  277. package/src/context/window-manager.ts +191 -5
  278. package/src/daemon/__tests__/conversation-lifecycle-auto-analyze.test.ts +79 -0
  279. package/src/daemon/__tests__/conversation-tool-setup.test.ts +109 -4
  280. package/src/daemon/__tests__/daemon-skill-host.test.ts +10 -4
  281. package/src/daemon/approval-generators.ts +23 -29
  282. package/src/daemon/config-watcher.ts +2 -0
  283. package/src/daemon/conversation-agent-loop-handlers.ts +24 -0
  284. package/src/daemon/conversation-agent-loop.ts +127 -97
  285. package/src/daemon/conversation-error.ts +21 -0
  286. package/src/daemon/conversation-lifecycle.ts +46 -5
  287. package/src/daemon/conversation-process.ts +36 -19
  288. package/src/daemon/conversation-runtime-assembly.ts +14 -5
  289. package/src/daemon/conversation-slash.ts +175 -23
  290. package/src/daemon/conversation-store.ts +17 -10
  291. package/src/daemon/conversation-surfaces.ts +76 -12
  292. package/src/daemon/conversation-tool-setup.ts +24 -14
  293. package/src/daemon/conversation.ts +48 -9
  294. package/src/daemon/external-plugins-bootstrap.ts +18 -8
  295. package/src/daemon/guardian-action-generators.ts +7 -22
  296. package/src/daemon/handlers/config-model.ts +8 -126
  297. package/src/daemon/handlers/config-slack-channel.ts +10 -7
  298. package/src/daemon/handlers/config-vercel.ts +3 -1
  299. package/src/daemon/handlers/skills.ts +84 -5
  300. package/src/daemon/history-repair.ts +33 -6
  301. package/src/daemon/host-app-control-proxy.ts +44 -19
  302. package/src/daemon/host-bash-proxy.ts +85 -158
  303. package/src/daemon/host-browser-proxy.ts +96 -35
  304. package/src/daemon/host-proxy-base.ts +13 -1
  305. package/src/daemon/host-proxy-preactivation.ts +25 -1
  306. package/src/daemon/identity-helpers.ts +19 -0
  307. package/src/daemon/lifecycle.ts +42 -43
  308. package/src/daemon/meet-host-supervisor.ts +15 -15
  309. package/src/daemon/memory-v2-startup.ts +9 -2
  310. package/src/daemon/message-protocol.ts +6 -0
  311. package/src/daemon/message-types/bookmarks.ts +18 -0
  312. package/src/daemon/message-types/conversations.ts +12 -9
  313. package/src/daemon/message-types/messages.ts +9 -1
  314. package/src/daemon/message-types/sync.ts +60 -0
  315. package/src/daemon/pkb-reminder-builder.test.ts +54 -13
  316. package/src/daemon/pkb-reminder-builder.ts +21 -7
  317. package/src/daemon/process-message.ts +56 -23
  318. package/src/daemon/server.ts +23 -18
  319. package/src/daemon/shutdown-handlers.ts +0 -2
  320. package/src/daemon/tool-setup-types.ts +9 -0
  321. package/src/daemon/tool-side-effects.ts +6 -4
  322. package/src/daemon/wake-target-adapter.ts +11 -0
  323. package/src/export/transcript-formatter.ts +61 -2
  324. package/src/filing/filing-service.ts +40 -53
  325. package/src/heartbeat/__tests__/heartbeat-service.test.ts +359 -0
  326. package/src/heartbeat/heartbeat-run-store.ts +2 -1
  327. package/src/heartbeat/heartbeat-service.ts +148 -127
  328. package/src/home/__tests__/feed-types.test.ts +63 -131
  329. package/src/home/__tests__/feed-writer.test.ts +77 -278
  330. package/src/home/__tests__/post-connect-feed.test.ts +9 -12
  331. package/src/home/feed-types.ts +19 -73
  332. package/src/home/feed-writer.ts +25 -156
  333. package/src/home/post-connect-feed.ts +1 -3
  334. package/src/ipc/__tests__/cli-ipc.test.ts +2 -0
  335. package/src/ipc/__tests__/email-ipc.test.ts +506 -0
  336. package/src/ipc/__tests__/exit-helper.test.ts +104 -0
  337. package/src/ipc/__tests__/streaming-client.test.ts +237 -0
  338. package/src/ipc/__tests__/streaming-framing.test.ts +142 -0
  339. package/src/ipc/assistant-server.ts +55 -6
  340. package/src/ipc/cli-client.ts +370 -50
  341. package/src/ipc/routes/db-proxy-transaction.ts +151 -0
  342. package/src/ipc/skill-routes/__tests__/events-ipc.test.ts +60 -0
  343. package/src/ipc/skill-routes/events.ts +30 -3
  344. package/src/live-voice/__tests__/live-voice-session-manager.test.ts +46 -0
  345. package/src/live-voice/__tests__/runtime-websocket-shell.test.ts +1 -0
  346. package/src/live-voice/live-voice-session-manager.ts +11 -4
  347. package/src/live-voice/live-voice-session.ts +14 -6
  348. package/src/memory/__tests__/bookmark-crud.test.ts +258 -0
  349. package/src/memory/__tests__/bookmark-schema.test.ts +181 -0
  350. package/src/memory/__tests__/conversation-types.test.ts +36 -0
  351. package/src/memory/__tests__/find-most-recent-retrospective-for.test.ts +130 -0
  352. package/src/memory/__tests__/memory-retrospective-enqueue.test.ts +177 -0
  353. package/src/memory/__tests__/memory-retrospective-job.test.ts +328 -0
  354. package/src/memory/__tests__/memory-retrospective-startup-cleanup.test.ts +213 -0
  355. package/src/memory/__tests__/memory-retrospective-trigger-check.test.ts +90 -0
  356. package/src/memory/__tests__/memory-v2-activation-log-store.test.ts +69 -0
  357. package/src/memory/__tests__/memory-v2-concept-frequency.test.ts +3 -0
  358. package/src/memory/bookmark-crud.ts +179 -0
  359. package/src/memory/context-search/__tests__/agent-runner-redaction.test.ts +31 -9
  360. package/src/memory/context-search/agent-protocol.ts +5 -1
  361. package/src/memory/context-search/agent-runner.ts +60 -85
  362. package/src/memory/context-search/limits.ts +1 -4
  363. package/src/memory/context-search/search.ts +23 -113
  364. package/src/memory/context-search/sources/conversations.ts +18 -6
  365. package/src/memory/context-search/sources/memory-v2.ts +39 -14
  366. package/src/memory/context-search/sources/memory.ts +7 -0
  367. package/src/memory/context-search/sources/workspace.ts +13 -10
  368. package/src/memory/context-search/types.ts +1 -1
  369. package/src/memory/conversation-bootstrap.ts +11 -0
  370. package/src/memory/conversation-crud.ts +312 -10
  371. package/src/memory/conversation-queries.ts +9 -5
  372. package/src/memory/conversation-title-service.ts +1 -0
  373. package/src/memory/conversation-types.ts +16 -0
  374. package/src/memory/db-init.ts +14 -0
  375. package/src/memory/embedding-backend.ts +2 -1
  376. package/src/memory/embedding-runtime-manager.ts +1 -2
  377. package/src/memory/graph/__tests__/remember-description.test.ts +55 -0
  378. package/src/memory/graph/conversation-graph-memory.ts +76 -5
  379. package/src/memory/graph/extraction.ts +4 -0
  380. package/src/memory/graph/graph-memory-state-store.ts +16 -3
  381. package/src/memory/graph/tool-handlers.ts +17 -7
  382. package/src/memory/graph/tools.ts +44 -5
  383. package/src/memory/indexer.ts +17 -0
  384. package/src/memory/jobs/__tests__/embed-concept-page.test.ts +13 -15
  385. package/src/memory/jobs/embed-concept-page.ts +45 -9
  386. package/src/memory/jobs-store.ts +51 -1
  387. package/src/memory/jobs-worker.ts +52 -3
  388. package/src/memory/llm-request-log-source-clickhouse.ts +317 -0
  389. package/src/memory/llm-request-log-source-local.ts +26 -0
  390. package/src/memory/llm-request-log-source.ts +97 -0
  391. package/src/memory/llm-request-log-store.ts +1 -1
  392. package/src/memory/memory-retrospective-constants.ts +13 -0
  393. package/src/memory/memory-retrospective-enqueue.ts +114 -0
  394. package/src/memory/memory-retrospective-job.ts +351 -0
  395. package/src/memory/memory-retrospective-startup-cleanup.ts +108 -0
  396. package/src/memory/memory-retrospective-state.ts +162 -0
  397. package/src/memory/memory-retrospective-trigger-check.ts +91 -0
  398. package/src/memory/memory-v2-activation-log-store.ts +49 -5
  399. package/src/memory/memory-v2-concept-frequency.ts +4 -0
  400. package/src/memory/message-content.ts +38 -1
  401. package/src/memory/migrations/227-add-conversation-inference-profile.ts +6 -1
  402. package/src/memory/migrations/228-rename-inference-profile-snake-case.ts +20 -7
  403. package/src/memory/migrations/229-delete-private-conversations.test.ts +70 -1
  404. package/src/memory/migrations/229-delete-private-conversations.ts +12 -0
  405. package/src/memory/migrations/231-repair-memory-graph-event-dates.ts +16 -2
  406. package/src/memory/migrations/240-conversation-inference-profile-session.ts +25 -0
  407. package/src/memory/migrations/241-activation-state-fk-cascade.ts +50 -0
  408. package/src/memory/migrations/242-message-bookmarks.ts +38 -0
  409. package/src/memory/migrations/243-provider-connections.ts +68 -0
  410. package/src/memory/migrations/244-provider-connection-status-label.ts +23 -0
  411. package/src/memory/migrations/245-memory-retrospective-state.ts +36 -0
  412. package/src/memory/migrations/246-backfill-provider-connection-label.ts +81 -0
  413. package/src/memory/migrations/__tests__/244-provider-connection-status-label.test.ts +84 -0
  414. package/src/memory/migrations/__tests__/245-memory-retrospective-state.test.ts +125 -0
  415. package/src/memory/migrations/__tests__/246-backfill-provider-connection-label.test.ts +192 -0
  416. package/src/memory/migrations/index.ts +7 -0
  417. package/src/memory/published-pages-store.ts +16 -0
  418. package/src/memory/schema/bookmarks.ts +38 -0
  419. package/src/memory/schema/conversations.ts +2 -0
  420. package/src/memory/schema/index.ts +2 -0
  421. package/src/memory/schema/inference.ts +29 -0
  422. package/src/memory/schema/memory-core.ts +9 -0
  423. package/src/memory/search/semantic.ts +1 -4
  424. package/src/memory/v2/__tests__/__snapshots__/prompts-router.test.ts.snap +27 -0
  425. package/src/memory/v2/__tests__/activation-store.test.ts +5 -5
  426. package/src/memory/v2/__tests__/activation.test.ts +11 -4
  427. package/src/memory/v2/__tests__/backfill-jobs.test.ts +38 -21
  428. package/src/memory/v2/__tests__/consolidation-job.test.ts +123 -135
  429. package/src/memory/v2/__tests__/edge-index.test.ts +1 -1
  430. package/src/memory/v2/__tests__/frontmatter-sweep.test.ts +111 -0
  431. package/src/memory/v2/__tests__/injection.test.ts +628 -10
  432. package/src/memory/v2/__tests__/migration.test.ts +7 -3
  433. package/src/memory/v2/__tests__/page-index.test.ts +277 -0
  434. package/src/memory/v2/__tests__/page-store.test.ts +14 -1
  435. package/src/memory/v2/__tests__/prompts-router.test.ts +257 -0
  436. package/src/memory/v2/__tests__/qdrant.test.ts +72 -0
  437. package/src/memory/v2/__tests__/reranker.test.ts +4 -4
  438. package/src/memory/v2/__tests__/router.test.ts +516 -0
  439. package/src/memory/v2/__tests__/sim.test.ts +45 -1
  440. package/src/memory/v2/__tests__/skill-store.test.ts +58 -3
  441. package/src/memory/v2/__tests__/static-context.test.ts +7 -22
  442. package/src/memory/v2/__tests__/sweep-job.test.ts +95 -0
  443. package/src/memory/v2/activation-store.ts +34 -5
  444. package/src/memory/v2/activation.ts +40 -27
  445. package/src/memory/v2/backfill-jobs.ts +17 -84
  446. package/src/memory/v2/consolidation-job.ts +85 -78
  447. package/src/memory/v2/frontmatter-sweep.ts +91 -0
  448. package/src/memory/v2/injection.ts +440 -109
  449. package/src/memory/v2/migration.ts +117 -20
  450. package/src/memory/v2/page-index.ts +191 -0
  451. package/src/memory/v2/page-store.ts +3 -0
  452. package/src/memory/v2/prompts/consolidation.ts +9 -7
  453. package/src/memory/v2/prompts/router.ts +192 -0
  454. package/src/memory/v2/qdrant.ts +100 -87
  455. package/src/memory/v2/reranker.ts +14 -7
  456. package/src/memory/v2/router.ts +322 -0
  457. package/src/memory/v2/sim.ts +25 -12
  458. package/src/memory/v2/skill-store.ts +118 -29
  459. package/src/memory/v2/static-context.ts +16 -9
  460. package/src/memory/v2/sweep-job.ts +122 -96
  461. package/src/memory/v2/types.ts +10 -6
  462. package/src/memory/validation.ts +13 -0
  463. package/src/notifications/__tests__/emit-signal-home-feed.test.ts +182 -0
  464. package/src/notifications/__tests__/home-feed-side-effect.test.ts +199 -0
  465. package/src/notifications/__tests__/signal-registry.test.ts +17 -0
  466. package/src/notifications/adapters/platform.ts +171 -0
  467. package/src/notifications/conversation-pairing.ts +2 -2
  468. package/src/notifications/copy-composer.ts +15 -0
  469. package/src/notifications/destination-resolver.ts +21 -0
  470. package/src/notifications/emit-signal.ts +28 -1
  471. package/src/notifications/home-feed-side-effect.ts +111 -0
  472. package/src/notifications/signal.ts +5 -0
  473. package/src/permissions/checker.ts +12 -0
  474. package/src/permissions/ipc-risk-types.ts +2 -0
  475. package/src/plugin-api/index.ts +13 -0
  476. package/src/plugin-api/package.json +12 -0
  477. package/src/plugin-api/types.ts +62 -0
  478. package/src/plugins/defaults/injectors.ts +19 -3
  479. package/src/plugins/external-plugin-loader.ts +294 -0
  480. package/src/plugins/types.ts +46 -30
  481. package/src/plugins/user-loader.ts +64 -41
  482. package/src/proactive-artifact/job.test.ts +12 -4
  483. package/src/proactive-artifact/job.ts +4 -0
  484. package/src/proactive-artifact/trigger-state.test.ts +9 -0
  485. package/src/proactive-artifact/trigger-state.ts +4 -0
  486. package/src/prompts/__tests__/system-prompt.test.ts +105 -0
  487. package/src/prompts/system-prompt.ts +22 -1
  488. package/src/prompts/update-bulletin-job.ts +61 -73
  489. package/src/providers/__tests__/dispatch-connection-routing.test.ts +279 -0
  490. package/src/providers/__tests__/inference.test.ts +288 -0
  491. package/src/providers/__tests__/provider-env-vars.test.ts +6 -0
  492. package/src/providers/__tests__/provider-secret-catalog.test.ts +6 -0
  493. package/src/providers/__tests__/retry-callsite.test.ts +14 -32
  494. package/src/providers/__tests__/satellite-connection-routing.test.ts +510 -0
  495. package/src/providers/__tests__/search-provider-catalog.test.ts +80 -0
  496. package/src/providers/anthropic/client.ts +95 -26
  497. package/src/providers/call-site-routing.ts +94 -16
  498. package/src/providers/connection-resolution.ts +163 -0
  499. package/src/providers/inference/__tests__/connections-status-label.test.ts +250 -0
  500. package/src/providers/inference/adapter-factory.ts +173 -0
  501. package/src/providers/inference/auth.ts +112 -0
  502. package/src/providers/inference/backfill.ts +196 -0
  503. package/src/providers/inference/connections.ts +356 -0
  504. package/src/providers/inference/resolve-auth.ts +65 -0
  505. package/src/providers/model-catalog.ts +104 -6
  506. package/src/providers/openai/responses-provider.ts +4 -2
  507. package/src/providers/provider-env-vars.ts +17 -7
  508. package/src/providers/provider-secret-catalog.ts +49 -30
  509. package/src/providers/provider-send-message.ts +41 -20
  510. package/src/providers/registry.ts +143 -159
  511. package/src/providers/retry.ts +18 -10
  512. package/src/providers/search-provider-catalog.ts +121 -0
  513. package/src/runtime/AGENTS.md +18 -5
  514. package/src/runtime/__tests__/background-job-runner.test.ts +357 -0
  515. package/src/runtime/__tests__/pre-first-message-gate.test.ts +82 -0
  516. package/src/runtime/actor-trust-resolver.ts +32 -10
  517. package/src/runtime/agent-wake.ts +35 -6
  518. package/src/runtime/assistant-event-hub.ts +3 -85
  519. package/src/runtime/auth/route-policy.ts +303 -8
  520. package/src/runtime/auth/same-actor.ts +2 -0
  521. package/src/runtime/background-job-runner.ts +339 -0
  522. package/src/runtime/btw-sidechain.ts +1 -0
  523. package/src/runtime/http-router.ts +36 -1
  524. package/src/runtime/http-server.ts +31 -5
  525. package/src/runtime/http-types.ts +2 -0
  526. package/src/runtime/middleware/__tests__/request-logger.test.ts +162 -0
  527. package/src/runtime/middleware/request-logger.ts +62 -1
  528. package/src/runtime/pre-first-message-gate.ts +83 -0
  529. package/src/runtime/routes/__tests__/backup-routes.test.ts +8 -1
  530. package/src/runtime/routes/__tests__/bookmark-routes.test.ts +251 -0
  531. package/src/runtime/routes/__tests__/connection-routes-vs-cli-parity.test.ts +142 -0
  532. package/src/runtime/routes/__tests__/conversation-management-routes.test.ts +315 -0
  533. package/src/runtime/routes/__tests__/conversation-query-routes.test.ts +189 -0
  534. package/src/runtime/routes/__tests__/home-feed-routes.test.ts +15 -136
  535. package/src/runtime/routes/__tests__/inference-provider-connection-routes.test.ts +736 -0
  536. package/src/runtime/routes/__tests__/memory-v2-routes.test.ts +4 -4
  537. package/src/runtime/routes/__tests__/stt-routes.test.ts +5 -1
  538. package/src/runtime/routes/__tests__/surface-action-routes.test.ts +384 -0
  539. package/src/runtime/routes/__tests__/tts-routes.test.ts +6 -2
  540. package/src/runtime/routes/acp-routes.ts +10 -8
  541. package/src/runtime/routes/app-management-routes.ts +228 -3
  542. package/src/runtime/routes/approval-routes.ts +0 -18
  543. package/src/runtime/routes/audit-routes.ts +43 -0
  544. package/src/runtime/routes/auth-routes.ts +72 -0
  545. package/src/runtime/routes/avatar-routes.ts +273 -20
  546. package/src/runtime/routes/backup-routes.ts +406 -2
  547. package/src/runtime/routes/bookmark-routes.ts +154 -0
  548. package/src/runtime/routes/channel-verification-routes.ts +2 -1
  549. package/src/runtime/routes/contact-routes.ts +0 -160
  550. package/src/runtime/routes/conversation-cli-routes.ts +192 -0
  551. package/src/runtime/routes/conversation-management-routes.ts +30 -43
  552. package/src/runtime/routes/conversation-query-routes.ts +334 -86
  553. package/src/runtime/routes/conversation-routes.ts +31 -10
  554. package/src/runtime/routes/conversations-import-routes.ts +229 -0
  555. package/src/runtime/routes/credential-routes.ts +540 -0
  556. package/src/runtime/routes/debug-routes.ts +2 -2
  557. package/src/runtime/routes/document-pdf-renderer.ts +5 -1
  558. package/src/runtime/routes/domain-routes.ts +167 -0
  559. package/src/runtime/routes/email-routes.ts +603 -0
  560. package/src/runtime/routes/errors.ts +2 -2
  561. package/src/runtime/routes/events-routes.ts +192 -0
  562. package/src/runtime/routes/home-feed-routes.ts +6 -78
  563. package/src/runtime/routes/host-app-control-routes.ts +44 -2
  564. package/src/runtime/routes/host-browser-routes.ts +103 -22
  565. package/src/runtime/routes/http-adapter.ts +2 -0
  566. package/src/runtime/routes/identity-routes.ts +5 -0
  567. package/src/runtime/routes/image-generation-routes.ts +99 -0
  568. package/src/runtime/routes/inbound-stages/background-dispatch.test.ts +137 -1
  569. package/src/runtime/routes/inbound-stages/background-dispatch.ts +87 -7
  570. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.test.ts +156 -0
  571. package/src/runtime/routes/inbound-stages/guardian-reply-intercept.ts +22 -4
  572. package/src/runtime/routes/index.ts +36 -0
  573. package/src/runtime/routes/inference-profile-session-handler.ts +312 -0
  574. package/src/runtime/routes/inference-profile-session-reaper.ts +98 -0
  575. package/src/runtime/routes/inference-profile-session-routes.ts +146 -0
  576. package/src/runtime/routes/inference-provider-connection-routes.ts +317 -0
  577. package/src/runtime/routes/inference-send-routes.ts +115 -0
  578. package/src/runtime/routes/integrations/twilio.ts +1 -0
  579. package/src/runtime/routes/mcp-auth-routes.ts +283 -9
  580. package/src/runtime/routes/memory-v2-routes.ts +13 -398
  581. package/src/runtime/routes/notification-routes.ts +2 -0
  582. package/src/runtime/routes/oauth-apps.ts +112 -7
  583. package/src/runtime/routes/oauth-commands-routes.ts +1007 -0
  584. package/src/runtime/routes/oauth-connect-routes.ts +67 -5
  585. package/src/runtime/routes/oauth-providers.ts +298 -8
  586. package/src/runtime/routes/platform-routes.ts +336 -0
  587. package/src/runtime/routes/playground/inject-failures.ts +2 -1
  588. package/src/runtime/routes/playground/reset-circuit.ts +2 -1
  589. package/src/runtime/routes/playground/state.ts +2 -1
  590. package/src/runtime/routes/publish-routes.ts +221 -0
  591. package/src/runtime/routes/schedule-routes.ts +82 -0
  592. package/src/runtime/routes/sequence-routes.ts +291 -0
  593. package/src/runtime/routes/settings-routes.ts +2 -10
  594. package/src/runtime/routes/skills-routes.ts +31 -1
  595. package/src/runtime/routes/stt-routes.ts +240 -3
  596. package/src/runtime/routes/surface-action-routes.ts +43 -7
  597. package/src/runtime/routes/tts-routes.ts +67 -0
  598. package/src/runtime/routes/types.ts +32 -0
  599. package/src/runtime/routes/user-routes-cli.ts +243 -0
  600. package/src/runtime/routes/webhook-routes.ts +165 -0
  601. package/src/runtime/sync/resource-sync-events.ts +25 -0
  602. package/src/runtime/sync/sync-publisher.test.ts +105 -0
  603. package/src/runtime/sync/sync-publisher.ts +21 -0
  604. package/src/schedule/scheduler.ts +200 -123
  605. package/src/security/__tests__/provider-key-env-fallback.test.ts +12 -6
  606. package/src/security/secret-patterns.ts +3 -0
  607. package/src/sequence/engine.ts +38 -40
  608. package/src/subagent/manager.ts +20 -15
  609. package/src/tools/browser/__tests__/browser-execution-acquire.test.ts +206 -0
  610. package/src/tools/browser/browser-execution.ts +15 -4
  611. package/src/tools/browser/cdp-client/__tests__/factory.test.ts +174 -0
  612. package/src/tools/browser/cdp-client/cdp-inspect/__tests__/ws-transport.test.ts +16 -13
  613. package/src/tools/browser/cdp-client/extension-cdp-client.ts +24 -1
  614. package/src/tools/browser/cdp-client/factory.ts +66 -5
  615. package/src/tools/browser/runtime-check.ts +77 -0
  616. package/src/tools/memory/register.test.ts +3 -3
  617. package/src/tools/memory/register.ts +9 -1
  618. package/src/tools/network/__tests__/web-search.test.ts +156 -0
  619. package/src/tools/network/web-search.ts +280 -37
  620. package/src/tools/permission-checker.ts +13 -5
  621. package/src/tools/subagent/spawn.ts +3 -3
  622. package/src/tools/terminal/shell.ts +44 -0
  623. package/src/usage/attribution.ts +3 -2
  624. package/src/util/pricing.ts +86 -160
  625. package/src/watcher/__tests__/engine.test.ts +301 -0
  626. package/src/watcher/constants.ts +7 -0
  627. package/src/watcher/engine.ts +90 -90
  628. package/src/workspace/migrations/046-seed-conversation-starters-callsite.ts +6 -9
  629. package/src/workspace/migrations/054-seed-recall-callsite.ts +10 -1
  630. package/src/workspace/migrations/057-repair-stale-gemini-model-ids.ts +28 -4
  631. package/src/workspace/migrations/069-seed-onboarding-threads.ts +8 -2
  632. package/src/workspace/migrations/072-seed-reply-suggestion-callsite.ts +104 -0
  633. package/src/workspace/migrations/073-repair-recall-callsite-empty-profile.ts +93 -0
  634. package/src/workspace/migrations/074-drop-deprecated-secret-detection-keys.ts +117 -0
  635. package/src/workspace/migrations/075-memory-v2-bm25-b-default-reembed.ts +61 -0
  636. package/src/workspace/migrations/076-drop-services-inference-mode.ts +62 -0
  637. package/src/workspace/migrations/077-seed-memory-router-callsite.ts +89 -0
  638. package/src/workspace/migrations/078-release-notes-tavily-web-search.ts +66 -0
  639. package/src/workspace/migrations/079-home-feed-notification-only.ts +197 -0
  640. package/src/workspace/migrations/080-restrict-vercel-api-token-metadata.ts +182 -0
  641. package/src/workspace/migrations/081-backfill-bash-allowed-tools-for-injection-credentials.ts +160 -0
  642. package/src/workspace/migrations/082-backfill-managed-profile-labels.ts +154 -0
  643. package/src/workspace/migrations/registry.ts +22 -0
  644. package/src/workspace/migrations/runner.ts +13 -2
  645. package/src/workspace/migrations/types.ts +13 -3
  646. package/src/workspace/provider-commit-message-generator.ts +3 -2
  647. package/src/__tests__/context-search-pkb-source.test.ts +0 -498
  648. package/src/__tests__/credentials-cli.test.ts +0 -1225
  649. package/src/__tests__/memory-admin-recall.test.ts +0 -213
  650. package/src/approvals/__tests__/guardian-feed-event.test.ts +0 -303
  651. package/src/cli/commands/__tests__/email-download.test.ts +0 -260
  652. package/src/cli/commands/__tests__/email-list.test.ts +0 -216
  653. package/src/cli/commands/__tests__/email-register.test.ts +0 -186
  654. package/src/cli/commands/__tests__/email-send.test.ts +0 -416
  655. package/src/cli/commands/__tests__/email-status.test.ts +0 -185
  656. package/src/cli/commands/__tests__/email-unregister.test.ts +0 -168
  657. package/src/cli/commands/__tests__/routes.test.ts +0 -562
  658. package/src/cli/commands/__tests__/stt-transcribe.test.ts +0 -454
  659. package/src/cli/commands/autonomy.ts +0 -365
  660. package/src/cli/commands/memory.ts +0 -424
  661. package/src/cli/commands/oauth/__tests__/connect.test.ts +0 -947
  662. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +0 -686
  663. package/src/cli/commands/oauth/__tests__/mode.test.ts +0 -632
  664. package/src/cli/commands/oauth/__tests__/ping.test.ts +0 -631
  665. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +0 -573
  666. package/src/cli/commands/oauth/__tests__/providers-register.test.ts +0 -330
  667. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +0 -521
  668. package/src/cli/commands/oauth/__tests__/status.test.ts +0 -551
  669. package/src/cli/commands/oauth/__tests__/token.test.ts +0 -420
  670. package/src/cli/lib/daemon-avatar-client.ts +0 -37
  671. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +0 -87
  672. package/src/config/bundled-skills/messaging/tools/__tests__/messaging-feed-events.test.ts +0 -207
  673. package/src/daemon/__tests__/conversation-feed-event.test.ts +0 -304
  674. package/src/heartbeat/__tests__/heartbeat-feed-event.test.ts +0 -233
  675. package/src/home/__tests__/assistant-feed-authoring.test.ts +0 -156
  676. package/src/home/__tests__/emit-feed-event.test.ts +0 -169
  677. package/src/home/__tests__/feed-population-integration.test.ts +0 -312
  678. package/src/home/__tests__/feed-scheduler.test.ts +0 -222
  679. package/src/home/__tests__/phase5-exit-criteria.test.ts +0 -229
  680. package/src/home/__tests__/platform-gmail-digest.test.ts +0 -222
  681. package/src/home/__tests__/rollup-producer.test.ts +0 -507
  682. package/src/home/assistant-feed-authoring.ts +0 -135
  683. package/src/home/emit-feed-event.ts +0 -169
  684. package/src/home/feed-scheduler.ts +0 -281
  685. package/src/home/platform-gmail-digest.ts +0 -163
  686. package/src/home/rewrite-command-preview.ts +0 -66
  687. package/src/home/rewrite-feed-title.ts +0 -58
  688. package/src/home/rollup-producer.ts +0 -426
  689. package/src/memory/admin.ts +0 -326
  690. package/src/memory/context-search/sources/pkb.ts +0 -476
  691. package/src/memory/graph/compaction.ts +0 -299
  692. /package/src/cli/{commands → lib}/cache-fs.ts +0 -0
@@ -1,37 +1,8 @@
1
1
  import type { Command } from "commander";
2
2
 
3
- import {
4
- fetchManagedCatalog,
5
- type ManagedCredentialDescriptor,
6
- } from "../../credential-execution/managed-catalog.js";
7
- import { cliIpcCall } from "../../ipc/cli-client.js";
8
- import { syncManualTokenConnection } from "../../oauth/manual-token-connection.js";
9
- import {
10
- disconnectOAuthProvider,
11
- getConnectionByProvider,
12
- listConnections,
13
- type OAuthConnectionRow,
14
- } from "../../oauth/oauth-store.js";
3
+ import { cliIpcCall, exitFromIpcResult } from "../../ipc/cli-client.js";
15
4
  import type { CredentialPromptResult } from "../../runtime/routes/credential-prompt-routes.js";
16
- import { credentialKey } from "../../security/credential-key.js";
17
- import {
18
- getActiveBackendInfoAsync,
19
- getSecureKeyAsync,
20
- getSecureKeyResultAsync,
21
- } from "../../security/secure-keys.js";
22
- import {
23
- assertMetadataWritable,
24
- type CredentialMetadata,
25
- deleteCredentialMetadata,
26
- getCredentialMetadata,
27
- getCredentialMetadataById,
28
- listCredentialMetadata,
29
- upsertCredentialMetadata,
30
- } from "../../tools/credentials/metadata-store.js";
31
- import {
32
- deleteSecureKeyViaDaemon,
33
- setSecureKeyViaDaemon,
34
- } from "../lib/daemon-credential-client.js";
5
+ import { registerCommand } from "../lib/register-command.js";
35
6
  import { log } from "../logger.js";
36
7
  import { shouldOutputJson, writeOutput } from "../output.js";
37
8
 
@@ -39,12 +10,6 @@ import { shouldOutputJson, writeOutput } from "../output.js";
39
10
  // Format-aware error output
40
11
  // ---------------------------------------------------------------------------
41
12
 
42
- /**
43
- * Write an error message respecting the output format. In JSON mode, emit a
44
- * structured `{ ok: false, error }` object to stdout. In human mode, write
45
- * plain text to stderr so the assistant (LLM) doesn't receive JSON that it
46
- * might misinterpret as data.
47
- */
48
13
  function writeError(cmd: Command, message: string): void {
49
14
  if (shouldOutputJson(cmd)) {
50
15
  writeOutput(cmd, { ok: false, error: message });
@@ -57,16 +22,10 @@ function writeError(cmd: Command, message: string): void {
57
22
  // CES shell lockdown guard
58
23
  // ---------------------------------------------------------------------------
59
24
 
60
- /**
61
- * Returns true when the current process is running inside an untrusted shell
62
- * (CES shell lockdown active). CLI commands that reveal raw secrets must
63
- * check this and fail deterministically.
64
- */
65
25
  function isUntrustedShell(): boolean {
66
26
  return process.env.VELLUM_UNTRUSTED_SHELL === "1";
67
27
  }
68
28
 
69
- /** Error message for commands blocked by CES shell lockdown. */
70
29
  const UNTRUSTED_SHELL_ERROR =
71
30
  "This command is not available in untrusted shell mode. " +
72
31
  "Raw secret access is restricted when running under CES shell lockdown.";
@@ -75,89 +34,6 @@ const UNTRUSTED_SHELL_ERROR =
75
34
  // Shared helpers
76
35
  // ---------------------------------------------------------------------------
77
36
 
78
- /**
79
- * Scrub a secret value for display. Shows `****` + last 4 characters for
80
- * secrets longer than 4 chars, `****` for secrets 4 chars or fewer, and
81
- * `(not set)` when no secret is stored.
82
- */
83
- function scrubSecret(secret: string | undefined): string {
84
- if (secret == null || secret.length === 0) return "(not set)";
85
- if (secret.length <= 4) return "****";
86
- return "****" + secret.slice(-4);
87
- }
88
-
89
- /**
90
- * Safely look up an OAuth connection for a credential service.
91
- * Returns undefined when the oauth-store has no data or the tables
92
- * haven't been created yet (pre-migration).
93
- */
94
- function safeGetConnectionByProvider(
95
- service: string,
96
- ): OAuthConnectionRow | undefined {
97
- try {
98
- return getConnectionByProvider(service);
99
- } catch {
100
- return undefined;
101
- }
102
- }
103
-
104
- /**
105
- * Safely list all OAuth connections. Returns an empty array when the
106
- * oauth-store has no data or the tables haven't been created yet.
107
- */
108
- function safeListConnections(): OAuthConnectionRow[] {
109
- try {
110
- return listConnections();
111
- } catch {
112
- return [];
113
- }
114
- }
115
-
116
- /**
117
- * Build a structured credential output object suitable for both `inspect`
118
- * and `list` responses. Produces an identical shape for every credential.
119
- * Optionally enriches with data from the oauth-store when a matching
120
- * connection exists.
121
- */
122
- function buildCredentialOutput(
123
- metadata: CredentialMetadata,
124
- secret: string | undefined,
125
- connection?: OAuthConnectionRow,
126
- ): Record<string, unknown> {
127
- const output: Record<string, unknown> = {
128
- ok: true,
129
- service: metadata.service,
130
- field: metadata.field,
131
- credentialId: metadata.credentialId,
132
- scrubbedValue: scrubSecret(secret),
133
- hasSecret: secret != null && secret.length > 0,
134
- alias: metadata.alias ?? null,
135
- usageDescription: metadata.usageDescription ?? null,
136
- allowedTools: metadata.allowedTools,
137
- allowedDomains: metadata.allowedDomains,
138
- createdAt: new Date(metadata.createdAt).toISOString(),
139
- updatedAt: new Date(metadata.updatedAt).toISOString(),
140
- injectionTemplateCount: metadata.injectionTemplates?.length ?? 0,
141
- grantedScopes: connection ? JSON.parse(connection.grantedScopes) : null,
142
- expiresAt: connection?.expiresAt
143
- ? new Date(connection.expiresAt).toISOString()
144
- : null,
145
- };
146
-
147
- if (connection) {
148
- output.oauthConnectionId = connection.id;
149
- output.oauthAccountInfo = connection.accountInfo ?? null;
150
- output.oauthStatus = connection.status;
151
- output.oauthHasRefreshToken = connection.hasRefreshToken === 1;
152
- output.oauthLabel = connection.label ?? null;
153
- }
154
-
155
- return output;
156
- }
157
-
158
- /**
159
- * Print a human-readable view of a single credential to the logger.
160
- */
161
37
  function printCredentialHuman(output: Record<string, unknown>): void {
162
38
  log.info(` ${output.service}:${output.field}`);
163
39
  log.info(` ID: ${output.credentialId}`);
@@ -194,28 +70,6 @@ function printCredentialHuman(output: Record<string, unknown>): void {
194
70
  }
195
71
  }
196
72
 
197
- /**
198
- * Build a structured output object for a platform-managed credential descriptor.
199
- * Never includes token values — only handle references and non-secret metadata.
200
- */
201
- function buildManagedCredentialOutput(
202
- descriptor: ManagedCredentialDescriptor,
203
- ): Record<string, unknown> {
204
- return {
205
- ok: true,
206
- source: "platform",
207
- handle: descriptor.handle,
208
- provider: descriptor.provider,
209
- connectionId: descriptor.connectionId,
210
- accountInfo: descriptor.accountInfo,
211
- grantedScopes: descriptor.grantedScopes,
212
- status: descriptor.status,
213
- };
214
- }
215
-
216
- /**
217
- * Print a human-readable view of a platform-managed credential to the logger.
218
- */
219
73
  function printManagedCredentialHuman(output: Record<string, unknown>): void {
220
74
  log.info(` [platform-managed] ${output.provider}`);
221
75
  log.info(` Handle: ${output.handle}`);
@@ -230,21 +84,42 @@ function printManagedCredentialHuman(output: Record<string, unknown>): void {
230
84
  );
231
85
  }
232
86
 
87
+ // ---------------------------------------------------------------------------
88
+ // Response types for IPC calls
89
+ // ---------------------------------------------------------------------------
90
+
91
+ interface CredentialsListResponse {
92
+ credentials: Record<string, unknown>[];
93
+ managedCredentials: Record<string, unknown>[];
94
+ }
95
+
96
+ interface CredentialsStatusResponse {
97
+ backend: string;
98
+ storePath?: string;
99
+ storeExists?: boolean;
100
+ storeKeyPath?: string;
101
+ storeKeyExists?: boolean;
102
+ ready?: boolean;
103
+ url?: string;
104
+ }
105
+
233
106
  // ---------------------------------------------------------------------------
234
107
  // Command registration
235
108
  // ---------------------------------------------------------------------------
236
109
 
237
110
  export function registerCredentialsCommand(program: Command): void {
238
- const credential = program
239
- .command("credentials")
240
- .description(
111
+ registerCommand(program, {
112
+ name: "credentials",
113
+ transport: "ipc",
114
+ description:
241
115
  "Manage credentials in the encrypted vault (API keys, tokens, passwords)",
242
- )
243
- .option("--json", "Machine-readable compact JSON output");
116
+ build: (credential) => {
117
+ credential
118
+ .option("--json", "Machine-readable compact JSON output");
244
119
 
245
- credential.addHelpText(
246
- "after",
247
- `
120
+ credential.addHelpText(
121
+ "after",
122
+ `
248
123
  Credentials are identified by --service and --field flags, matching the
249
124
  storage convention used internally (credential/{service}/{field}):
250
125
 
@@ -264,22 +139,24 @@ Examples:
264
139
  $ assistant credentials inspect --service twilio --field account_sid
265
140
  $ assistant credentials reveal --service twilio --field account_sid
266
141
  $ assistant credentials delete --service twilio --field auth_token`,
267
- );
268
-
269
- // -------------------------------------------------------------------------
270
- // list
271
- // -------------------------------------------------------------------------
272
-
273
- credential
274
- .command("list")
275
- .description("List all stored credentials with metadata and masked values")
276
- .option(
277
- "--search <query>",
278
- "Filter credentials by substring match on service, field, label, or description",
279
- )
280
- .addHelpText(
281
- "after",
282
- `
142
+ );
143
+
144
+ // -----------------------------------------------------------------------
145
+ // list
146
+ // -----------------------------------------------------------------------
147
+
148
+ credential
149
+ .command("list")
150
+ .description(
151
+ "List all stored credentials with metadata and masked values",
152
+ )
153
+ .option(
154
+ "--search <query>",
155
+ "Filter credentials by substring match on service, field, label, or description",
156
+ )
157
+ .addHelpText(
158
+ "after",
159
+ `
283
160
  Lists all credentials in the vault. Each entry includes the same fields as
284
161
  "inspect" — scrubbed value, timestamps, policy, and metadata.
285
162
 
@@ -295,115 +172,64 @@ Examples:
295
172
  $ assistant credentials list --search twilio
296
173
  $ assistant credentials list --search bot_token
297
174
  $ assistant credentials list --json`,
298
- )
299
- .action(async (opts: { search?: string }, cmd: Command) => {
300
- try {
301
- let allMetadata = listCredentialMetadata();
302
-
303
- if (opts.search) {
304
- const query = opts.search.toLowerCase();
305
- allMetadata = allMetadata.filter((m) => {
306
- const service = m.service.toLowerCase();
307
- const field = m.field.toLowerCase();
308
- const alias = (m.alias ?? "").toLowerCase();
309
- const description = (m.usageDescription ?? "").toLowerCase();
310
- return (
311
- service.includes(query) ||
312
- field.includes(query) ||
313
- alias.includes(query) ||
314
- description.includes(query)
175
+ )
176
+ .action(async (opts: { search?: string }, cmd: Command) => {
177
+ const r = await cliIpcCall<CredentialsListResponse>(
178
+ "credentials_list",
179
+ { body: { search: opts.search } },
180
+ );
181
+ if (!r.ok) {
182
+ return exitFromIpcResult(
183
+ r as { ok: false; error?: string; statusCode?: number },
184
+ cmd,
315
185
  );
316
- });
317
- }
318
-
319
- // Build a lookup of oauth connections keyed by provider for enrichment.
320
- // listConnections() returns rows in no guaranteed order, so we compare
321
- // createdAt to keep the most recent active connection per provider —
322
- // matching the behaviour of getConnectionByProvider() used by inspect.
323
- const allConnections = safeListConnections();
324
- const connectionsByProvider = new Map<string, OAuthConnectionRow>();
325
- for (const conn of allConnections) {
326
- if (conn.status !== "active") continue;
327
- const existing = connectionsByProvider.get(conn.provider);
328
- if (!existing || conn.createdAt > existing.createdAt) {
329
- connectionsByProvider.set(conn.provider, conn);
330
186
  }
331
- }
332
187
 
333
- const credentials = await Promise.all(
334
- allMetadata.map(async (m) => {
335
- const secret = await getSecureKeyAsync(
336
- credentialKey(m.service, m.field),
337
- );
338
- const connection = connectionsByProvider.get(m.service);
339
- return buildCredentialOutput(m, secret, connection);
340
- }),
341
- );
188
+ const { credentials, managedCredentials } = r.result!;
342
189
 
343
- // Fetch platform-managed credentials (best-effort — errors do not
344
- // break local listing). Filter by search query if provided.
345
- const managedResult = await fetchManagedCatalog();
346
- let managedOutputs: Record<string, unknown>[] = [];
347
- if (managedResult.ok && managedResult.descriptors.length > 0) {
348
- let descriptors = managedResult.descriptors;
349
- if (opts.search) {
350
- const query = opts.search.toLowerCase();
351
- descriptors = descriptors.filter(
352
- (d) =>
353
- d.provider.toLowerCase().includes(query) ||
354
- d.handle.toLowerCase().includes(query) ||
355
- (d.accountInfo ?? "").toLowerCase().includes(query),
356
- );
357
- }
358
- managedOutputs = descriptors.map(buildManagedCredentialOutput);
359
- }
360
-
361
- if (shouldOutputJson(cmd)) {
362
- writeOutput(cmd, {
363
- ok: true,
364
- credentials,
365
- managedCredentials: managedOutputs,
366
- });
367
- } else {
368
- const totalCount = credentials.length + managedOutputs.length;
369
- if (totalCount === 0) {
370
- log.info("No credentials found");
190
+ if (shouldOutputJson(cmd)) {
191
+ writeOutput(cmd, {
192
+ ok: true,
193
+ credentials,
194
+ managedCredentials,
195
+ });
371
196
  } else {
372
- if (credentials.length > 0) {
373
- log.info(`${credentials.length} local credential(s):\n`);
374
- for (const cred of credentials) {
375
- printCredentialHuman(cred);
376
- log.info("");
197
+ const totalCount = credentials.length + managedCredentials.length;
198
+ if (totalCount === 0) {
199
+ log.info("No credentials found");
200
+ } else {
201
+ if (credentials.length > 0) {
202
+ log.info(`${credentials.length} local credential(s):\n`);
203
+ for (const cred of credentials) {
204
+ printCredentialHuman(cred);
205
+ log.info("");
206
+ }
377
207
  }
378
- }
379
- if (managedOutputs.length > 0) {
380
- log.info(
381
- `${managedOutputs.length} platform-managed credential(s):\n`,
382
- );
383
- for (const managed of managedOutputs) {
384
- printManagedCredentialHuman(managed);
385
- log.info("");
208
+ if (managedCredentials.length > 0) {
209
+ log.info(
210
+ `${managedCredentials.length} platform-managed credential(s):\n`,
211
+ );
212
+ for (const managed of managedCredentials) {
213
+ printManagedCredentialHuman(managed);
214
+ log.info("");
215
+ }
386
216
  }
387
217
  }
388
218
  }
389
- }
390
- } catch (err) {
391
- const message = err instanceof Error ? err.message : String(err);
392
- writeError(cmd, message);
393
- process.exitCode = 1;
394
- }
395
- });
396
-
397
- // -------------------------------------------------------------------------
398
- // status
399
- // -------------------------------------------------------------------------
400
-
401
- credential
402
- .command("status")
403
- .description("Show the active credential backend and its configuration")
404
- .addHelpText(
405
- "after",
406
- `
219
+ });
220
+
221
+ // -----------------------------------------------------------------------
222
+ // status
223
+ // -----------------------------------------------------------------------
224
+
225
+ credential
226
+ .command("status")
227
+ .description(
228
+ "Show the active credential backend and its configuration",
229
+ )
230
+ .addHelpText(
231
+ "after",
232
+ `
407
233
  Shows which credential storage backend this process is using and backend-specific
408
234
  path or connection details. Run this to diagnose credential lookup mismatches —
409
235
  for example, when the CLI and the daemon are reading from different stores.
@@ -420,53 +246,60 @@ process is scoped to.
420
246
  Examples:
421
247
  $ assistant credentials status
422
248
  $ assistant credentials status --json`,
423
- )
424
- .action(async (_opts: Record<string, unknown>, cmd: Command) => {
425
- try {
426
- const info = await getActiveBackendInfoAsync();
427
-
428
- if (shouldOutputJson(cmd)) {
429
- writeOutput(cmd, { ok: true, ...info });
430
- } else {
431
- log.info(`Backend: ${info.backend}`);
432
- if (info.backend === "encrypted-store") {
433
- log.info(
434
- ` Store path: ${info.storePath} [${info.storeExists ? "exists" : "missing"}]`,
435
- );
436
- log.info(
437
- ` Key path: ${info.storeKeyPath} [${info.storeKeyExists ? "exists" : "missing"}]`,
249
+ )
250
+ .action(async (_opts: Record<string, unknown>, cmd: Command) => {
251
+ const r = await cliIpcCall<CredentialsStatusResponse>(
252
+ "credentials_status",
253
+ );
254
+ if (!r.ok) {
255
+ return exitFromIpcResult(
256
+ r as { ok: false; error?: string; statusCode?: number },
257
+ cmd,
438
258
  );
439
- } else if (info.backend === "ces-rpc") {
440
- log.info(` RPC ready: ${info.ready}`);
441
- } else if (info.backend === "ces-http") {
442
- log.info(` URL: ${info.url}`);
443
259
  }
444
- }
445
- } catch (err) {
446
- const message = err instanceof Error ? err.message : String(err);
447
- writeError(cmd, message);
448
- process.exitCode = 1;
449
- }
450
- });
451
-
452
- // -------------------------------------------------------------------------
453
- // set
454
- // -------------------------------------------------------------------------
455
-
456
- credential
457
- .command("set <value>")
458
- .description("Store a secret and create or update its metadata")
459
- .requiredOption("--service <service>", "Service namespace (e.g. google)")
460
- .requiredOption("--field <field>", "Field name (e.g. client_secret)")
461
- .option("--label <label>", 'Human-friendly label (e.g. "prod", "work")')
462
- .option("--description <description>", "What this credential is used for")
463
- .option(
464
- "--allowed-tools <tools>",
465
- "Comma-separated tool names that may use this credential",
466
- )
467
- .addHelpText(
468
- "after",
469
- `
260
+
261
+ const info = r.result!;
262
+
263
+ if (shouldOutputJson(cmd)) {
264
+ writeOutput(cmd, { ok: true, ...info });
265
+ } else {
266
+ log.info(`Backend: ${info.backend}`);
267
+ if (info.backend === "encrypted-store") {
268
+ log.info(
269
+ ` Store path: ${info.storePath} [${info.storeExists ? "exists" : "missing"}]`,
270
+ );
271
+ log.info(
272
+ ` Key path: ${info.storeKeyPath} [${info.storeKeyExists ? "exists" : "missing"}]`,
273
+ );
274
+ } else if (info.backend === "ces-rpc") {
275
+ log.info(` RPC ready: ${info.ready}`);
276
+ } else if (info.backend === "ces-http") {
277
+ log.info(` URL: ${info.url}`);
278
+ }
279
+ }
280
+ });
281
+
282
+ // -----------------------------------------------------------------------
283
+ // set
284
+ // -----------------------------------------------------------------------
285
+
286
+ credential
287
+ .command("set <value>")
288
+ .description("Store a secret and create or update its metadata")
289
+ .requiredOption("--service <service>", "Service namespace (e.g. google)")
290
+ .requiredOption("--field <field>", "Field name (e.g. client_secret)")
291
+ .option("--label <label>", 'Human-friendly label (e.g. "prod", "work")')
292
+ .option(
293
+ "--description <description>",
294
+ "What this credential is used for",
295
+ )
296
+ .option(
297
+ "--allowed-tools <tools>",
298
+ "Comma-separated tool names that may use this credential",
299
+ )
300
+ .addHelpText(
301
+ "after",
302
+ `
470
303
  Arguments:
471
304
  value The secret value to store
472
305
 
@@ -477,163 +310,127 @@ Examples:
477
310
  $ assistant credentials set --service twilio --field account_sid AC1234567890
478
311
  $ assistant credentials set --service fal --field api_key key_live_abc --label "fal-prod" --description "Image generation"
479
312
  $ assistant credentials set --service github --field token ghp_abc --allowed-tools "bash,host_bash"`,
480
- )
481
- .action(
482
- async (
483
- value: string,
484
- opts: {
485
- service: string;
486
- field: string;
487
- label?: string;
488
- description?: string;
489
- allowedTools?: string;
490
- },
491
- cmd: Command,
492
- ) => {
493
- try {
494
- const { service, field } = opts;
495
-
496
- assertMetadataWritable();
497
-
498
- const setResult = await setSecureKeyViaDaemon(
499
- "credential",
500
- `${service}:${field}`,
501
- value,
502
- );
503
- if (!setResult.ok) {
504
- const detail = setResult.error ? `: ${setResult.error}` : "";
505
- writeError(
506
- cmd,
507
- `Failed to store credential ${service}:${field}${detail}`,
508
- );
509
- process.exitCode = 1;
510
- return;
511
- }
512
-
513
- const allowedTools = opts.allowedTools
514
- ? opts.allowedTools.split(",").map((t) => t.trim())
515
- : undefined;
313
+ )
314
+ .action(
315
+ async (
316
+ value: string,
317
+ opts: {
318
+ service: string;
319
+ field: string;
320
+ label?: string;
321
+ description?: string;
322
+ allowedTools?: string;
323
+ },
324
+ cmd: Command,
325
+ ) => {
326
+ const allowedTools = opts.allowedTools
327
+ ? opts.allowedTools.split(",").map((t) => t.trim())
328
+ : undefined;
329
+
330
+ const r = await cliIpcCall<{
331
+ credentialId: string;
332
+ service: string;
333
+ field: string;
334
+ }>("credentials_set", {
335
+ body: {
336
+ service: opts.service,
337
+ field: opts.field,
338
+ value,
339
+ label: opts.label,
340
+ description: opts.description,
341
+ allowedTools,
342
+ },
343
+ });
516
344
 
517
- const metadata = upsertCredentialMetadata(service, field, {
518
- alias: opts.label,
519
- usageDescription: opts.description,
520
- allowedTools,
521
- });
522
- await syncManualTokenConnection(service);
345
+ if (!r.ok) {
346
+ writeError(
347
+ cmd,
348
+ r.error ?? `Failed to store credential ${opts.service}:${opts.field}`,
349
+ );
350
+ process.exitCode = 1;
351
+ return;
352
+ }
523
353
 
524
- if (shouldOutputJson(cmd)) {
525
- writeOutput(cmd, {
526
- ok: true,
527
- credentialId: metadata.credentialId,
528
- service,
529
- field,
530
- });
531
- } else {
532
- log.info(
533
- `Stored credential ${service}:${field} (${metadata.credentialId})`,
534
- );
535
- }
536
- } catch (err) {
537
- const message = err instanceof Error ? err.message : String(err);
538
- writeError(cmd, message);
539
- process.exitCode = 1;
540
- }
541
- },
542
- );
354
+ if (shouldOutputJson(cmd)) {
355
+ writeOutput(cmd, {
356
+ ok: true,
357
+ credentialId: r.result!.credentialId,
358
+ service: opts.service,
359
+ field: opts.field,
360
+ });
361
+ } else {
362
+ log.info(
363
+ `Stored credential ${opts.service}:${opts.field} (${r.result!.credentialId})`,
364
+ );
365
+ }
366
+ },
367
+ );
543
368
 
544
- // -------------------------------------------------------------------------
545
- // delete
546
- // -------------------------------------------------------------------------
547
-
548
- credential
549
- .command("delete")
550
- .description("Remove a secret and its metadata from the vault")
551
- .requiredOption("--service <service>", "Service namespace")
552
- .requiredOption("--field <field>", "Field name")
553
- .addHelpText(
554
- "after",
555
- `
369
+ // -----------------------------------------------------------------------
370
+ // delete
371
+ // -----------------------------------------------------------------------
372
+
373
+ credential
374
+ .command("delete")
375
+ .description("Remove a secret and its metadata from the vault")
376
+ .requiredOption("--service <service>", "Service namespace")
377
+ .requiredOption("--field <field>", "Field name")
378
+ .addHelpText(
379
+ "after",
380
+ `
556
381
  Deletes both the encrypted secret and all associated metadata (policy,
557
382
  timestamps, injection templates). This action cannot be undone.
558
383
 
559
384
  Examples:
560
385
  $ assistant credentials delete --service twilio --field auth_token
561
386
  $ assistant credentials delete --service github --field token`,
562
- )
563
- .action(async (opts: { service: string; field: string }, cmd: Command) => {
564
- try {
565
- const { service, field } = opts;
387
+ )
388
+ .action(
389
+ async (opts: { service: string; field: string }, cmd: Command) => {
390
+ const r = await cliIpcCall<{
391
+ service: string;
392
+ field: string;
393
+ }>("credentials_delete", {
394
+ body: { service: opts.service, field: opts.field },
395
+ });
566
396
 
567
- assertMetadataWritable();
397
+ if (!r.ok) {
398
+ writeError(
399
+ cmd,
400
+ r.error ?? `Failed to delete credential ${opts.service}:${opts.field}`,
401
+ );
402
+ process.exitCode = 1;
403
+ return;
404
+ }
568
405
 
569
- const deleteResult = await deleteSecureKeyViaDaemon(
570
- "credential",
571
- `${service}:${field}`,
406
+ if (shouldOutputJson(cmd)) {
407
+ writeOutput(cmd, {
408
+ ok: true,
409
+ service: opts.service,
410
+ field: opts.field,
411
+ });
412
+ } else {
413
+ log.info(
414
+ `Deleted credential ${opts.service}:${opts.field}`,
415
+ );
416
+ }
417
+ },
572
418
  );
573
- if (deleteResult.result === "error") {
574
- const detail = deleteResult.error ? `: ${deleteResult.error}` : "";
575
- writeError(
576
- cmd,
577
- `Failed to delete credential ${service}:${field}${detail}`,
578
- );
579
- process.exitCode = 1;
580
- return;
581
- }
582
-
583
- const metadataDeleted = deleteCredentialMetadata(service, field);
584
-
585
- // Also clean up the OAuth connection and new-format secure keys.
586
- // disconnectOAuthProvider is a no-op when no connection exists.
587
- let oauthResult: "disconnected" | "not-found" | "error" = "not-found";
588
- try {
589
- oauthResult = await disconnectOAuthProvider(service);
590
- } catch {
591
- // Best-effort — OAuth tables may not exist yet
592
- }
593
-
594
- if (oauthResult === "error") {
595
- writeError(
596
- cmd,
597
- "Failed to disconnect OAuth provider — please try again",
598
- );
599
- process.exitCode = 1;
600
- return;
601
- }
602
-
603
- if (
604
- deleteResult.result !== "deleted" &&
605
- !metadataDeleted &&
606
- oauthResult !== "disconnected"
607
- ) {
608
- writeError(cmd, "Credential not found");
609
- process.exitCode = 1;
610
- return;
611
- }
612
-
613
- if (shouldOutputJson(cmd)) {
614
- writeOutput(cmd, { ok: true, service, field });
615
- } else {
616
- log.info(`Deleted credential ${service}:${field}`);
617
- }
618
- } catch (err) {
619
- const message = err instanceof Error ? err.message : String(err);
620
- writeError(cmd, message);
621
- process.exitCode = 1;
622
- }
623
- });
624
-
625
- // -------------------------------------------------------------------------
626
- // inspect
627
- // -------------------------------------------------------------------------
628
-
629
- credential
630
- .command("inspect [id]")
631
- .description("Show metadata and a masked preview of a stored credential")
632
- .option("--service <service>", "Service namespace")
633
- .option("--field <field>", "Field name")
634
- .addHelpText(
635
- "after",
636
- `
419
+
420
+ // -----------------------------------------------------------------------
421
+ // inspect
422
+ // -----------------------------------------------------------------------
423
+
424
+ credential
425
+ .command("inspect [id]")
426
+ .description(
427
+ "Show metadata and a masked preview of a stored credential",
428
+ )
429
+ .option("--service <service>", "Service namespace")
430
+ .option("--field <field>", "Field name")
431
+ .addHelpText(
432
+ "after",
433
+ `
637
434
  Arguments:
638
435
  id (optional) Credential UUID for lookup by ID
639
436
 
@@ -650,127 +447,66 @@ Examples:
650
447
  $ assistant credentials inspect --service twilio --field account_sid
651
448
  $ assistant credentials inspect 7a3b1c2d-4e5f-6789-abcd-ef0123456789
652
449
  $ assistant credentials inspect --json --service slack_channel --field bot_token`,
653
- )
654
- .action(
655
- async (
656
- id: string | undefined,
657
- opts: { service?: string; field?: string },
658
- cmd: Command,
659
- ) => {
660
- try {
661
- let metadata: CredentialMetadata | undefined;
662
- let storageKey: string;
663
- let service: string | undefined;
664
- let field: string | undefined;
665
-
666
- if (opts.service && opts.field) {
667
- service = opts.service;
668
- field = opts.field;
669
- metadata = getCredentialMetadata(service, field);
670
- storageKey = credentialKey(service, field);
671
- } else if (id) {
672
- metadata = getCredentialMetadataById(id);
673
- if (metadata) {
674
- storageKey = credentialKey(metadata.service, metadata.field);
675
- service = metadata.service;
676
- field = metadata.field;
677
- } else {
678
- // No metadata found by UUID, and we can't determine the storage key
679
- writeError(cmd, "Credential not found");
450
+ )
451
+ .action(
452
+ async (
453
+ id: string | undefined,
454
+ opts: { service?: string; field?: string },
455
+ cmd: Command,
456
+ ) => {
457
+ if (!opts.service && !opts.field && !id) {
458
+ writeError(
459
+ cmd,
460
+ "Either --service and --field flags or a credential UUID is required",
461
+ );
680
462
  process.exitCode = 1;
681
463
  return;
682
464
  }
683
- } else {
684
- writeError(
685
- cmd,
686
- "Either --service and --field flags or a credential UUID is required",
687
- );
688
- process.exitCode = 1;
689
- return;
690
- }
691
465
 
692
- const { value: secret, unreachable } =
693
- await getSecureKeyResultAsync(storageKey);
466
+ const r = await cliIpcCall<Record<string, unknown>>(
467
+ "credentials_inspect",
468
+ {
469
+ body: {
470
+ service: opts.service,
471
+ field: opts.field,
472
+ id,
473
+ },
474
+ },
475
+ );
694
476
 
695
- if (!metadata && (secret == null || secret.length === 0)) {
696
- if (unreachable) {
697
- writeError(
698
- cmd,
699
- "Credential store is unreachable — ensure the assistant is running",
700
- );
701
- } else {
702
- writeError(cmd, "Credential not found");
477
+ if (!r.ok) {
478
+ writeError(cmd, r.error ?? "Credential not found");
479
+ process.exitCode = 1;
480
+ return;
703
481
  }
704
- process.exitCode = 1;
705
- return;
706
- }
707
482
 
708
- // If we have a secret but no metadata, we still need metadata for the output.
709
- // This can happen if someone stored a key directly without going through the
710
- // credential set command. Build a minimal output in that case.
711
- if (!metadata) {
483
+ const output = r.result!;
484
+
712
485
  if (shouldOutputJson(cmd)) {
713
- writeOutput(cmd, {
714
- ok: true,
715
- service: service,
716
- field: field,
717
- credentialId: null,
718
- scrubbedValue: scrubSecret(secret),
719
- hasSecret: secret != null && secret.length > 0,
720
- alias: null,
721
- usageDescription: null,
722
- allowedTools: [],
723
- allowedDomains: [],
724
- createdAt: null,
725
- updatedAt: null,
726
- injectionTemplateCount: 0,
727
- });
486
+ writeOutput(cmd, { ok: true, ...output });
728
487
  } else {
729
- log.info(` ${service}:${field}`);
730
- log.info(` Value: ${scrubSecret(secret)}`);
731
- log.info(" (no metadata record)");
732
- }
733
- return;
734
- }
735
-
736
- const connection = safeGetConnectionByProvider(metadata.service);
737
- const output = buildCredentialOutput(metadata, secret, connection);
738
-
739
- if (unreachable && (secret == null || secret.length === 0)) {
740
- output.scrubbedValue = "(credential store unreachable)";
741
- output.brokerUnreachable = true;
742
- }
743
-
744
- if (shouldOutputJson(cmd)) {
745
- writeOutput(cmd, output);
746
- } else {
747
- printCredentialHuman(output);
748
- if (unreachable && (secret == null || secret.length === 0)) {
749
- log.info(
750
- " \u26A0 Credential store is unreachable — ensure the assistant is running",
751
- );
488
+ printCredentialHuman(output);
489
+ if (output.brokerUnreachable) {
490
+ log.info(
491
+ " ⚠ Credential store is unreachable — ensure the assistant is running",
492
+ );
493
+ }
752
494
  }
753
- }
754
- } catch (err) {
755
- const message = err instanceof Error ? err.message : String(err);
756
- writeError(cmd, message);
757
- process.exitCode = 1;
758
- }
759
- },
760
- );
495
+ },
496
+ );
761
497
 
762
- // -------------------------------------------------------------------------
763
- // reveal
764
- // -------------------------------------------------------------------------
765
-
766
- credential
767
- .command("reveal [id]")
768
- .description("Print the plaintext value of a credential")
769
- .option("--service <service>", "Service namespace")
770
- .option("--field <field>", "Field name")
771
- .addHelpText(
772
- "after",
773
- `
498
+ // -----------------------------------------------------------------------
499
+ // reveal
500
+ // -----------------------------------------------------------------------
501
+
502
+ credential
503
+ .command("reveal [id]")
504
+ .description("Print the plaintext value of a credential")
505
+ .option("--service <service>", "Service namespace")
506
+ .option("--field <field>", "Field name")
507
+ .addHelpText(
508
+ "after",
509
+ `
774
510
  Arguments:
775
511
  id (optional) Credential UUID for lookup by ID
776
512
 
@@ -787,101 +523,86 @@ Examples:
787
523
  $ assistant credentials reveal 7a3b1c2d-4e5f-6789-abcd-ef0123456789
788
524
  $ assistant credentials reveal --json --service twilio --field account_sid
789
525
  $ export TWILIO_TOKEN=$(assistant credentials reveal --service twilio --field auth_token)`,
790
- )
791
- .action(
792
- async (
793
- id: string | undefined,
794
- opts: { service?: string; field?: string },
795
- cmd: Command,
796
- ) => {
797
- try {
798
- // CES shell lockdown: deny raw secret reveal in untrusted shells.
799
- if (isUntrustedShell()) {
800
- writeError(cmd, UNTRUSTED_SHELL_ERROR);
801
- process.exitCode = 1;
802
- return;
803
- }
804
-
805
- let storageKey: string;
806
-
807
- if (opts.service && opts.field) {
808
- storageKey = credentialKey(opts.service, opts.field);
809
- } else if (id) {
810
- const metadata = getCredentialMetadataById(id);
811
- if (metadata) {
812
- storageKey = credentialKey(metadata.service, metadata.field);
813
- } else {
814
- writeError(cmd, "Credential not found");
526
+ )
527
+ .action(
528
+ async (
529
+ id: string | undefined,
530
+ opts: { service?: string; field?: string },
531
+ cmd: Command,
532
+ ) => {
533
+ // CES shell lockdown: deny raw secret reveal in untrusted shells.
534
+ if (isUntrustedShell()) {
535
+ writeError(cmd, UNTRUSTED_SHELL_ERROR);
815
536
  process.exitCode = 1;
816
537
  return;
817
538
  }
818
- } else {
819
- writeError(
820
- cmd,
821
- "Either --service and --field flags or a credential UUID is required",
822
- );
823
- process.exitCode = 1;
824
- return;
825
- }
826
-
827
- const { value: secret, unreachable } =
828
- await getSecureKeyResultAsync(storageKey);
829
539
 
830
- if (secret == null || secret.length === 0) {
831
- if (unreachable) {
540
+ if (!opts.service && !opts.field && !id) {
832
541
  writeError(
833
542
  cmd,
834
- "Credential store is unreachable ensure the assistant is running",
543
+ "Either --service and --field flags or a credential UUID is required",
835
544
  );
836
- } else {
837
- writeError(cmd, "Credential not found");
545
+ process.exitCode = 1;
546
+ return;
838
547
  }
839
- process.exitCode = 1;
840
- return;
841
- }
842
548
 
843
- if (shouldOutputJson(cmd)) {
844
- writeOutput(cmd, { ok: true, value: secret });
845
- } else {
846
- process.stdout.write(secret + "\n");
847
- }
848
- } catch (err) {
849
- const message = err instanceof Error ? err.message : String(err);
850
- writeError(cmd, message);
851
- process.exitCode = 1;
852
- }
853
- },
854
- );
549
+ const r = await cliIpcCall<{ value: string }>(
550
+ "credentials_reveal",
551
+ {
552
+ body: {
553
+ service: opts.service,
554
+ field: opts.field,
555
+ id,
556
+ },
557
+ },
558
+ );
559
+
560
+ if (!r.ok) {
561
+ writeError(cmd, r.error ?? "Credential not found");
562
+ process.exitCode = 1;
563
+ return;
564
+ }
565
+
566
+ if (shouldOutputJson(cmd)) {
567
+ writeOutput(cmd, { ok: true, value: r.result!.value });
568
+ } else {
569
+ process.stdout.write(r.result!.value + "\n");
570
+ }
571
+ },
572
+ );
855
573
 
856
- // -------------------------------------------------------------------------
857
- // prompt
858
- // -------------------------------------------------------------------------
859
-
860
- credential
861
- .command("prompt")
862
- .description(
863
- "Securely prompt the user for a credential via the app UI and store it",
864
- )
865
- .requiredOption("--service <service>", "Service namespace (e.g. sentry)")
866
- .requiredOption("--field <field>", "Field name (e.g. auth_token)")
867
- .requiredOption("--label <label>", "Display label for the prompt UI")
868
- .option("--description <description>", "Context shown in the prompt UI")
869
- .option("--placeholder <placeholder>", "Placeholder text for the input")
870
- .option(
871
- "--allowed-domains <domains>",
872
- "Comma-separated domains where this credential may be used",
873
- )
874
- .option(
875
- "--allowed-tools <tools>",
876
- "Comma-separated tool names that may use this credential",
877
- )
878
- .option(
879
- "--injection-templates <json>",
880
- "JSON array of injection template objects",
881
- )
882
- .addHelpText(
883
- "after",
884
- `
574
+ // -----------------------------------------------------------------------
575
+ // prompt
576
+ // -----------------------------------------------------------------------
577
+
578
+ credential
579
+ .command("prompt")
580
+ .description(
581
+ "Securely prompt the user for a credential via the app UI and store it",
582
+ )
583
+ .requiredOption(
584
+ "--service <service>",
585
+ "Service namespace (e.g. sentry)",
586
+ )
587
+ .requiredOption("--field <field>", "Field name (e.g. auth_token)")
588
+ .requiredOption("--label <label>", "Display label for the prompt UI")
589
+ .option("--description <description>", "Context shown in the prompt UI")
590
+ .option("--placeholder <placeholder>", "Placeholder text for the input")
591
+ .option(
592
+ "--allowed-domains <domains>",
593
+ "Comma-separated domains where this credential may be used",
594
+ )
595
+ .option(
596
+ "--allowed-tools <tools>",
597
+ "Comma-separated tool names that may use this credential",
598
+ )
599
+ .option(
600
+ "--injection-templates <json>",
601
+ "JSON array of injection template objects",
602
+ )
603
+ .addHelpText(
604
+ "after",
605
+ `
885
606
  Opens a secure credential input prompt in the user's connected app (desktop,
886
607
  web, etc.). The user enters the secret through the UI — it never passes through
887
608
  the conversation or CLI output. On success the credential is stored in the
@@ -894,92 +615,91 @@ Examples:
894
615
  --label "Sentry Auth Token" --placeholder "sntrys_..." \\
895
616
  --allowed-domains "sentry.io" \\
896
617
  --injection-templates '[{"hostPattern":"sentry.io","injectionType":"header","headerName":"Authorization","valuePrefix":"Bearer "}]'`,
897
- )
898
- .action(
899
- async (
900
- opts: {
901
- service: string;
902
- field: string;
903
- label: string;
904
- description?: string;
905
- placeholder?: string;
906
- allowedDomains?: string;
907
- allowedTools?: string;
908
- injectionTemplates?: string;
909
- },
910
- cmd: Command,
911
- ) => {
912
- try {
913
- const allowedDomains = opts.allowedDomains
914
- ? opts.allowedDomains.split(",").map((d) => d.trim())
915
- : undefined;
916
- const allowedTools = opts.allowedTools
917
- ? opts.allowedTools.split(",").map((t) => t.trim())
918
- : undefined;
919
-
920
- let injectionTemplates: unknown[] | undefined;
921
- if (opts.injectionTemplates) {
922
- try {
923
- injectionTemplates = JSON.parse(opts.injectionTemplates);
924
- if (!Array.isArray(injectionTemplates)) {
925
- writeError(cmd, "--injection-templates must be a JSON array");
618
+ )
619
+ .action(
620
+ async (
621
+ opts: {
622
+ service: string;
623
+ field: string;
624
+ label: string;
625
+ description?: string;
626
+ placeholder?: string;
627
+ allowedDomains?: string;
628
+ allowedTools?: string;
629
+ injectionTemplates?: string;
630
+ },
631
+ cmd: Command,
632
+ ) => {
633
+ const allowedDomains = opts.allowedDomains
634
+ ? opts.allowedDomains.split(",").map((d) => d.trim())
635
+ : undefined;
636
+ const allowedTools = opts.allowedTools
637
+ ? opts.allowedTools.split(",").map((t) => t.trim())
638
+ : undefined;
639
+
640
+ let injectionTemplates: unknown[] | undefined;
641
+ if (opts.injectionTemplates) {
642
+ try {
643
+ injectionTemplates = JSON.parse(opts.injectionTemplates);
644
+ if (!Array.isArray(injectionTemplates)) {
645
+ writeError(cmd, "--injection-templates must be a JSON array");
646
+ process.exitCode = 1;
647
+ return;
648
+ }
649
+ } catch {
650
+ writeError(cmd, "--injection-templates must be valid JSON");
926
651
  process.exitCode = 1;
927
652
  return;
928
653
  }
929
- } catch {
930
- writeError(cmd, "--injection-templates must be valid JSON");
931
- process.exitCode = 1;
932
- return;
933
654
  }
934
- }
935
655
 
936
- // The server-side handler waits up to permissionTimeoutSec (default
937
- // 300s) for the user to enter the credential. Give the IPC call a
938
- // generous budget so it doesn't time out before the prompt resolves.
939
- const PROMPT_TIMEOUT_MS = 310_000; // 5 min + 10s buffer
940
- const ipc = await cliIpcCall<CredentialPromptResult>(
941
- "credentials_prompt",
942
- {
943
- body: {
944
- service: opts.service,
945
- field: opts.field,
946
- label: opts.label,
947
- description: opts.description,
948
- placeholder: opts.placeholder,
949
- allowedDomains,
950
- allowedTools,
951
- injectionTemplates,
656
+ const PROMPT_TIMEOUT_MS = 310_000; // 5 min + 10s buffer
657
+ const ipc = await cliIpcCall<CredentialPromptResult>(
658
+ "credentials_prompt",
659
+ {
660
+ body: {
661
+ service: opts.service,
662
+ field: opts.field,
663
+ label: opts.label,
664
+ description: opts.description,
665
+ placeholder: opts.placeholder,
666
+ allowedDomains,
667
+ allowedTools,
668
+ injectionTemplates,
669
+ },
952
670
  },
953
- },
954
- { timeoutMs: PROMPT_TIMEOUT_MS },
955
- );
671
+ { timeoutMs: PROMPT_TIMEOUT_MS },
672
+ );
956
673
 
957
- if (!ipc.ok) {
958
- writeError(cmd, ipc.error ?? "Failed to connect to the assistant");
959
- process.exitCode = 1;
960
- return;
961
- }
674
+ if (!ipc.ok) {
675
+ writeError(
676
+ cmd,
677
+ ipc.error ?? "Failed to connect to the assistant",
678
+ );
679
+ process.exitCode = 1;
680
+ return;
681
+ }
962
682
 
963
- if (!ipc.result?.ok) {
964
- writeError(cmd, ipc.result?.error ?? "Credential prompt failed");
965
- process.exitCode = 1;
966
- return;
967
- }
683
+ if (!ipc.result?.ok) {
684
+ writeError(
685
+ cmd,
686
+ ipc.result?.error ?? "Credential prompt failed",
687
+ );
688
+ process.exitCode = 1;
689
+ return;
690
+ }
968
691
 
969
- if (shouldOutputJson(cmd)) {
970
- writeOutput(cmd, {
971
- ok: true,
972
- service: opts.service,
973
- field: opts.field,
974
- });
975
- } else {
976
- log.info(`Stored credential ${opts.service}:${opts.field}`);
977
- }
978
- } catch (err) {
979
- const message = err instanceof Error ? err.message : String(err);
980
- writeError(cmd, message);
981
- process.exitCode = 1;
982
- }
983
- },
984
- );
692
+ if (shouldOutputJson(cmd)) {
693
+ writeOutput(cmd, {
694
+ ok: true,
695
+ service: opts.service,
696
+ field: opts.field,
697
+ });
698
+ } else {
699
+ log.info(`Stored credential ${opts.service}:${opts.field}`);
700
+ }
701
+ },
702
+ );
703
+ },
704
+ });
985
705
  }