@vellumai/assistant 0.4.49 → 0.4.51

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 (353) hide show
  1. package/ARCHITECTURE.md +24 -33
  2. package/README.md +3 -3
  3. package/docs/architecture/integrations.md +2 -2
  4. package/docs/architecture/keychain-broker.md +6 -6
  5. package/docs/architecture/memory.md +180 -119
  6. package/knip.json +32 -0
  7. package/package.json +3 -2
  8. package/src/__tests__/agent-loop.test.ts +3 -1
  9. package/src/__tests__/anthropic-provider.test.ts +114 -23
  10. package/src/__tests__/approval-cascade.test.ts +1 -15
  11. package/src/__tests__/approval-routes-http.test.ts +2 -0
  12. package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
  13. package/src/__tests__/btw-routes.test.ts +61 -5
  14. package/src/__tests__/canonical-guardian-store.test.ts +95 -0
  15. package/src/__tests__/checker.test.ts +13 -0
  16. package/src/__tests__/config-schema.test.ts +1 -68
  17. package/src/__tests__/config-watcher.test.ts +8 -0
  18. package/src/__tests__/context-memory-e2e.test.ts +11 -100
  19. package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
  20. package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
  21. package/src/__tests__/credential-security-e2e.test.ts +1 -0
  22. package/src/__tests__/credential-security-invariants.test.ts +8 -7
  23. package/src/__tests__/credential-vault-unit.test.ts +23 -18
  24. package/src/__tests__/credential-vault.test.ts +30 -18
  25. package/src/__tests__/credentials-cli.test.ts +257 -82
  26. package/src/__tests__/cu-unified-flow.test.ts +532 -0
  27. package/src/__tests__/date-context.test.ts +93 -77
  28. package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
  29. package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
  30. package/src/__tests__/history-repair.test.ts +245 -0
  31. package/src/__tests__/host-cu-proxy.test.ts +165 -3
  32. package/src/__tests__/http-user-message-parity.test.ts +1 -0
  33. package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
  34. package/src/__tests__/integration-status.test.ts +31 -30
  35. package/src/__tests__/invite-redemption-service.test.ts +166 -13
  36. package/src/__tests__/invite-routes-http.test.ts +166 -5
  37. package/src/__tests__/keychain-broker-client.test.ts +4 -4
  38. package/src/__tests__/list-messages-attachments.test.ts +193 -0
  39. package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
  40. package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
  41. package/src/__tests__/memory-recall-quality.test.ts +244 -407
  42. package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
  43. package/src/__tests__/memory-regressions.test.ts +477 -2841
  44. package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
  45. package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
  46. package/src/__tests__/mime-builder.test.ts +28 -0
  47. package/src/__tests__/native-web-search.test.ts +1 -0
  48. package/src/__tests__/oauth-cli.test.ts +824 -31
  49. package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
  50. package/src/__tests__/oauth-store.test.ts +363 -17
  51. package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
  52. package/src/__tests__/registry.test.ts +0 -1
  53. package/src/__tests__/relay-server.test.ts +55 -1
  54. package/src/__tests__/schedule-tools.test.ts +32 -0
  55. package/src/__tests__/script-proxy-certs.test.ts +1 -1
  56. package/src/__tests__/secret-onetime-send.test.ts +1 -0
  57. package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
  58. package/src/__tests__/secure-keys.test.ts +78 -18
  59. package/src/__tests__/send-endpoint-busy.test.ts +3 -0
  60. package/src/__tests__/server-history-render.test.ts +2 -2
  61. package/src/__tests__/session-abort-tool-results.test.ts +1 -14
  62. package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
  63. package/src/__tests__/session-agent-loop.test.ts +19 -15
  64. package/src/__tests__/session-confirmation-signals.test.ts +1 -15
  65. package/src/__tests__/session-error.test.ts +124 -2
  66. package/src/__tests__/session-history-web-search.test.ts +918 -0
  67. package/src/__tests__/session-pre-run-repair.test.ts +1 -14
  68. package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
  69. package/src/__tests__/session-queue.test.ts +37 -27
  70. package/src/__tests__/session-runtime-assembly.test.ts +54 -0
  71. package/src/__tests__/session-slash-known.test.ts +1 -15
  72. package/src/__tests__/session-slash-queue.test.ts +1 -15
  73. package/src/__tests__/session-slash-unknown.test.ts +1 -15
  74. package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
  75. package/src/__tests__/session-workspace-injection.test.ts +3 -37
  76. package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
  77. package/src/__tests__/skills-install-extract.test.ts +93 -0
  78. package/src/__tests__/skills.test.ts +2 -2
  79. package/src/__tests__/skillssh-registry.test.ts +451 -0
  80. package/src/__tests__/slack-channel-config.test.ts +10 -8
  81. package/src/__tests__/trust-store.test.ts +15 -0
  82. package/src/__tests__/twilio-config.test.ts +11 -10
  83. package/src/__tests__/twilio-provider.test.ts +9 -4
  84. package/src/__tests__/voice-invite-redemption.test.ts +85 -5
  85. package/src/agent/ax-tree-compaction.test.ts +51 -0
  86. package/src/agent/loop.ts +39 -12
  87. package/src/approvals/AGENTS.md +1 -1
  88. package/src/approvals/guardian-request-resolvers.ts +14 -2
  89. package/src/bundler/compiler-tools.ts +66 -2
  90. package/src/calls/call-domain.ts +134 -3
  91. package/src/calls/call-store.ts +6 -0
  92. package/src/calls/relay-server.ts +44 -6
  93. package/src/calls/relay-setup-router.ts +17 -1
  94. package/src/calls/twilio-config.ts +5 -4
  95. package/src/calls/twilio-provider.ts +14 -9
  96. package/src/calls/twilio-rest.ts +10 -7
  97. package/src/calls/types.ts +3 -1
  98. package/src/cli/commands/config.ts +14 -9
  99. package/src/cli/commands/contacts.ts +3 -0
  100. package/src/cli/commands/credentials.ts +170 -174
  101. package/src/cli/commands/doctor.ts +11 -8
  102. package/src/cli/commands/keys.ts +9 -9
  103. package/src/cli/commands/mcp.ts +46 -59
  104. package/src/cli/commands/memory.ts +16 -165
  105. package/src/cli/commands/oauth/apps.ts +68 -10
  106. package/src/cli/commands/oauth/connections.ts +475 -105
  107. package/src/cli/commands/oauth/index.ts +3 -3
  108. package/src/cli/commands/oauth/providers.ts +18 -4
  109. package/src/cli/commands/sessions.ts +5 -2
  110. package/src/cli/commands/skills.ts +173 -1
  111. package/src/cli/http-client.ts +0 -20
  112. package/src/cli/main-screen.tsx +2 -2
  113. package/src/cli/program.ts +5 -6
  114. package/src/cli.ts +20 -22
  115. package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
  116. package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
  117. package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
  118. package/src/config/bundled-skills/contacts/SKILL.md +35 -11
  119. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  120. package/src/config/bundled-skills/gmail/SKILL.md +1 -1
  121. package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
  122. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
  123. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
  124. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
  125. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
  126. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
  127. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
  128. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
  129. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
  130. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
  131. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
  132. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
  133. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
  134. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
  135. package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
  136. package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
  137. package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
  138. package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
  139. package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
  140. package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
  141. package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
  142. package/src/config/bundled-skills/messaging/SKILL.md +1 -1
  143. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
  144. package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
  145. package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
  146. package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
  147. package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
  148. package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
  149. package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
  150. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
  151. package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
  152. package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
  153. package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
  154. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
  155. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
  156. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
  157. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
  158. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
  159. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
  160. package/src/config/bundled-tool-registry.ts +2 -5
  161. package/src/config/loader.ts +6 -42
  162. package/src/config/schema.ts +1 -12
  163. package/src/config/schemas/memory-lifecycle.ts +0 -9
  164. package/src/config/schemas/memory-processing.ts +0 -180
  165. package/src/config/schemas/memory-retrieval.ts +32 -104
  166. package/src/config/schemas/memory.ts +0 -10
  167. package/src/config/types.ts +0 -4
  168. package/src/contacts/contact-store.ts +39 -2
  169. package/src/contacts/contacts-write.ts +9 -0
  170. package/src/context/window-manager.ts +4 -1
  171. package/src/daemon/config-watcher.ts +55 -2
  172. package/src/daemon/daemon-control.ts +1 -1
  173. package/src/daemon/date-context.ts +114 -31
  174. package/src/daemon/handlers/config-ingress.ts +2 -2
  175. package/src/daemon/handlers/config-slack-channel.ts +59 -39
  176. package/src/daemon/handlers/config-telegram.ts +23 -14
  177. package/src/daemon/handlers/session-history.ts +1 -358
  178. package/src/daemon/handlers/sessions.ts +18 -13
  179. package/src/daemon/handlers/shared.ts +3 -17
  180. package/src/daemon/handlers/skills.ts +20 -1
  181. package/src/daemon/history-repair.ts +72 -8
  182. package/src/daemon/host-cu-proxy.ts +55 -26
  183. package/src/daemon/lifecycle.ts +39 -4
  184. package/src/daemon/mcp-reload-service.ts +2 -2
  185. package/src/daemon/message-types/computer-use.ts +1 -12
  186. package/src/daemon/message-types/memory.ts +4 -16
  187. package/src/daemon/message-types/messages.ts +1 -0
  188. package/src/daemon/message-types/sessions.ts +4 -42
  189. package/src/daemon/server.ts +6 -1
  190. package/src/daemon/session-agent-loop-handlers.ts +38 -0
  191. package/src/daemon/session-agent-loop.ts +334 -48
  192. package/src/daemon/session-error.ts +89 -6
  193. package/src/daemon/session-history.ts +17 -7
  194. package/src/daemon/session-media-retry.ts +6 -2
  195. package/src/daemon/session-memory.ts +69 -149
  196. package/src/daemon/session-process.ts +10 -1
  197. package/src/daemon/session-runtime-assembly.ts +49 -19
  198. package/src/daemon/session-slash.ts +3 -5
  199. package/src/daemon/session-surfaces.ts +4 -1
  200. package/src/daemon/session-tool-setup.ts +7 -1
  201. package/src/daemon/session.ts +12 -2
  202. package/src/email/providers/index.ts +2 -2
  203. package/src/instrument.ts +61 -1
  204. package/src/media/avatar-router.ts +1 -1
  205. package/src/memory/admin.ts +2 -191
  206. package/src/memory/canonical-guardian-store.ts +38 -2
  207. package/src/memory/conversation-crud.ts +0 -33
  208. package/src/memory/conversation-queries.ts +25 -83
  209. package/src/memory/db-init.ts +32 -0
  210. package/src/memory/embedding-backend.ts +84 -8
  211. package/src/memory/embedding-types.ts +9 -1
  212. package/src/memory/indexer.ts +7 -46
  213. package/src/memory/invite-store.ts +19 -0
  214. package/src/memory/items-extractor.ts +274 -76
  215. package/src/memory/job-handlers/backfill.ts +2 -127
  216. package/src/memory/job-handlers/cleanup.ts +2 -16
  217. package/src/memory/job-handlers/extraction.ts +2 -138
  218. package/src/memory/job-handlers/index-maintenance.ts +1 -6
  219. package/src/memory/job-handlers/summarization.ts +3 -148
  220. package/src/memory/job-utils.ts +21 -59
  221. package/src/memory/jobs-store.ts +1 -159
  222. package/src/memory/jobs-worker.ts +9 -52
  223. package/src/memory/migrations/104-core-indexes.ts +3 -3
  224. package/src/memory/migrations/149-oauth-tables.ts +2 -0
  225. package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
  226. package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
  227. package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
  228. package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
  229. package/src/memory/migrations/154-drop-fts.ts +20 -0
  230. package/src/memory/migrations/155-drop-conflicts.ts +7 -0
  231. package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
  232. package/src/memory/migrations/157-invite-contact-id.ts +104 -0
  233. package/src/memory/migrations/index.ts +8 -0
  234. package/src/memory/migrations/registry.ts +6 -0
  235. package/src/memory/qdrant-client.ts +148 -51
  236. package/src/memory/raw-query.ts +1 -1
  237. package/src/memory/retriever.test.ts +294 -273
  238. package/src/memory/retriever.ts +421 -645
  239. package/src/memory/schema/calls.ts +2 -0
  240. package/src/memory/schema/contacts.ts +1 -0
  241. package/src/memory/schema/memory-core.ts +3 -48
  242. package/src/memory/schema/oauth.ts +2 -0
  243. package/src/memory/search/formatting.ts +263 -176
  244. package/src/memory/search/lexical.ts +1 -254
  245. package/src/memory/search/ranking.ts +0 -455
  246. package/src/memory/search/semantic.ts +100 -14
  247. package/src/memory/search/staleness.ts +47 -0
  248. package/src/memory/search/tier-classifier.ts +21 -0
  249. package/src/memory/search/types.ts +15 -77
  250. package/src/memory/task-memory-cleanup.ts +4 -6
  251. package/src/messaging/provider.ts +1 -1
  252. package/src/messaging/providers/gmail/adapter.ts +1 -1
  253. package/src/messaging/providers/gmail/mime-builder.ts +17 -7
  254. package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
  255. package/src/messaging/providers/whatsapp/adapter.ts +13 -9
  256. package/src/messaging/registry.ts +9 -5
  257. package/src/oauth/byo-connection.test.ts +40 -25
  258. package/src/oauth/connect-orchestrator.ts +4 -10
  259. package/src/oauth/connection-resolver.ts +20 -6
  260. package/src/oauth/manual-token-connection.ts +5 -5
  261. package/src/oauth/oauth-store.ts +183 -31
  262. package/src/oauth/platform-connection.test.ts +1 -1
  263. package/src/oauth/provider-behaviors.ts +503 -4
  264. package/src/oauth/seed-providers.ts +214 -8
  265. package/src/oauth/token-persistence.ts +31 -16
  266. package/src/permissions/defaults.ts +1 -0
  267. package/src/permissions/trust-store.ts +23 -1
  268. package/src/playbooks/playbook-compiler.ts +1 -1
  269. package/src/prompts/system-prompt.ts +18 -2
  270. package/src/providers/anthropic/client.ts +56 -126
  271. package/src/providers/types.ts +7 -1
  272. package/src/runtime/AGENTS.md +9 -0
  273. package/src/runtime/auth/route-policy.ts +6 -3
  274. package/src/runtime/channel-readiness-service.ts +48 -40
  275. package/src/runtime/guardian-reply-router.ts +24 -22
  276. package/src/runtime/http-server.ts +2 -2
  277. package/src/runtime/http-types.ts +2 -0
  278. package/src/runtime/invite-redemption-service.ts +72 -12
  279. package/src/runtime/invite-service.ts +43 -0
  280. package/src/runtime/middleware/twilio-validation.ts +1 -1
  281. package/src/runtime/pending-interactions.ts +2 -2
  282. package/src/runtime/routes/brain-graph-routes.ts +10 -90
  283. package/src/runtime/routes/btw-routes.ts +10 -5
  284. package/src/runtime/routes/conversation-routes.ts +56 -11
  285. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
  286. package/src/runtime/routes/integrations/slack/channel.ts +2 -2
  287. package/src/runtime/routes/integrations/telegram.ts +2 -2
  288. package/src/runtime/routes/integrations/twilio.ts +17 -17
  289. package/src/runtime/routes/invite-routes.ts +29 -4
  290. package/src/runtime/routes/memory-item-routes.test.ts +754 -0
  291. package/src/runtime/routes/memory-item-routes.ts +503 -0
  292. package/src/runtime/routes/secret-routes.ts +17 -0
  293. package/src/runtime/routes/session-management-routes.ts +3 -3
  294. package/src/runtime/routes/settings-routes.ts +3 -3
  295. package/src/runtime/routes/trust-rules-routes.ts +14 -0
  296. package/src/runtime/routes/workspace-routes.ts +9 -4
  297. package/src/runtime/routes/workspace-utils.ts +8 -2
  298. package/src/schedule/integration-status.ts +26 -19
  299. package/src/security/keychain-broker-client.ts +17 -4
  300. package/src/security/oauth2.ts +6 -7
  301. package/src/security/secure-keys.ts +44 -19
  302. package/src/security/token-manager.ts +46 -39
  303. package/src/services/vercel-deploy.ts +0 -24
  304. package/src/signals/confirm.ts +78 -0
  305. package/src/signals/mcp-reload.ts +18 -0
  306. package/src/skills/catalog-install.ts +74 -18
  307. package/src/skills/skillssh-registry.ts +503 -0
  308. package/src/tools/assets/search.ts +5 -1
  309. package/src/tools/computer-use/definitions.ts +0 -10
  310. package/src/tools/computer-use/registry.ts +1 -1
  311. package/src/tools/credentials/vault.ts +22 -7
  312. package/src/tools/memory/definitions.ts +4 -13
  313. package/src/tools/memory/handlers.test.ts +83 -103
  314. package/src/tools/memory/handlers.ts +50 -85
  315. package/src/tools/network/script-proxy/session-manager.ts +8 -8
  316. package/src/tools/schedule/create.ts +10 -3
  317. package/src/tools/schedule/update.ts +8 -1
  318. package/src/tools/skills/load.ts +25 -2
  319. package/src/watcher/provider-types.ts +1 -1
  320. package/src/watcher/providers/github.ts +1 -1
  321. package/src/watcher/providers/gmail.ts +3 -3
  322. package/src/watcher/providers/google-calendar.ts +3 -3
  323. package/src/watcher/providers/linear.ts +1 -1
  324. package/src/__tests__/clarification-resolver.test.ts +0 -193
  325. package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
  326. package/src/__tests__/conflict-policy.test.ts +0 -269
  327. package/src/__tests__/conflict-store.test.ts +0 -372
  328. package/src/__tests__/contradiction-checker.test.ts +0 -361
  329. package/src/__tests__/entity-extractor.test.ts +0 -211
  330. package/src/__tests__/entity-search.test.ts +0 -1117
  331. package/src/__tests__/profile-compiler.test.ts +0 -392
  332. package/src/__tests__/session-conflict-gate.test.ts +0 -1228
  333. package/src/__tests__/session-profile-injection.test.ts +0 -557
  334. package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
  335. package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
  336. package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
  337. package/src/daemon/session-conflict-gate.ts +0 -167
  338. package/src/daemon/session-dynamic-profile.ts +0 -77
  339. package/src/memory/clarification-resolver.ts +0 -417
  340. package/src/memory/conflict-intent.ts +0 -205
  341. package/src/memory/conflict-policy.ts +0 -127
  342. package/src/memory/conflict-store.ts +0 -410
  343. package/src/memory/contradiction-checker.ts +0 -508
  344. package/src/memory/entity-extractor.ts +0 -535
  345. package/src/memory/format-recall.ts +0 -47
  346. package/src/memory/fts-reconciler.ts +0 -165
  347. package/src/memory/job-handlers/conflict.ts +0 -200
  348. package/src/memory/profile-compiler.ts +0 -195
  349. package/src/memory/recall-cache.ts +0 -117
  350. package/src/memory/search/entity.ts +0 -535
  351. package/src/memory/search/query-expansion.test.ts +0 -70
  352. package/src/memory/search/query-expansion.ts +0 -118
  353. package/src/runtime/routes/mcp-routes.ts +0 -20
