@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,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
  }