@vellumai/assistant 0.5.13 → 0.5.14

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 (425) hide show
  1. package/.env.example +1 -6
  2. package/AGENTS.md +4 -0
  3. package/ARCHITECTURE.md +0 -1
  4. package/bunfig.toml +1 -0
  5. package/docs/architecture/memory.md +3 -3
  6. package/openapi.yaml +127 -22
  7. package/package.json +1 -1
  8. package/src/__tests__/access-request-decision.test.ts +2 -32
  9. package/src/__tests__/actor-token-service.test.ts +1 -31
  10. package/src/__tests__/anthropic-provider.test.ts +53 -40
  11. package/src/__tests__/app-git-history.test.ts +9 -17
  12. package/src/__tests__/app-git-service.test.ts +14 -20
  13. package/src/__tests__/app-store-dir-names.test.ts +10 -20
  14. package/src/__tests__/approval-cascade.test.ts +2 -19
  15. package/src/__tests__/approval-primitive.test.ts +2 -27
  16. package/src/__tests__/approval-routes-http.test.ts +2 -30
  17. package/src/__tests__/assistant-events-sse-hardening.test.ts +2 -28
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +2 -45
  19. package/src/__tests__/attachments-store.test.ts +5 -32
  20. package/src/__tests__/audit-log-rotation.test.ts +5 -36
  21. package/src/__tests__/avatar-e2e.test.ts +1 -9
  22. package/src/__tests__/avatar-generator.test.ts +1 -7
  23. package/src/__tests__/browser-fill-credential.test.ts +0 -4
  24. package/src/__tests__/browser-manager.test.ts +0 -6
  25. package/src/__tests__/call-controller.test.ts +1 -22
  26. package/src/__tests__/call-conversation-messages.test.ts +0 -21
  27. package/src/__tests__/call-domain.test.ts +0 -25
  28. package/src/__tests__/call-pointer-messages.test.ts +0 -21
  29. package/src/__tests__/call-recovery.test.ts +0 -22
  30. package/src/__tests__/call-routes-http.test.ts +0 -24
  31. package/src/__tests__/call-store.test.ts +0 -21
  32. package/src/__tests__/cancel-resolves-conversation-key.test.ts +0 -24
  33. package/src/__tests__/canonical-guardian-store.test.ts +48 -21
  34. package/src/__tests__/channel-approval-routes.test.ts +6 -26
  35. package/src/__tests__/channel-approvals.test.ts +1 -38
  36. package/src/__tests__/channel-delivery-store.test.ts +0 -21
  37. package/src/__tests__/channel-guardian.test.ts +0 -26
  38. package/src/__tests__/channel-reply-delivery.test.ts +5 -0
  39. package/src/__tests__/channel-retry-sweep.test.ts +0 -21
  40. package/src/__tests__/checker.test.ts +26 -61
  41. package/src/__tests__/clawhub.test.ts +9 -25
  42. package/src/__tests__/cli-command-risk-guard.test.ts +0 -18
  43. package/src/__tests__/config-loader-backfill.test.ts +9 -28
  44. package/src/__tests__/config-schema-cmd.test.ts +5 -25
  45. package/src/__tests__/config-schema.test.ts +21 -40
  46. package/src/__tests__/config-watcher.test.ts +4 -91
  47. package/src/__tests__/confirmation-request-guardian-bridge.test.ts +0 -21
  48. package/src/__tests__/contacts-tools.test.ts +0 -21
  49. package/src/__tests__/context-memory-e2e.test.ts +0 -21
  50. package/src/__tests__/context-window-manager.test.ts +130 -3
  51. package/src/__tests__/conversation-abort-tool-results.test.ts +0 -4
  52. package/src/__tests__/conversation-agent-loop-overflow.test.ts +0 -4
  53. package/src/__tests__/conversation-agent-loop.test.ts +0 -4
  54. package/src/__tests__/conversation-attachments.test.ts +1 -24
  55. package/src/__tests__/conversation-attention-store.test.ts +0 -21
  56. package/src/__tests__/conversation-attention-telegram.test.ts +0 -22
  57. package/src/__tests__/conversation-clear-safety.test.ts +0 -22
  58. package/src/__tests__/conversation-confirmation-signals.test.ts +2 -21
  59. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +0 -24
  60. package/src/__tests__/conversation-disk-view-integration.test.ts +1 -23
  61. package/src/__tests__/conversation-disk-view.test.ts +5 -27
  62. package/src/__tests__/conversation-error.test.ts +1 -1
  63. package/src/__tests__/conversation-fork-crud.test.ts +1 -33
  64. package/src/__tests__/conversation-fork-route.test.ts +0 -27
  65. package/src/__tests__/conversation-history-web-search.test.ts +23 -16
  66. package/src/__tests__/conversation-init.benchmark.test.ts +22 -43
  67. package/src/__tests__/conversation-key-store-disk-view.test.ts +8 -34
  68. package/src/__tests__/conversation-load-history-repair.test.ts +0 -4
  69. package/src/__tests__/conversation-pre-run-repair.test.ts +0 -4
  70. package/src/__tests__/conversation-provider-retry-repair.test.ts +0 -4
  71. package/src/__tests__/conversation-queue.test.ts +8 -8
  72. package/src/__tests__/conversation-routes-disk-view.test.ts +13 -51
  73. package/src/__tests__/conversation-runtime-assembly.test.ts +64 -38
  74. package/src/__tests__/conversation-slash-commands.test.ts +5 -0
  75. package/src/__tests__/conversation-slash-queue.test.ts +0 -4
  76. package/src/__tests__/conversation-slash-unknown.test.ts +0 -4
  77. package/src/__tests__/conversation-speed-override.test.ts +326 -0
  78. package/src/__tests__/conversation-starter-routes.test.ts +0 -23
  79. package/src/__tests__/conversation-store.test.ts +0 -21
  80. package/src/__tests__/conversation-unread-route.test.ts +0 -24
  81. package/src/__tests__/conversation-usage.test.ts +56 -21
  82. package/src/__tests__/conversation-wipe.test.ts +0 -21
  83. package/src/__tests__/conversation-workspace-cache-state.test.ts +0 -4
  84. package/src/__tests__/conversation-workspace-injection.test.ts +0 -4
  85. package/src/__tests__/conversation-workspace-tool-tracking.test.ts +0 -4
  86. package/src/__tests__/credential-execution-shell-lockdown.test.ts +8 -5
  87. package/src/__tests__/credential-vault-unit.test.ts +9 -428
  88. package/src/__tests__/credentials-cli.test.ts +10 -10
  89. package/src/__tests__/daemon-assistant-events.test.ts +0 -19
  90. package/src/__tests__/date-context.test.ts +77 -97
  91. package/src/__tests__/db-conversation-fork-lineage-migration.test.ts +7 -24
  92. package/src/__tests__/db-llm-request-log-provider-migration.test.ts +29 -42
  93. package/src/__tests__/delete-managed-skill-tool.test.ts +2 -10
  94. package/src/__tests__/deterministic-verification-control-plane.test.ts +1 -26
  95. package/src/__tests__/docker-signing-key-bootstrap.test.ts +61 -15
  96. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +2 -36
  97. package/src/__tests__/email-cli.test.ts +6 -6
  98. package/src/__tests__/ephemeral-permissions.test.ts +5 -17
  99. package/src/__tests__/first-greeting.test.ts +4 -32
  100. package/src/__tests__/followup-tools.test.ts +0 -21
  101. package/src/__tests__/gateway-only-enforcement.test.ts +0 -20
  102. package/src/__tests__/guardian-action-conversation-turn.test.ts +0 -23
  103. package/src/__tests__/guardian-action-followup-executor.test.ts +0 -23
  104. package/src/__tests__/guardian-action-followup-store.test.ts +0 -21
  105. package/src/__tests__/guardian-action-grant-mint-consume.test.ts +0 -21
  106. package/src/__tests__/guardian-action-late-reply.test.ts +0 -21
  107. package/src/__tests__/guardian-action-store.test.ts +0 -21
  108. package/src/__tests__/guardian-action-sweep.test.ts +0 -21
  109. package/src/__tests__/guardian-binding-drift-heal.test.ts +0 -23
  110. package/src/__tests__/guardian-decision-primitive-canonical.test.ts +172 -22
  111. package/src/__tests__/guardian-dispatch.test.ts +0 -21
  112. package/src/__tests__/guardian-grant-minting.test.ts +0 -22
  113. package/src/__tests__/guardian-outbound-http.test.ts +0 -22
  114. package/src/__tests__/guardian-principal-id-roundtrip.test.ts +0 -23
  115. package/src/__tests__/guardian-routing-invariants.test.ts +0 -22
  116. package/src/__tests__/guardian-routing-state.test.ts +0 -22
  117. package/src/__tests__/guardian-verification-voice-binding.test.ts +0 -24
  118. package/src/__tests__/headless-browser-interactions.test.ts +0 -4
  119. package/src/__tests__/headless-browser-navigate.test.ts +0 -4
  120. package/src/__tests__/headless-browser-read-tools.test.ts +0 -4
  121. package/src/__tests__/headless-browser-snapshot.test.ts +0 -4
  122. package/src/__tests__/heartbeat-service.test.ts +99 -26
  123. package/src/__tests__/hooks-blocking.test.ts +3 -3
  124. package/src/__tests__/hooks-config.test.ts +7 -7
  125. package/src/__tests__/hooks-discovery.test.ts +3 -3
  126. package/src/__tests__/hooks-integration.test.ts +5 -5
  127. package/src/__tests__/hooks-manager.test.ts +3 -3
  128. package/src/__tests__/hooks-runner.test.ts +5 -23
  129. package/src/__tests__/hooks-settings.test.ts +3 -3
  130. package/src/__tests__/hooks-templates.test.ts +3 -3
  131. package/src/__tests__/http-conversation-lineage.test.ts +0 -27
  132. package/src/__tests__/identity-intro-cache.test.ts +0 -4
  133. package/src/__tests__/inbound-invite-redemption.test.ts +0 -22
  134. package/src/__tests__/inline-skill-load-permissions.test.ts +5 -16
  135. package/src/__tests__/intent-routing.test.ts +2 -55
  136. package/src/__tests__/invite-redemption-service.test.ts +0 -21
  137. package/src/__tests__/invite-routes-http.test.ts +0 -21
  138. package/src/__tests__/jobs-store-qdrant-breaker.test.ts +0 -17
  139. package/src/__tests__/journal-context.test.ts +8 -75
  140. package/src/__tests__/list-messages-attachments.test.ts +0 -22
  141. package/src/__tests__/llm-context-route-provider.test.ts +0 -21
  142. package/src/__tests__/llm-request-log-turn-query.test.ts +46 -28
  143. package/src/__tests__/llm-usage-store.test.ts +0 -21
  144. package/src/__tests__/log-export-workspace.test.ts +1 -1
  145. package/src/__tests__/managed-skill-lifecycle.test.ts +1 -1
  146. package/src/__tests__/managed-store.test.ts +1 -1
  147. package/src/__tests__/mcp-cli.test.ts +7 -10
  148. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +0 -21
  149. package/src/__tests__/memory-jobs-worker-backoff.test.ts +0 -11
  150. package/src/__tests__/memory-lifecycle-e2e.test.ts +0 -21
  151. package/src/__tests__/memory-recall-log-store.test.ts +0 -27
  152. package/src/__tests__/memory-recall-quality.test.ts +0 -21
  153. package/src/__tests__/memory-regressions.experimental.test.ts +31 -30
  154. package/src/__tests__/memory-regressions.test.ts +282 -70
  155. package/src/__tests__/memory-retrieval.benchmark.test.ts +0 -21
  156. package/src/__tests__/memory-upsert-concurrency.test.ts +0 -21
  157. package/src/__tests__/messaging-send-tool.test.ts +201 -0
  158. package/src/__tests__/migration-cross-version-compatibility.test.ts +18 -13
  159. package/src/__tests__/migration-export-http.test.ts +7 -1
  160. package/src/__tests__/migration-import-commit-http.test.ts +16 -14
  161. package/src/__tests__/migration-import-preflight-http.test.ts +27 -44
  162. package/src/__tests__/migration-validate-http.test.ts +1 -28
  163. package/src/__tests__/native-web-search.test.ts +25 -22
  164. package/src/__tests__/non-member-access-request.test.ts +0 -22
  165. package/src/__tests__/notification-guardian-path.test.ts +0 -21
  166. package/src/__tests__/notification-schedule-dedup.test.ts +1 -25
  167. package/src/__tests__/oauth-apps-routes.test.ts +103 -2
  168. package/src/__tests__/oauth-cli.test.ts +52 -0
  169. package/src/__tests__/oauth-provider-profiles.test.ts +0 -16
  170. package/src/__tests__/oauth-provider-serializer.test.ts +232 -0
  171. package/src/__tests__/oauth-providers-routes.test.ts +257 -0
  172. package/src/__tests__/oauth-store.test.ts +0 -21
  173. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  174. package/src/__tests__/openai-provider.test.ts +261 -0
  175. package/src/__tests__/pairing-concurrent.test.ts +6 -6
  176. package/src/__tests__/pairing-routes.test.ts +7 -1
  177. package/src/__tests__/path-policy.test.ts +1 -1
  178. package/src/__tests__/platform.test.ts +64 -88
  179. package/src/__tests__/playbook-execution.test.ts +0 -21
  180. package/src/__tests__/playbook-tools.test.ts +0 -21
  181. package/src/__tests__/pricing.test.ts +100 -0
  182. package/src/__tests__/relay-server.test.ts +1 -25
  183. package/src/__tests__/runtime-attachment-metadata.test.ts +0 -24
  184. package/src/__tests__/runtime-events-sse-parity.test.ts +2 -24
  185. package/src/__tests__/runtime-events-sse.test.ts +0 -24
  186. package/src/__tests__/sandbox-diagnostics.test.ts +2 -1
  187. package/src/__tests__/scaffold-managed-skill-tool.test.ts +1 -1
  188. package/src/__tests__/schedule-store.test.ts +0 -21
  189. package/src/__tests__/schedule-tools.test.ts +0 -21
  190. package/src/__tests__/scheduler-recurrence.test.ts +0 -21
  191. package/src/__tests__/scoped-approval-grants.test.ts +0 -21
  192. package/src/__tests__/scoped-grant-security-matrix.test.ts +0 -21
  193. package/src/__tests__/secret-allowlist.test.ts +1 -1
  194. package/src/__tests__/secret-ingress-channel.test.ts +0 -5
  195. package/src/__tests__/secret-ingress-cli.test.ts +0 -6
  196. package/src/__tests__/secret-ingress-http.test.ts +0 -5
  197. package/src/__tests__/secret-ingress.test.ts +0 -5
  198. package/src/__tests__/send-endpoint-busy.test.ts +0 -24
  199. package/src/__tests__/sequence-store.test.ts +0 -21
  200. package/src/__tests__/server-history-render.test.ts +0 -24
  201. package/src/__tests__/shell-tool-proxy-mode.test.ts +0 -4
  202. package/src/__tests__/skill-load-inline-command.test.ts +9 -0
  203. package/src/__tests__/skill-load-inline-includes.test.ts +9 -0
  204. package/src/__tests__/skill-load-tool.test.ts +11 -0
  205. package/src/__tests__/skills-uninstall.test.ts +10 -8
  206. package/src/__tests__/skills.test.ts +1 -1
  207. package/src/__tests__/slack-channel-config.test.ts +1 -1
  208. package/src/__tests__/slack-inbound-verification.test.ts +0 -22
  209. package/src/__tests__/starter-bundle.test.ts +4 -1
  210. package/src/__tests__/suggestion-routes.test.ts +2 -0
  211. package/src/__tests__/system-prompt.test.ts +1 -1
  212. package/src/__tests__/terminal-tools.test.ts +1 -1
  213. package/src/__tests__/test-preload.ts +31 -0
  214. package/src/__tests__/tool-execution-abort-cleanup.test.ts +1 -1
  215. package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
  216. package/src/__tests__/tool-executor.test.ts +0 -20
  217. package/src/__tests__/tool-input-summary.test.ts +124 -0
  218. package/src/__tests__/tool-preview-lifecycle.test.ts +2 -1
  219. package/src/__tests__/trust-store.test.ts +7 -1
  220. package/src/__tests__/trusted-contact-inline-approval-integration.test.ts +1 -1
  221. package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +1 -1
  222. package/src/__tests__/trusted-contact-multichannel.test.ts +1 -1
  223. package/src/__tests__/trusted-contact-verification.test.ts +1 -1
  224. package/src/__tests__/turn-boundary-resolution.test.ts +1 -1
  225. package/src/__tests__/twilio-routes.test.ts +1 -1
  226. package/src/__tests__/update-bulletin.test.ts +1 -1
  227. package/src/__tests__/vbundle-pax-and-symlink.test.ts +1 -1
  228. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -0
  229. package/src/__tests__/voice-scoped-grant-consumer.test.ts +1 -1
  230. package/src/__tests__/voice-session-bridge.test.ts +1 -1
  231. package/src/__tests__/workspace-migration-009-backfill-conversation-disk-view.test.ts +4 -4
  232. package/src/__tests__/workspace-migration-013-repair-conversation-disk-view.test.ts +1 -1
  233. package/src/__tests__/workspace-migration-down-functions.test.ts +15 -3
  234. package/src/__tests__/workspace-migration-seed-device-id.test.ts +40 -4
  235. package/src/agent/loop.ts +6 -9
  236. package/src/approvals/guardian-decision-primitive.ts +46 -18
  237. package/src/approvals/guardian-request-resolvers.ts +19 -2
  238. package/src/calls/active-call-lease.ts +2 -2
  239. package/src/cli/AGENTS.md +1 -1
  240. package/src/cli/commands/doctor.ts +9 -9
  241. package/src/cli/commands/memory.ts +142 -0
  242. package/src/cli/commands/oauth/__tests__/connect.test.ts +13 -11
  243. package/src/cli/commands/oauth/__tests__/ping.test.ts +1 -1
  244. package/src/cli/commands/oauth/connect.ts +13 -12
  245. package/src/cli/commands/oauth/index.ts +1 -1
  246. package/src/cli/commands/oauth/providers.ts +47 -62
  247. package/src/cli/commands/platform/__tests__/connect.test.ts +72 -46
  248. package/src/cli/commands/platform/__tests__/disconnect.test.ts +54 -1
  249. package/src/cli/commands/platform/__tests__/status.test.ts +36 -0
  250. package/src/cli/commands/platform/connect.ts +17 -7
  251. package/src/cli/commands/platform/disconnect.ts +28 -3
  252. package/src/cli/commands/platform/index.ts +3 -3
  253. package/src/cli.ts +1 -299
  254. package/src/config/assistant-feature-flags.ts +23 -15
  255. package/src/config/bundled-skills/app-builder/TOOLS.json +16 -0
  256. package/src/config/bundled-skills/app-builder/tools/app-create.ts +4 -0
  257. package/src/config/bundled-skills/app-builder/tools/app-delete.ts +5 -1
  258. package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +9 -1
  259. package/src/config/bundled-skills/app-builder/tools/app-refresh.ts +5 -1
  260. package/src/config/bundled-skills/contacts/TOOLS.json +8 -0
  261. package/src/config/bundled-skills/contacts/tools/contact-search.ts +10 -1
  262. package/src/config/bundled-skills/contacts/tools/contact-upsert.ts +16 -2
  263. package/src/config/bundled-skills/media-processing/tools/ingest-media.ts +1 -0
  264. package/src/config/bundled-skills/messaging/SKILL.md +7 -7
  265. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +37 -0
  266. package/src/config/bundled-skills/slack/SKILL.md +18 -0
  267. package/src/config/env-registry.ts +15 -11
  268. package/src/config/env.ts +1 -11
  269. package/src/config/feature-flag-registry.json +16 -0
  270. package/src/config/schema.ts +4 -0
  271. package/src/config/schemas/heartbeat.ts +6 -1
  272. package/src/config/schemas/inference.ts +14 -3
  273. package/src/config/schemas/memory-processing.ts +16 -8
  274. package/src/config/schemas/memory-retrieval.ts +3 -3
  275. package/src/config/skills.ts +1 -1
  276. package/src/context/window-manager.ts +174 -51
  277. package/src/credential-execution/executable-discovery.ts +2 -2
  278. package/src/daemon/approved-devices-store.ts +2 -2
  279. package/src/daemon/assistant-attachments.ts +2 -0
  280. package/src/daemon/config-watcher.ts +4 -50
  281. package/src/daemon/conversation-agent-loop-handlers.ts +9 -1
  282. package/src/daemon/conversation-agent-loop.ts +12 -0
  283. package/src/daemon/conversation-error.ts +3 -5
  284. package/src/daemon/conversation-history.ts +7 -3
  285. package/src/daemon/conversation-lifecycle.ts +16 -0
  286. package/src/daemon/conversation-messaging.ts +1 -0
  287. package/src/daemon/conversation-notifiers.ts +67 -30
  288. package/src/daemon/conversation-process.ts +161 -2
  289. package/src/daemon/conversation-queue-manager.ts +2 -0
  290. package/src/daemon/conversation-runtime-assembly.ts +33 -11
  291. package/src/daemon/conversation-slash.ts +14 -3
  292. package/src/daemon/conversation-tool-setup.ts +2 -0
  293. package/src/daemon/conversation-usage.ts +32 -4
  294. package/src/daemon/conversation.ts +33 -1
  295. package/src/daemon/daemon-control.ts +32 -16
  296. package/src/daemon/date-context.ts +47 -45
  297. package/src/daemon/dictation-profile-store.ts +2 -2
  298. package/src/daemon/handlers/conversations.ts +19 -0
  299. package/src/daemon/handlers/shared.ts +14 -21
  300. package/src/daemon/lifecycle.ts +5 -7
  301. package/src/daemon/message-types/conversations.ts +2 -0
  302. package/src/daemon/message-types/guardian-actions.ts +3 -17
  303. package/src/daemon/message-types/integrations.ts +11 -1
  304. package/src/daemon/message-types/messages.ts +1 -0
  305. package/src/daemon/pairing-store.ts +2 -79
  306. package/src/daemon/server.ts +154 -8
  307. package/src/daemon/watch-handler.ts +65 -21
  308. package/src/email/guardrails.ts +3 -3
  309. package/src/heartbeat/heartbeat-service.ts +14 -7
  310. package/src/hooks/cli.ts +2 -2
  311. package/src/hooks/config.ts +2 -2
  312. package/src/hooks/discovery.ts +2 -2
  313. package/src/hooks/manager.ts +2 -2
  314. package/src/hooks/runner.ts +5 -2
  315. package/src/hooks/templates.ts +2 -2
  316. package/src/memory/admin.ts +181 -2
  317. package/src/memory/app-git-service.ts +61 -4
  318. package/src/memory/attachments-store.ts +2 -0
  319. package/src/memory/canonical-guardian-store.ts +16 -0
  320. package/src/memory/db-init.ts +8 -0
  321. package/src/memory/embedding-local.ts +5 -2
  322. package/src/memory/indexer.ts +44 -26
  323. package/src/memory/items-extractor.ts +34 -82
  324. package/src/memory/job-handlers/batch-extraction.ts +741 -0
  325. package/src/memory/job-handlers/journal-carry-forward.test.ts +383 -0
  326. package/src/memory/job-handlers/journal-carry-forward.ts +255 -0
  327. package/src/memory/jobs-store.ts +28 -0
  328. package/src/memory/jobs-worker.ts +56 -9
  329. package/src/memory/lifecycle-events-store.ts +4 -2
  330. package/src/memory/llm-request-log-store.ts +40 -2
  331. package/src/memory/llm-usage-store.ts +4 -3
  332. package/src/memory/migrations/199-guardian-request-enrichment-columns.ts +71 -0
  333. package/src/memory/migrations/200-usage-llm-call-count.ts +20 -0
  334. package/src/memory/migrations/index.ts +2 -0
  335. package/src/memory/query-expansion.ts +83 -0
  336. package/src/memory/retriever.test.ts +119 -0
  337. package/src/memory/retriever.ts +513 -105
  338. package/src/memory/schema/guardian.ts +4 -0
  339. package/src/memory/schema/infrastructure.ts +1 -0
  340. package/src/memory/search/formatting.test.ts +140 -0
  341. package/src/memory/search/formatting.ts +143 -198
  342. package/src/memory/search/mmr.ts +136 -0
  343. package/src/memory/search/staleness.ts +0 -15
  344. package/src/memory/search/tier-classifier.ts +10 -21
  345. package/src/memory/search/types.ts +17 -0
  346. package/src/messaging/providers/slack/adapter.ts +51 -5
  347. package/src/notifications/broadcaster.ts +13 -0
  348. package/src/notifications/copy-composer.ts +8 -0
  349. package/src/oauth/connect-orchestrator.ts +1 -1
  350. package/src/oauth/connection-resolver.ts +2 -2
  351. package/src/oauth/provider-serializer.ts +116 -0
  352. package/src/permissions/trust-store.ts +24 -7
  353. package/src/prompts/__tests__/build-cli-reference-section.test.ts +5 -0
  354. package/src/prompts/journal-context.ts +50 -35
  355. package/src/prompts/persona-resolver.ts +1 -1
  356. package/src/prompts/system-prompt.ts +27 -28
  357. package/src/prompts/templates/BOOTSTRAP.md +14 -1
  358. package/src/prompts/templates/HEARTBEAT.md +10 -0
  359. package/src/prompts/templates/NOW.md +19 -25
  360. package/src/prompts/templates/SOUL.md +13 -1
  361. package/src/prompts/templates/UPDATES.md +12 -0
  362. package/src/prompts/update-bulletin.ts +1 -1
  363. package/src/providers/anthropic/client.ts +89 -18
  364. package/src/providers/model-catalog.ts +22 -2
  365. package/src/providers/model-intents.ts +2 -2
  366. package/src/providers/openai/client.ts +40 -1
  367. package/src/providers/retry.ts +23 -4
  368. package/src/providers/types.ts +2 -0
  369. package/src/runtime/assistant-scope.ts +1 -1
  370. package/src/runtime/auth/__tests__/credential-service.test.ts +1 -0
  371. package/src/runtime/auth/route-policy.ts +1 -0
  372. package/src/runtime/auth/token-service.ts +51 -29
  373. package/src/runtime/confirmation-request-guardian-bridge.ts +3 -1
  374. package/src/runtime/guardian-decision-types.ts +16 -10
  375. package/src/runtime/http-server.ts +3 -14
  376. package/src/runtime/http-types.ts +1 -0
  377. package/src/runtime/migrations/vbundle-builder.ts +7 -4
  378. package/src/runtime/migrations/vbundle-import-analyzer.ts +0 -4
  379. package/src/runtime/migrations/vbundle-importer.ts +1 -1
  380. package/src/runtime/routes/conversation-query-routes.ts +40 -8
  381. package/src/runtime/routes/conversation-routes.ts +125 -3
  382. package/src/runtime/routes/guardian-action-routes.ts +9 -3
  383. package/src/runtime/routes/identity-routes.ts +25 -4
  384. package/src/runtime/routes/llm-context-normalization.ts +1 -0
  385. package/src/runtime/routes/log-export-routes.ts +34 -12
  386. package/src/runtime/routes/migration-routes.ts +6 -10
  387. package/src/runtime/routes/oauth-apps.ts +2 -9
  388. package/src/runtime/routes/oauth-providers.ts +60 -0
  389. package/src/runtime/routes/pairing-routes.ts +0 -8
  390. package/src/runtime/routes/settings-routes.ts +0 -1
  391. package/src/runtime/routes/telemetry-routes.ts +16 -4
  392. package/src/security/encrypted-store.ts +2 -2
  393. package/src/security/secret-allowlist.ts +3 -3
  394. package/src/signals/emit-event.ts +42 -0
  395. package/src/signals/user-message.ts +37 -0
  396. package/src/telemetry/usage-telemetry-reporter.test.ts +83 -19
  397. package/src/telemetry/usage-telemetry-reporter.ts +23 -17
  398. package/src/tools/browser/runtime-check.ts +2 -2
  399. package/src/tools/credentials/vault.ts +2 -249
  400. package/src/tools/memory/definitions.ts +1 -1
  401. package/src/tools/memory/handlers.test.ts +50 -8
  402. package/src/tools/memory/handlers.ts +3 -1
  403. package/src/tools/side-effects.ts +1 -6
  404. package/src/tools/terminal/safe-env.ts +3 -2
  405. package/src/tools/terminal/shell.ts +11 -14
  406. package/src/tools/tool-approval-handler.ts +20 -1
  407. package/src/tools/tool-input-summary.ts +66 -0
  408. package/src/tools/types.ts +4 -0
  409. package/src/usage/types.ts +4 -0
  410. package/src/util/device-id.ts +10 -10
  411. package/src/util/platform.ts +71 -33
  412. package/src/util/pricing.ts +19 -6
  413. package/src/util/strip-comment-lines.ts +28 -0
  414. package/src/workspace/git-service.ts +8 -18
  415. package/src/workspace/migrations/003-seed-device-id.ts +6 -4
  416. package/src/workspace/migrations/016-extract-feature-flags-to-protected.ts +7 -1
  417. package/src/workspace/migrations/017-seed-persona-dirs.ts +2 -4
  418. package/src/workspace/migrations/021-move-signals-to-workspace.ts +84 -0
  419. package/src/workspace/migrations/022-move-hooks-to-workspace.ts +94 -0
  420. package/src/workspace/migrations/023-move-config-files-to-workspace.ts +86 -0
  421. package/src/workspace/migrations/024-move-runtime-files-to-workspace.ts +126 -0
  422. package/src/workspace/migrations/migrate-to-workspace-volume.ts +3 -6
  423. package/src/workspace/migrations/registry.ts +8 -0
  424. package/src/signals/confirm.ts +0 -82
  425. package/src/signals/trust-rule.ts +0 -174