@@ -429,7 +429,10 @@ describe("assistant credentials CLI", () => {
429
429
 
430
430
  const inspectResult = await runCli([
431
431
  "inspect",
432
- "twilio:account_sid",
432
+ "--service",
433
+ "twilio",
434
+ "--field",
435
+ "account_sid",
433
436
  "--json",
434
437
  ]);
435
438
  const inspectParsed = JSON.parse(inspectResult.stdout);
@@ -448,7 +451,10 @@ describe("assistant credentials CLI", () => {
448
451
  test("stores secret and creates metadata", async () => {
449
452
  const result = await runCli([
450
453
  "set",
451
- "twilio:account_sid",
454
+ "--service",
455
+ "twilio",
456
+ "--field",
457
+ "account_sid",
452
458
  "AC1234567890",
453
459
  "--json",
454
460
  ]);
@@ -476,7 +482,10 @@ describe("assistant credentials CLI", () => {
476
482
  test("stores metadata with --label and --description", async () => {
477
483
  const result = await runCli([
478
484
  "set",
479
- "fal:api_key",
485
+ "--service",
486
+ "fal",
487
+ "--field",
488
+ "api_key",
480
489
  "key_live_abc",
481
490
  "--label",
482
491
  "fal-prod",
@@ -496,34 +505,39 @@ describe("assistant credentials CLI", () => {
496
505
  expect(meta!.usageDescription).toBe("Image generation");
497
506
  });
498
507
 
499
- test("rejects invalid name without colon", async () => {
508
+ test("errors when --service flag is missing", async () => {
500
509
  const result = await runCli([
501
510
  "set",
502
- "invalid_name",
511
+ "--field",
512
+ "account_sid",
503
513
  "some_value",
504
514
  "--json",
505
515
  ]);
506
- expect(result.exitCode).toBe(1);
507
- const parsed = JSON.parse(result.stdout);
508
- expect(parsed.ok).toBe(false);
509
- expect(parsed.error).toContain("Invalid credential name");
510
- expect(parsed.error).toContain("service:field");
516
+ // Commander should error on missing required option
517
+ expect(result.exitCode).not.toBe(0);
511
518
  });
512
519
 
513
- test("rejects name with leading colon", async () => {
520
+ test("errors when --field flag is missing", async () => {
514
521
  const result = await runCli([
515
522
  "set",
516
- ":field_only",
523
+ "--service",
524
+ "twilio",
517
525
  "some_value",
518
526
  "--json",
519
527
  ]);
520
- expect(result.exitCode).toBe(1);
521
- const parsed = JSON.parse(result.stdout);
522
- expect(parsed.ok).toBe(false);
528
+ // Commander should error on missing required option
529
+ expect(result.exitCode).not.toBe(0);
523
530
  });
524
531
 
525
532
  test("errors when value argument is missing", async () => {
526
- const result = await runCli(["set", "twilio:account_sid", "--json"]);
533
+ const result = await runCli([
534
+ "set",
535
+ "--service",
536
+ "twilio",
537
+ "--field",
538
+ "account_sid",
539
+ "--json",
540
+ ]);
527
541
  // Commander should error on missing required arg
528
542
  expect(result.exitCode).not.toBe(0);
529
543
  });
@@ -531,7 +545,10 @@ describe("assistant credentials CLI", () => {
531
545
  test("stores metadata with --allowed-tools", async () => {
532
546
  const result = await runCli([
533
547
  "set",
534
- "twilio:auth_token",
548
+ "--service",
549
+ "twilio",
550
+ "--field",
551
+ "auth_token",
535
552
  "sometoken",
536
553
  "--allowed-tools",
537
554
  "bash,host_bash",
@@ -550,7 +567,15 @@ describe("assistant credentials CLI", () => {
550
567
 
551
568
  test("updates existing credential on second set", async () => {
552
569
  // First set
553
- await runCli(["set", "twilio:account_sid", "original_value", "--json"]);
570
+ await runCli([
571
+ "set",
572
+ "--service",
573
+ "twilio",
574
+ "--field",
575
+ "account_sid",
576
+ "original_value",
577
+ "--json",
578
+ ]);
554
579
  const meta1 = metadataStore.find(
555
580
  (m) => m.service === "twilio" && m.field === "account_sid",
556
581
  );
@@ -561,7 +586,15 @@ describe("assistant credentials CLI", () => {
561
586
  await new Promise((resolve) => setTimeout(resolve, 5));
562
587
 
563
588
  // Second set
564
- await runCli(["set", "twilio:account_sid", "new_value", "--json"]);
589
+ await runCli([
590
+ "set",
591
+ "--service",
592
+ "twilio",
593
+ "--field",
594
+ "account_sid",
595
+ "new_value",
596
+ "--json",
597
+ ]);
565
598
  const meta2 = metadataStore.find(
566
599
  (m) => m.service === "twilio" && m.field === "account_sid",
567
600
  );
@@ -583,7 +616,14 @@ describe("assistant credentials CLI", () => {
583
616
  test("removes both secret and metadata", async () => {
584
617
  seedCredential("twilio", "auth_token", "secret_value_here");
585
618
 
586
- const result = await runCli(["delete", "twilio:auth_token", "--json"]);
619
+ const result = await runCli([
620
+ "delete",
621
+ "--service",
622
+ "twilio",
623
+ "--field",
624
+ "auth_token",
625
+ "--json",
626
+ ]);
587
627
  expect(result.exitCode).toBe(0);
588
628
  const parsed = JSON.parse(result.stdout);
589
629
  expect(parsed.ok).toBe(true);
@@ -602,26 +642,48 @@ describe("assistant credentials CLI", () => {
602
642
  });
603
643
 
604
644
  test("errors on nonexistent credential", async () => {
605
- const result = await runCli(["delete", "twilio:nonexistent", "--json"]);
645
+ const result = await runCli([
646
+ "delete",
647
+ "--service",
648
+ "twilio",
649
+ "--field",
650
+ "nonexistent",
651
+ "--json",
652
+ ]);
606
653
  expect(result.exitCode).toBe(1);
607
654
  const parsed = JSON.parse(result.stdout);
608
655
  expect(parsed.ok).toBe(false);
609
656
  expect(parsed.error).toContain("not found");
610
657
  });
611
658
 
612
- test("rejects invalid name without colon", async () => {
613
- const result = await runCli(["delete", "badname", "--json"]);
614
- expect(result.exitCode).toBe(1);
615
- const parsed = JSON.parse(result.stdout);
616
- expect(parsed.ok).toBe(false);
617
- expect(parsed.error).toContain("Invalid credential name");
618
- expect(parsed.error).toContain("service:field");
659
+ test("errors when --service flag is missing", async () => {
660
+ const result = await runCli([
661
+ "delete",
662
+ "--field",
663
+ "auth_token",
664
+ "--json",
665
+ ]);
666
+ // Commander should error on missing required option
667
+ expect(result.exitCode).not.toBe(0);
668
+ });
669
+
670
+ test("errors when --field flag is missing", async () => {
671
+ const result = await runCli(["delete", "--service", "twilio", "--json"]);
672
+ // Commander should error on missing required option
673
+ expect(result.exitCode).not.toBe(0);
619
674
  });
620
675
 
621
676
  test("succeeds when only metadata exists (no secret)", async () => {
622
677
  seedMetadataOnly("twilio", "auth_token");
623
678
 
624
- const result = await runCli(["delete", "twilio:auth_token", "--json"]);
679
+ const result = await runCli([
680
+ "delete",
681
+ "--service",
682
+ "twilio",
683
+ "--field",
684
+ "auth_token",
685
+ "--json",
686
+ ]);
625
687
  expect(result.exitCode).toBe(0);
626
688
  const parsed = JSON.parse(result.stdout);
627
689
  expect(parsed.ok).toBe(true);
@@ -637,7 +699,14 @@ describe("assistant credentials CLI", () => {
637
699
  test("calls disconnectOAuthProvider for OAuth cleanup", async () => {
638
700
  seedCredential("gmail", "access_token", "ya29.token_value");
639
701
 
640
- const result = await runCli(["delete", "gmail:access_token", "--json"]);
702
+ const result = await runCli([
703
+ "delete",
704
+ "--service",
705
+ "gmail",
706
+ "--field",
707
+ "access_token",
708
+ "--json",
709
+ ]);
641
710
  expect(result.exitCode).toBe(0);
642
711
  const parsed = JSON.parse(result.stdout);
643
712
  expect(parsed.ok).toBe(true);
@@ -650,7 +719,14 @@ describe("assistant credentials CLI", () => {
650
719
  // No legacy credential seeded — only the OAuth disconnect finds something
651
720
  disconnectOAuthProviderResult = "disconnected";
652
721
 
653
- const result = await runCli(["delete", "gmail:access_token", "--json"]);
722
+ const result = await runCli([
723
+ "delete",
724
+ "--service",
725
+ "gmail",
726
+ "--field",
727
+ "access_token",
728
+ "--json",
729
+ ]);
654
730
  expect(result.exitCode).toBe(0);
655
731
  const parsed = JSON.parse(result.stdout);
656
732
  expect(parsed.ok).toBe(true);
@@ -659,29 +735,6 @@ describe("assistant credentials CLI", () => {
659
735
 
660
736
  expect(disconnectOAuthProviderCalls).toEqual(["gmail"]);
661
737
  });
662
-
663
- test("demonstrates colon-in-service-name parsing limitation with integration:gmail", async () => {
664
- // parseCredentialName("integration:gmail:access_token") splits on the
665
- // first colon, yielding service="integration" and field="gmail:access_token".
666
- // This is incorrect for the intended service "integration:gmail". The fix
667
- // for this limitation is addressed by introducing a dedicated `disconnect`
668
- // subcommand (PR 5).
669
- const result = await runCli([
670
- "delete",
671
- "integration:gmail:access_token",
672
- "--json",
673
- ]);
674
- // The command parses as service="integration", field="gmail:access_token"
675
- // which finds nothing and reports not-found.
676
- expect(result.exitCode).toBe(1);
677
- const parsed = JSON.parse(result.stdout);
678
- expect(parsed.ok).toBe(false);
679
- expect(parsed.error).toContain("not found");
680
-
681
- // disconnectOAuthProvider was called with "integration" (wrong) instead
682
- // of "integration:gmail" (intended).
683
- expect(disconnectOAuthProviderCalls).toEqual(["integration"]);
684
- });
685
738
  });
686
739
 
687
740
  // =========================================================================
@@ -689,10 +742,17 @@ describe("assistant credentials CLI", () => {
689
742
  // =========================================================================
690
743
 
691
744
  describe("inspect", () => {
692
- test("shows metadata and scrubbed value by service:field", async () => {
745
+ test("shows metadata and scrubbed value by --service/--field", async () => {
693
746
  const meta = seedCredential("twilio", "account_sid", "AC123456789012");
694
747
 
695
- const result = await runCli(["inspect", "twilio:account_sid", "--json"]);
748
+ const result = await runCli([
749
+ "inspect",
750
+ "--service",
751
+ "twilio",
752
+ "--field",
753
+ "account_sid",
754
+ "--json",
755
+ ]);
696
756
  expect(result.exitCode).toBe(0);
697
757
  const parsed = JSON.parse(result.stdout);
698
758
  expect(parsed.ok).toBe(true);
@@ -727,7 +787,14 @@ describe("assistant credentials CLI", () => {
727
787
  test("scrubs normal-length secret (>4 chars): shows last 4", async () => {
728
788
  seedCredential("test", "normal", "abcdefgh");
729
789
 
730
- const result = await runCli(["inspect", "test:normal", "--json"]);
790
+ const result = await runCli([
791
+ "inspect",
792
+ "--service",
793
+ "test",
794
+ "--field",
795
+ "normal",
796
+ "--json",
797
+ ]);
731
798
  const parsed = JSON.parse(result.stdout);
732
799
  expect(parsed.scrubbedValue).toBe("****efgh");
733
800
  });
@@ -735,7 +802,14 @@ describe("assistant credentials CLI", () => {
735
802
  test("scrubs short secret (<=4 chars): shows only ****", async () => {
736
803
  seedCredential("test", "short", "ab");
737
804
 
738
- const result = await runCli(["inspect", "test:short", "--json"]);
805
+ const result = await runCli([
806
+ "inspect",
807
+ "--service",
808
+ "test",
809
+ "--field",
810
+ "short",
811
+ "--json",
812
+ ]);
739
813
  const parsed = JSON.parse(result.stdout);
740
814
  expect(parsed.scrubbedValue).toBe("****");
741
815
  });
@@ -743,32 +817,49 @@ describe("assistant credentials CLI", () => {
743
817
  test("shows (not set) when no secret exists", async () => {
744
818
  seedMetadataOnly("test", "nosecret");
745
819
 
746
- const result = await runCli(["inspect", "test:nosecret", "--json"]);
820
+ const result = await runCli([
821
+ "inspect",
822
+ "--service",
823
+ "test",
824
+ "--field",
825
+ "nosecret",
826
+ "--json",
827
+ ]);
747
828
  const parsed = JSON.parse(result.stdout);
748
829
  expect(parsed.ok).toBe(true);
749
830
  expect(parsed.scrubbedValue).toBe("(not set)");
750
831
  expect(parsed.hasSecret).toBe(false);
751
832
  });
752
833
 
753
- test("rejects invalid name without colon", async () => {
754
- const result = await runCli(["inspect", "badname", "--json"]);
834
+ test("errors when neither flags nor UUID provided", async () => {
835
+ const result = await runCli(["inspect", "--json"]);
755
836
  expect(result.exitCode).toBe(1);
756
837
  const parsed = JSON.parse(result.stdout);
757
838
  expect(parsed.ok).toBe(false);
758
- expect(parsed.error).toContain("not found");
839
+ expect(parsed.error).toContain("--service");
759
840
  });
760
841
 
761
- test("rejects name with leading colon", async () => {
762
- const result = await runCli(["inspect", ":field_only", "--json"]);
842
+ test("errors on nonexistent credential by --service/--field", async () => {
843
+ const result = await runCli([
844
+ "inspect",
845
+ "--service",
846
+ "nonexistent",
847
+ "--field",
848
+ "field",
849
+ "--json",
850
+ ]);
763
851
  expect(result.exitCode).toBe(1);
764
852
  const parsed = JSON.parse(result.stdout);
765
853
  expect(parsed.ok).toBe(false);
766
- expect(parsed.error).toContain("Invalid credential name");
767
- expect(parsed.error).toContain("service:field");
854
+ expect(parsed.error).toContain("not found");
768
855
  });
769
856
 
770
- test("errors on nonexistent credential", async () => {
771
- const result = await runCli(["inspect", "nonexistent:field", "--json"]);
857
+ test("errors on nonexistent UUID", async () => {
858
+ const result = await runCli([
859
+ "inspect",
860
+ "00000000-0000-0000-0000-000000000099",
861
+ "--json",
862
+ ]);
772
863
  expect(result.exitCode).toBe(1);
773
864
  const parsed = JSON.parse(result.stdout);
774
865
  expect(parsed.ok).toBe(false);
@@ -778,7 +869,14 @@ describe("assistant credentials CLI", () => {
778
869
  test("--json flag produces compact JSON (single line)", async () => {
779
870
  seedCredential("twilio", "account_sid", "AC123456789012");
780
871
 
781
- const result = await runCli(["inspect", "twilio:account_sid", "--json"]);
872
+ const result = await runCli([
873
+ "inspect",
874
+ "--service",
875
+ "twilio",
876
+ "--field",
877
+ "account_sid",
878
+ "--json",
879
+ ]);
782
880
  const lines = result.stdout.trim().split("\n");
783
881
  expect(lines).toHaveLength(1);
784
882
  // Verify it parses as valid JSON
@@ -788,7 +886,14 @@ describe("assistant credentials CLI", () => {
788
886
  test("shows hasSecret: false when metadata exists but no secret", async () => {
789
887
  seedMetadataOnly("test", "metaonly");
790
888
 
791
- const result = await runCli(["inspect", "test:metaonly", "--json"]);
889
+ const result = await runCli([
890
+ "inspect",
891
+ "--service",
892
+ "test",
893
+ "--field",
894
+ "metaonly",
895
+ "--json",
896
+ ]);
792
897
  const parsed = JSON.parse(result.stdout);
793
898
  expect(parsed.ok).toBe(true);
794
899
  expect(parsed.hasSecret).toBe(false);
@@ -801,10 +906,17 @@ describe("assistant credentials CLI", () => {
801
906
  // =========================================================================
802
907
 
803
908
  describe("reveal", () => {
804
- test("returns plaintext value by service:field", async () => {
909
+ test("returns plaintext value by --service/--field", async () => {
805
910
  seedCredential("twilio", "account_sid", "AC123456789012");
806
911
 
807
- const result = await runCli(["reveal", "twilio:account_sid", "--json"]);
912
+ const result = await runCli([
913
+ "reveal",
914
+ "--service",
915
+ "twilio",
916
+ "--field",
917
+ "account_sid",
918
+ "--json",
919
+ ]);
808
920
  expect(result.exitCode).toBe(0);
809
921
  const parsed = JSON.parse(result.stdout);
810
922
  expect(parsed.ok).toBe(true);
@@ -821,8 +933,15 @@ describe("assistant credentials CLI", () => {
821
933
  expect(parsed.value).toBe("ghp_abcdefghij1234");
822
934
  });
823
935
 
824
- test("errors on nonexistent credential", async () => {
825
- const result = await runCli(["reveal", "nonexistent:field", "--json"]);
936
+ test("errors on nonexistent credential by --service/--field", async () => {
937
+ const result = await runCli([
938
+ "reveal",
939
+ "--service",
940
+ "nonexistent",
941
+ "--field",
942
+ "field",
943
+ "--json",
944
+ ]);
826
945
  expect(result.exitCode).toBe(1);
827
946
  const parsed = JSON.parse(result.stdout);
828
947
  expect(parsed.ok).toBe(false);
@@ -841,18 +960,24 @@ describe("assistant credentials CLI", () => {
841
960
  expect(parsed.error).toContain("not found");
842
961
  });
843
962
 
844
- test("rejects invalid name without colon", async () => {
845
- const result = await runCli(["reveal", ":field_only", "--json"]);
963
+ test("errors when neither flags nor UUID provided", async () => {
964
+ const result = await runCli(["reveal", "--json"]);
846
965
  expect(result.exitCode).toBe(1);
847
966
  const parsed = JSON.parse(result.stdout);
848
967
  expect(parsed.ok).toBe(false);
849
- expect(parsed.error).toContain("Invalid credential name");
968
+ expect(parsed.error).toContain("--service");
850
969
  });
851
970
 
852
971
  test("reveal in human mode emits bare secret with trailing newline", async () => {
853
972
  seedCredential("twilio", "auth_token", "secret_xyz_789");
854
973
 
855
- const result = await runCli(["reveal", "twilio:auth_token"]);
974
+ const result = await runCli([
975
+ "reveal",
976
+ "--service",
977
+ "twilio",
978
+ "--field",
979
+ "auth_token",
980
+ ]);
856
981
  expect(result.exitCode).toBe(0);
857
982
  expect(result.stdout).toBe("secret_xyz_789\n");
858
983
  });
@@ -860,7 +985,14 @@ describe("assistant credentials CLI", () => {
860
985
  test("errors when metadata exists but no secret stored", async () => {
861
986
  seedMetadataOnly("test", "nosecret");
862
987
 
863
- const result = await runCli(["reveal", "test:nosecret", "--json"]);
988
+ const result = await runCli([
989
+ "reveal",
990
+ "--service",
991
+ "test",
992
+ "--field",
993
+ "nosecret",
994
+ "--json",
995
+ ]);
864
996
  expect(result.exitCode).toBe(1);
865
997
  const parsed = JSON.parse(result.stdout);
866
998
  expect(parsed.ok).toBe(false);
@@ -868,6 +1000,42 @@ describe("assistant credentials CLI", () => {
868
1000
  });
869
1001
  });
870
1002
 
1003
+ // =========================================================================
1004
+ // compound service names (colons in service)
1005
+ // =========================================================================
1006
+
1007
+ describe("compound service names", () => {
1008
+ test("set and reveal with colon in service name works correctly", async () => {
1009
+ const setResult = await runCli([
1010
+ "set",
1011
+ "--service",
1012
+ "integration:google",
1013
+ "--field",
1014
+ "client_secret",
1015
+ "secret123",
1016
+ "--json",
1017
+ ]);
1018
+ expect(setResult.exitCode).toBe(0);
1019
+ const setParsed = JSON.parse(setResult.stdout);
1020
+ expect(setParsed.ok).toBe(true);
1021
+ expect(setParsed.service).toBe("integration:google");
1022
+ expect(setParsed.field).toBe("client_secret");
1023
+
1024
+ const revealResult = await runCli([
1025
+ "reveal",
1026
+ "--service",
1027
+ "integration:google",
1028
+ "--field",
1029
+ "client_secret",
1030
+ "--json",
1031
+ ]);
1032
+ expect(revealResult.exitCode).toBe(0);
1033
+ const revealParsed = JSON.parse(revealResult.stdout);
1034
+ expect(revealParsed.ok).toBe(true);
1035
+ expect(revealParsed.value).toBe("secret123");
1036
+ });
1037
+ });
1038
+
871
1039
  // =========================================================================
872
1040
  // instance-scoped BASE_DATA_DIR
873
1041
  // =========================================================================
@@ -899,8 +1067,15 @@ describe("assistant credentials CLI", () => {
899
1067
  // Seed a credential in the mock store
900
1068
  seedCredential("twilio", "auth_token", "instance_secret_abc123");
901
1069
 
902
- // Run `credentials reveal twilio:auth_token`
903
- const result = await runCli(["reveal", "twilio:auth_token", "--json"]);
1070
+ // Run `credentials reveal --service twilio --field auth_token`
1071
+ const result = await runCli([
1072
+ "reveal",
1073
+ "--service",
1074
+ "twilio",
1075
+ "--field",
1076
+ "auth_token",
1077
+ "--json",
1078
+ ]);
904
1079
  expect(result.exitCode).toBe(0);
905
1080
  const parsed = JSON.parse(result.stdout);
906
1081
  expect(parsed.ok).toBe(true);
@@ -924,7 +1099,7 @@ describe("assistant credentials CLI", () => {
924
1099
  test("credentials --help contains naming convention table and storage description", async () => {
925
1100
  const result = await runCli(["--help"]);
926
1101
  const out = result.stdout;
927
- expect(out).toContain("twilio:account_sid");
1102
+ expect(out).toContain("--service twilio --field account_sid");
928
1103
  expect(out).toContain("AES-256-GCM");
929
1104
  expect(out).toContain("Examples:");
930
1105
  });