@@ -10,7 +10,7 @@ import {
10
10
  import { dirname, join } from "node:path";
11
11
 
12
12
  import { getLogger } from "../util/logger.js";
13
- import { getRootDir } from "../util/platform.js";
13
+ import { getWorkspaceDir } from "../util/platform.js";
14
14
  import { isTerminalState } from "./call-state-machine.js";
15
15
  import type { CallSession } from "./types.js";
16
16
 
@@ -31,7 +31,7 @@ export interface ActiveCallLease {
31
31
  }
32
32
 
33
33
  function getStorePath(): string {
34
- return join(getRootDir(), ACTIVE_CALL_LEASES_FILE);
34
+ return join(getWorkspaceDir(), ACTIVE_CALL_LEASES_FILE);
35
35
  }
36
36
 
37
37
  function loadLeaseFile(): ActiveCallLeaseFile {
package/src/cli/AGENTS.md CHANGED
@@ -93,7 +93,7 @@ are created during the OAuth authorization flow or can be managed manually via
93
93
  their respective subcommands.
94
94
 
95
95
  Examples:
96
- $ assistant oauth connect google --open-browser
96
+ $ assistant oauth connect google
97
97
  $ assistant oauth status google
98
98
  `,
99
99
  );
@@ -8,11 +8,12 @@ import { loadRawConfig } from "../../config/loader.js";
8
8
  import { shouldAutoStartDaemon } from "../../daemon/connection-policy.js";
9
9
  import { isHttpHealthy } from "../../daemon/daemon-control.js";
10
10
  import {
11
+ getDataDir,
11
12
  getDbPath,
12
- getHooksDir,
13
13
  getLogPath,
14
- getRootDir,
14
+ getProtectedDir,
15
15
  getWorkspaceDir,
16
+ getWorkspaceHooksDir,
16
17
  getWorkspaceSkillsDir,
17
18
  } from "../../util/platform.js";
18
19
  import { getProviderKeyViaDaemon } from "../lib/daemon-credential-client.js";
@@ -129,18 +130,17 @@ Examples:
129
130
  }
130
131
 
131
132
  // 5. ~/.vellum/ directory structure (workspace layout)
132
- const rootDir = getRootDir();
133
- const dataDir = process.env.VELLUM_DATA_DIR!;
133
+ const protectedDir = getProtectedDir();
134
+ const dataDir = getDataDir();
134
135
  const workspaceDir = getWorkspaceDir();
135
136
  const requiredDirs = [
136
- rootDir,
137
137
  workspaceDir,
138
138
  dataDir,
139
139
  `${dataDir}/db`,
140
140
  `${dataDir}/logs`,
141
141
  getWorkspaceSkillsDir(),
142
- getHooksDir(),
143
- `${rootDir}/protected`,
142
+ getWorkspaceHooksDir(),
143
+ protectedDir,
144
144
  ];
145
145
  const missing = requiredDirs.filter((d) => !existsSync(d));
146
146
  if (missing.length === 0) {
@@ -151,7 +151,7 @@ Examples:
151
151
 
152
152
  // 6. Disk space
153
153
  try {
154
- const output = execSync(`df -k "${rootDir}"`, {
154
+ const output = execSync(`df -k "${workspaceDir}"`, {
155
155
  stdio: "pipe",
156
156
  encoding: "utf-8",
157
157
  });
@@ -222,7 +222,7 @@ Examples:
222
222
  }
223
223
 
224
224
  // 9. Trust rule syntax
225
- const trustPath = `${rootDir}/protected/trust.json`;
225
+ const trustPath = `${protectedDir}/trust.json`;
226
226
  if (existsSync(trustPath)) {
227
227
  try {
228
228
  const rawTrust = readFileSync(trustPath, "utf-8");
@@ -1,11 +1,15 @@
1
1
  import type { Command } from "commander";
2
2
 
3
3
  import {
4
+ cleanupShortSegments,
5
+ findReextractTarget,
6
+ findReextractTargets,
4
7
  getMemorySystemStatus,
5
8
  queryMemory,
6
9
  requestMemoryBackfill,
7
10
  requestMemoryCleanup,
8
11
  requestMemoryRebuildIndex,
12
+ requestReextract,
9
13
  } from "../../memory/admin.js";
10
14
  import { listConversations } from "../../memory/conversation-queries.js";
11
15
  import { initializeDb } from "../db.js";
@@ -144,6 +148,39 @@ Examples:
144
148
  );
145
149
  });
146
150
 
151
+ memory
152
+ .command("cleanup-segments")
153
+ .description("Remove short segments that waste retrieval budget")
154
+ .option("--dry-run", "Show count of segments that would be removed")
155
+ .addHelpText(
156
+ "after",
157
+ `
158
+ Removes segments shorter than the minimum character threshold from both
159
+ SQLite and Qdrant. Short fragments (e.g. "Collar Touched") burn embedding
160
+ budget, retrieval slots, and injection tokens without adding value.
161
+
162
+ New segments are already filtered at creation time. This command cleans up
163
+ existing short segments that were stored before the filter was added.
164
+
165
+ Examples:
166
+ $ assistant memory cleanup-segments
167
+ $ assistant memory cleanup-segments --dry-run`,
168
+ )
169
+ .action(async (opts: { dryRun?: boolean }) => {
170
+ initializeDb();
171
+ const result = await cleanupShortSegments({ dryRun: opts.dryRun });
172
+ if (opts.dryRun) {
173
+ log.info(
174
+ `Dry run: ${result.dryRunCount} short segment(s) would be removed.`,
175
+ );
176
+ } else {
177
+ log.info(`Removed ${result.removed} short segment(s).`);
178
+ if (result.failed > 0) {
179
+ log.warn(`${result.failed} segment(s) skipped — Qdrant deletion failed. Re-run when Qdrant is available.`);
180
+ }
181
+ }
182
+ });
183
+
147
184
  memory
148
185
  .command("query <text>")
149
186
  .description(
@@ -216,4 +253,109 @@ Examples:
216
253
  const jobId = requestMemoryRebuildIndex();
217
254
  log.info(`Queued rebuild-index job: ${jobId}`);
218
255
  });
256
+
257
+ memory
258
+ .command("re-extract")
259
+ .description(
260
+ "Re-extract memories from conversations using the latest extraction prompt",
261
+ )
262
+ .option(
263
+ "-c, --conversation <id>",
264
+ "Target a specific conversation by ID (repeatable)",
265
+ (val: string, prev: string[]) => [...prev, val],
266
+ [] as string[],
267
+ )
268
+ .option(
269
+ "-t, --top <n>",
270
+ "Auto-select top N conversations by message count",
271
+ )
272
+ .option("--dry-run", "Show what would be re-extracted without doing it")
273
+ .addHelpText(
274
+ "after",
275
+ `
276
+ Re-runs memory extraction on existing conversations using the current
277
+ extraction prompt. This is useful after updating the extraction prompt
278
+ (e.g. importance scoring rework) to re-score and re-extract memories
279
+ from historically important conversations.
280
+
281
+ The command resets extraction checkpoints so the batch extraction handler
282
+ re-processes all messages. Existing memories are provided as supersession
283
+ context — the new extraction can supersede old flat-fact memories with
284
+ richer, properly-scored replacements.
285
+
286
+ Requires the assistant to be running (jobs are processed by the
287
+ background worker).
288
+
289
+ Examples:
290
+ $ assistant memory re-extract --top 20
291
+ $ assistant memory re-extract --conversation conv_abc123
292
+ $ assistant memory re-extract --top 10 --dry-run`,
293
+ )
294
+ .action(
295
+ (opts: {
296
+ conversation?: string[];
297
+ top?: string;
298
+ dryRun?: boolean;
299
+ }) => {
300
+ initializeDb();
301
+
302
+ const targets = [];
303
+
304
+ // Collect targets from --conversation flags
305
+ if (opts.conversation && opts.conversation.length > 0) {
306
+ for (const id of opts.conversation) {
307
+ const target = findReextractTarget(id);
308
+ if (target) {
309
+ targets.push(target);
310
+ } else {
311
+ log.info(`Conversation not found: ${id}`);
312
+ }
313
+ }
314
+ }
315
+
316
+ // Collect targets from --top flag
317
+ if (opts.top) {
318
+ const n = Number.parseInt(opts.top, 10);
319
+ if (!Number.isFinite(n) || n <= 0) {
320
+ log.info("--top must be a positive integer");
321
+ return;
322
+ }
323
+ const topTargets = findReextractTargets(n);
324
+ // Deduplicate against conversation targets
325
+ const seen = new Set(targets.map((t) => t.conversationId));
326
+ for (const t of topTargets) {
327
+ if (!seen.has(t.conversationId)) {
328
+ targets.push(t);
329
+ seen.add(t.conversationId);
330
+ }
331
+ }
332
+ }
333
+
334
+ if (targets.length === 0) {
335
+ log.info(
336
+ "No targets specified. Use --conversation <id> or --top <n>.",
337
+ );
338
+ return;
339
+ }
340
+
341
+ // Show targets
342
+ log.info(`\nRe-extraction targets (${targets.length}):`);
343
+ for (const t of targets) {
344
+ const title = t.title ?? "(untitled)";
345
+ log.info(
346
+ ` ${t.conversationId} ${t.messageCount} msgs "${title}"`,
347
+ );
348
+ }
349
+
350
+ if (opts.dryRun) {
351
+ log.info("\n--dry-run: no jobs queued.");
352
+ return;
353
+ }
354
+
355
+ const { jobIds } = requestReextract(targets);
356
+ log.info(
357
+ `\nQueued ${jobIds.length} re-extraction job(s). The assistant will process them in the background.`,
358
+ );
359
+ },
360
+ );
219
361
  }
@@ -259,10 +259,10 @@ describe("assistant oauth connect", () => {
259
259
  });
260
260
 
261
261
  // -------------------------------------------------------------------------
262
- // Managed mode: prints connect URL without --open-browser
262
+ // Managed mode with --no-browser: prints connect URL
263
263
  // -------------------------------------------------------------------------
264
264
 
265
- test("managed mode: prints connect URL without --open-browser", async () => {
265
+ test("managed mode with --no-browser: prints connect URL", async () => {
266
266
  mockGetProvider = () => ({
267
267
  providerKey: "google",
268
268
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
@@ -282,6 +282,7 @@ describe("assistant oauth connect", () => {
282
282
  const { exitCode, stdout } = await runCommand([
283
283
  "connect",
284
284
  "google",
285
+ "--no-browser",
285
286
  "--json",
286
287
  ]);
287
288
  expect(exitCode).toBe(0);
@@ -295,10 +296,10 @@ describe("assistant oauth connect", () => {
295
296
  });
296
297
 
297
298
  // -------------------------------------------------------------------------
298
- // Managed mode with --open-browser: opens browser and polls
299
+ // Managed mode default: opens browser and polls
299
300
  // -------------------------------------------------------------------------
300
301
 
301
- test("managed mode with --open-browser: opens browser and polls for new connection", async () => {
302
+ test("managed mode default: opens browser and polls for new connection", async () => {
302
303
  mockGetProvider = () => ({
303
304
  providerKey: "google",
304
305
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
@@ -336,7 +337,6 @@ describe("assistant oauth connect", () => {
336
337
  const { exitCode, stdout } = await runCommand([
337
338
  "connect",
338
339
  "google",
339
- "--open-browser",
340
340
  "--json",
341
341
  ]);
342
342
  expect(exitCode).toBe(0);
@@ -352,10 +352,10 @@ describe("assistant oauth connect", () => {
352
352
  });
353
353
 
354
354
  // -------------------------------------------------------------------------
355
- // BYO mode: prints auth URL without --open-browser (deferred)
355
+ // BYO mode with --no-browser: prints auth URL (deferred)
356
356
  // -------------------------------------------------------------------------
357
357
 
358
- test("BYO mode: prints auth URL without --open-browser", async () => {
358
+ test("BYO mode with --no-browser: prints auth URL", async () => {
359
359
  mockGetProvider = () => ({
360
360
  providerKey: "google",
361
361
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
@@ -384,6 +384,7 @@ describe("assistant oauth connect", () => {
384
384
  const { exitCode, stdout } = await runCommand([
385
385
  "connect",
386
386
  "google",
387
+ "--no-browser",
387
388
  "--json",
388
389
  ]);
389
390
  expect(exitCode).toBe(0);
@@ -397,10 +398,10 @@ describe("assistant oauth connect", () => {
397
398
  });
398
399
 
399
400
  // -------------------------------------------------------------------------
400
- // BYO mode with --open-browser: orchestrator called with isInteractive true
401
+ // BYO mode default: orchestrator called with isInteractive true
401
402
  // -------------------------------------------------------------------------
402
403
 
403
- test("BYO mode with --open-browser calls orchestrator with isInteractive: true", async () => {
404
+ test("BYO mode default calls orchestrator with isInteractive: true", async () => {
404
405
  mockGetProvider = () => ({
405
406
  providerKey: "google",
406
407
  authUrl: "https://accounts.google.com/o/oauth2/v2/auth",
@@ -434,13 +435,12 @@ describe("assistant oauth connect", () => {
434
435
  "google",
435
436
  "--client-id",
436
437
  "test-id",
437
- "--open-browser",
438
438
  "--json",
439
439
  ]);
440
440
  expect(exitCode).toBe(0);
441
441
  expect(capturedOpts).toBeDefined();
442
442
  expect(capturedOpts!.isInteractive).toBe(true);
443
- // openUrl should be provided when --open-browser is set
443
+ // openUrl should be provided by default (browser opens automatically)
444
444
  expect(typeof capturedOpts!.openUrl).toBe("function");
445
445
 
446
446
  const parsed = JSON.parse(stdout);
@@ -529,6 +529,7 @@ describe("assistant oauth connect", () => {
529
529
  "google",
530
530
  "--client-id",
531
531
  "should-be-ignored",
532
+ "--no-browser",
532
533
  "--json",
533
534
  ]);
534
535
  // Should succeed — --client-id does not cause an error in managed mode
@@ -573,6 +574,7 @@ describe("assistant oauth connect", () => {
573
574
  const { exitCode, stdout } = await runCommand([
574
575
  "connect",
575
576
  "slack",
577
+ "--no-browser",
576
578
  "--json",
577
579
  ]);
578
580
  expect(exitCode).toBe(0);
@@ -368,7 +368,7 @@ describe("assistant oauth ping", () => {
368
368
  });
369
369
 
370
370
  mockResolveOAuthConnectionResult = new Error(
371
- 'No active OAuth connection found for "google". Connect the service first with oauth2_connect.',
371
+ 'No active OAuth connection found for "google". Connect the service first with `assistant oauth connect google`.',
372
372
  );
373
373
 
374
374
  const { exitCode, stdout } = await runCommand(["ping", "google", "--json"]);
@@ -80,8 +80,8 @@ export function registerConnectCommand(oauth: Command): void {
80
80
  )
81
81
  .option("--scopes <scopes...>", "Scopes to request for the authorization")
82
82
  .option(
83
- "--open-browser",
84
- "Open the auth URL in the browser and wait for completion",
83
+ "--no-browser",
84
+ "Print the auth URL instead of opening it in the browser",
85
85
  )
86
86
  .option("--client-id <id>", "BYO app client ID disambiguation")
87
87
  .addHelpText(
@@ -93,21 +93,22 @@ Arguments:
93
93
 
94
94
  In managed mode, --scopes must be in the provider's allowed set (use full
95
95
  scope URLs). In BYO mode, --scopes are appended to the provider's defaults.
96
- The --open-browser flag polls for a platform connection (managed) or starts
97
- a local callback server (BYO).
96
+ By default, the browser opens automatically and the command waits for
97
+ completion. Use --no-browser to print the URL instead (useful for headless
98
+ or SSH sessions).
98
99
 
99
100
  Examples:
100
101
  $ assistant oauth connect google
101
- $ assistant oauth connect google --open-browser
102
+ $ assistant oauth connect google --no-browser
102
103
  $ assistant oauth connect google --scopes https://www.googleapis.com/auth/calendar https://www.googleapis.com/auth/calendar.events
103
- $ assistant oauth connect google --client-id abc123 --open-browser`,
104
+ $ assistant oauth connect google --client-id abc123`,
104
105
  )
105
106
  .action(
106
107
  async (
107
108
  provider: string,
108
109
  opts: {
109
110
  scopes?: string[];
110
- openBrowser?: boolean;
111
+ browser?: boolean;
111
112
  clientId?: string;
112
113
  },
113
114
  cmd: Command,
@@ -166,7 +167,7 @@ Examples:
166
167
  let redirectServer:
167
168
  | { redirectUrl: string; cleanup: () => void }
168
169
  | undefined;
169
- if (opts.openBrowser) {
170
+ if (opts.browser !== false) {
170
171
  try {
171
172
  redirectServer = await startManagedRedirectServer(provider);
172
173
  body.redirect_after_connect = redirectServer.redirectUrl;
@@ -201,7 +202,7 @@ Examples:
201
202
  return;
202
203
  }
203
204
 
204
- if (opts.openBrowser) {
205
+ if (opts.browser !== false) {
205
206
  // Snapshot existing connection IDs before opening browser
206
207
  const snapshotEntries = await fetchActiveConnections(
207
208
  client,
@@ -287,7 +288,7 @@ Examples:
287
288
  }
288
289
  }
289
290
  } else {
290
- // No --open-browser: output the connect URL
291
+ // --no-browser: output the connect URL
291
292
  if (jsonMode) {
292
293
  writeOutput(cmd, {
293
294
  ok: true,
@@ -357,8 +358,8 @@ Examples:
357
358
  service: provider,
358
359
  clientId,
359
360
  clientSecret,
360
- isInteractive: !!opts.openBrowser,
361
- openUrl: opts.openBrowser ? openInBrowser : undefined,
361
+ isInteractive: opts.browser !== false,
362
+ openUrl: opts.browser !== false ? openInBrowser : undefined,
362
363
  ...(opts.scopes ? { requestedScopes: opts.scopes } : {}),
363
364
  });
364
365
 
@@ -38,7 +38,7 @@ Examples:
38
38
  assistant oauth providers list
39
39
  assistant oauth providers get google
40
40
  assistant oauth mode google --set=managed
41
- assistant oauth connect google --open-browser
41
+ assistant oauth connect google
42
42
  assistant oauth status google
43
43
  assistant oauth ping google
44
44
  assistant oauth request --provider google /gmail/v1/users/me/messages
@@ -14,6 +14,7 @@ import {
14
14
  registerProvider,
15
15
  updateProvider,
16
16
  } from "../../../oauth/oauth-store.js";
17
+ import { serializeProvider } from "../../../oauth/provider-serializer.js";
17
18
  import { SEEDED_PROVIDER_KEYS } from "../../../oauth/seed-providers.js";
18
19
  import { getCliLogger } from "../../logger.js";
19
20
  import { shouldOutputJson, writeOutput } from "../../output.js";
@@ -51,43 +52,12 @@ function resolveRedirectUri(
51
52
  }
52
53
  }
53
54
 
54
- /** Parse stored JSON string fields into their native types. */
55
+ /** Serialize a provider row with the CLI-resolved redirect URI. */
55
56
  function parseProviderRow(row: ReturnType<typeof getProvider>) {
56
57
  if (!row) return row;
57
- return {
58
- ...row,
59
- displayName: row.displayName ?? null,
60
- description: row.description ?? null,
61
- dashboardUrl: row.dashboardUrl ?? null,
62
- clientIdPlaceholder: row.clientIdPlaceholder ?? null,
63
- requiresClientSecret: !!(row.requiresClientSecret ?? 1),
64
- supportsManagedMode: !!row.managedServiceConfigKey,
65
- defaultScopes: row.defaultScopes ? JSON.parse(row.defaultScopes) : [],
66
- scopePolicy: row.scopePolicy ? JSON.parse(row.scopePolicy) : {},
67
- extraParams: row.extraParams ? JSON.parse(row.extraParams) : null,
68
- pingHeaders: row.pingHeaders ? JSON.parse(row.pingHeaders) : null,
69
- pingBody: row.pingBody ? JSON.parse(row.pingBody) : null,
70
- loopbackPort: row.loopbackPort ?? null,
71
- injectionTemplates: row.injectionTemplates
72
- ? JSON.parse(row.injectionTemplates)
73
- : null,
74
- appType: row.appType ?? null,
75
- setupNotes: row.setupNotes ? JSON.parse(row.setupNotes) : null,
76
- identityUrl: row.identityUrl ?? null,
77
- identityMethod: row.identityMethod ?? null,
78
- identityHeaders: row.identityHeaders
79
- ? JSON.parse(row.identityHeaders)
80
- : null,
81
- identityBody: row.identityBody ? JSON.parse(row.identityBody) : null,
82
- identityResponsePaths: row.identityResponsePaths
83
- ? JSON.parse(row.identityResponsePaths)
84
- : null,
85
- identityFormat: row.identityFormat ?? null,
86
- identityOkField: row.identityOkField ?? null,
58
+ return serializeProvider(row, {
87
59
  redirectUri: resolveRedirectUri(row.callbackTransport, row.loopbackPort),
88
- createdAt: new Date(row.createdAt).toISOString(),
89
- updatedAt: new Date(row.updatedAt).toISOString(),
90
- };
60
+ });
91
61
  }
92
62
 
93
63
  export function registerProviderCommands(oauth: Command): void {
@@ -120,6 +90,10 @@ Each provider is identified by a provider key (e.g. "google").`,
120
90
  "--provider-key <key>",
121
91
  'Filter by provider key substring (case-insensitive). Comma-separated values are OR\'d (e.g. "google,slack")',
122
92
  )
93
+ .option(
94
+ "--supports-managed",
95
+ "Only show providers that support managed mode",
96
+ )
123
97
  .addHelpText(
124
98
  "after",
125
99
  `
@@ -139,37 +113,48 @@ Examples:
139
113
  $ assistant oauth providers list
140
114
  $ assistant oauth providers list --provider-key google
141
115
  $ assistant oauth providers list --provider-key "google,slack"
142
- $ assistant oauth providers list --provider-key notion --json`,
116
+ $ assistant oauth providers list --provider-key notion --json
117
+ $ assistant oauth providers list --supports-managed
118
+ $ assistant oauth providers list --supports-managed --json`,
143
119
  )
144
- .action((opts: { providerKey?: string }, cmd: Command) => {
145
- try {
146
- let rows = listProviders().map(parseProviderRow);
147
-
148
- if (opts.providerKey) {
149
- const needles = opts.providerKey
150
- .split(",")
151
- .map((n) => n.trim().toLowerCase())
152
- .filter(Boolean);
153
- rows = rows.filter(
154
- (r) =>
155
- r &&
156
- needles.some((needle) =>
157
- r.providerKey.toLowerCase().includes(needle),
158
- ),
159
- );
160
- }
120
+ .action(
121
+ (
122
+ opts: { providerKey?: string; supportsManaged?: boolean },
123
+ cmd: Command,
124
+ ) => {
125
+ try {
126
+ let rows = listProviders().map(parseProviderRow);
127
+
128
+ if (opts.providerKey) {
129
+ const needles = opts.providerKey
130
+ .split(",")
131
+ .map((n) => n.trim().toLowerCase())
132
+ .filter(Boolean);
133
+ rows = rows.filter(
134
+ (r) =>
135
+ r &&
136
+ needles.some((needle) =>
137
+ r.providerKey.toLowerCase().includes(needle),
138
+ ),
139
+ );
140
+ }
161
141
 
162
- if (!shouldOutputJson(cmd)) {
163
- log.info(`Found ${rows.length} provider(s)`);
164
- }
142
+ if (opts.supportsManaged) {
143
+ rows = rows.filter((r) => r && r.supportsManagedMode);
144
+ }
165
145
 
166
- writeOutput(cmd, rows);
167
- } catch (err) {
168
- const message = err instanceof Error ? err.message : String(err);
169
- writeOutput(cmd, { ok: false, error: message });
170
- process.exitCode = 1;
171
- }
172
- });
146
+ if (!shouldOutputJson(cmd)) {
147
+ log.info(`Found ${rows.length} provider(s)`);
148
+ }
149
+
150
+ writeOutput(cmd, rows);
151
+ } catch (err) {
152
+ const message = err instanceof Error ? err.message : String(err);
153
+ writeOutput(cmd, { ok: false, error: message });
154
+ process.exitCode = 1;
155
+ }
156
+ },
157
+ );
173
158
 
174
159
  // ---------------------------------------------------------------------------
175
160
  // providers get <provider-key>