@vellumai/assistant 0.5.9 → 0.5.11

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 (278) hide show
  1. package/AGENTS.md +9 -1
  2. package/ARCHITECTURE.md +48 -48
  3. package/Dockerfile +2 -0
  4. package/README.md +1 -1
  5. package/docs/architecture/integrations.md +6 -13
  6. package/docs/architecture/memory.md +7 -12
  7. package/docs/architecture/security.md +5 -5
  8. package/docs/credential-execution-service.md +9 -9
  9. package/docs/skills.md +1 -1
  10. package/node_modules/@vellumai/credential-storage/src/index.ts +2 -2
  11. package/node_modules/@vellumai/credential-storage/src/static-credentials.ts +1 -1
  12. package/openapi.yaml +7130 -0
  13. package/package.json +2 -1
  14. package/scripts/generate-openapi.ts +562 -0
  15. package/src/__tests__/acp-session.test.ts +239 -44
  16. package/src/__tests__/assistant-feature-flag-guard.test.ts +8 -8
  17. package/src/__tests__/assistant-feature-flag-guardrails.test.ts +5 -86
  18. package/src/__tests__/assistant-feature-flags-integration.test.ts +7 -14
  19. package/src/__tests__/browser-skill-endstate.test.ts +1 -1
  20. package/src/__tests__/btw-routes.test.ts +8 -0
  21. package/src/__tests__/bundled-skill-retrieval-guard.test.ts +10 -10
  22. package/src/__tests__/channel-approvals.test.ts +7 -7
  23. package/src/__tests__/channel-readiness-service.test.ts +41 -0
  24. package/src/__tests__/config-schema.test.ts +10 -2
  25. package/src/__tests__/context-memory-e2e.test.ts +2 -6
  26. package/src/__tests__/conversation-skill-tools.test.ts +1 -3
  27. package/src/__tests__/conversation-title-service.test.ts +2 -15
  28. package/src/__tests__/credential-execution-feature-gates.test.ts +4 -8
  29. package/src/__tests__/credential-execution-managed-contract.test.ts +8 -8
  30. package/src/__tests__/credential-security-e2e.test.ts +4 -4
  31. package/src/__tests__/credential-security-invariants.test.ts +3 -3
  32. package/src/__tests__/credentials-cli.test.ts +3 -3
  33. package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +1 -1
  34. package/src/__tests__/gateway-only-guard.test.ts +3 -0
  35. package/src/__tests__/heartbeat-service.test.ts +35 -0
  36. package/src/__tests__/host-shell-tool.test.ts +1 -1
  37. package/src/__tests__/inline-skill-load-permissions.test.ts +3 -3
  38. package/src/__tests__/llm-request-log-turn-query.test.ts +64 -0
  39. package/src/__tests__/log-export-workspace.test.ts +1 -1
  40. package/src/__tests__/mcp-client-auth.test.ts +1 -1
  41. package/src/__tests__/memory-lifecycle-e2e.test.ts +2 -2
  42. package/src/__tests__/memory-recall-log-store.test.ts +182 -0
  43. package/src/__tests__/memory-recall-quality.test.ts +6 -8
  44. package/src/__tests__/memory-regressions.test.ts +53 -42
  45. package/src/__tests__/memory-retrieval.benchmark.test.ts +5 -9
  46. package/src/__tests__/messaging-skill-split.test.ts +2 -17
  47. package/src/__tests__/oauth-cli.test.ts +98 -551
  48. package/src/__tests__/platform-callback-registration.test.ts +119 -0
  49. package/src/__tests__/secret-ingress-channel.test.ts +261 -0
  50. package/src/__tests__/secret-ingress-cli.test.ts +201 -0
  51. package/src/__tests__/secret-ingress-http.test.ts +312 -0
  52. package/src/__tests__/secret-ingress.test.ts +283 -0
  53. package/src/__tests__/secret-onetime-send.test.ts +4 -4
  54. package/src/__tests__/skill-feature-flags-integration.test.ts +4 -4
  55. package/src/__tests__/skill-feature-flags.test.ts +11 -19
  56. package/src/__tests__/skill-load-feature-flag.test.ts +1 -1
  57. package/src/__tests__/skill-load-inline-command.test.ts +3 -3
  58. package/src/__tests__/skill-load-inline-includes.test.ts +2 -2
  59. package/src/__tests__/skill-memory.test.ts +2 -4
  60. package/src/__tests__/skill-projection-feature-flag.test.ts +2 -4
  61. package/src/__tests__/skill-projection.benchmark.test.ts +1 -3
  62. package/src/__tests__/skills.test.ts +16 -2
  63. package/src/__tests__/slack-channel-config.test.ts +1 -1
  64. package/src/__tests__/slack-skill.test.ts +5 -69
  65. package/src/__tests__/vellum-self-knowledge-inline-command.test.ts +1 -1
  66. package/src/__tests__/workspace-migration-015-migrate-credentials-to-keychain.test.ts +5 -238
  67. package/src/__tests__/workspace-migration-016-migrate-credentials-from-keychain.test.ts +5 -206
  68. package/src/__tests__/workspace-migration-018-rekey-compound-credential-keys.test.ts +181 -0
  69. package/src/__tests__/workspace-migrations-runner.test.ts +15 -7
  70. package/src/acp/client-handler.ts +113 -31
  71. package/src/acp/session-manager.ts +29 -27
  72. package/src/approvals/guardian-request-resolvers.ts +1 -1
  73. package/src/cli/AGENTS.md +73 -0
  74. package/src/cli/commands/autonomy.ts +3 -5
  75. package/src/cli/commands/credential-execution.ts +1 -2
  76. package/src/cli/commands/credentials.ts +4 -4
  77. package/src/cli/commands/memory.ts +2 -3
  78. package/src/cli/commands/oauth/__tests__/connect.test.ts +785 -0
  79. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +760 -0
  80. package/src/cli/commands/oauth/__tests__/mode.test.ts +672 -0
  81. package/src/cli/commands/oauth/__tests__/ping.test.ts +690 -0
  82. package/src/cli/commands/oauth/__tests__/status.test.ts +579 -0
  83. package/src/cli/commands/oauth/__tests__/token.test.ts +467 -0
  84. package/src/cli/commands/oauth/apps.ts +29 -11
  85. package/src/cli/commands/oauth/connect.ts +373 -0
  86. package/src/cli/commands/oauth/connections.ts +14 -493
  87. package/src/cli/commands/oauth/disconnect.ts +333 -0
  88. package/src/cli/commands/oauth/index.ts +62 -10
  89. package/src/cli/commands/oauth/mode.ts +263 -0
  90. package/src/cli/commands/oauth/ping.ts +222 -0
  91. package/src/cli/commands/oauth/providers.ts +30 -3
  92. package/src/cli/commands/oauth/request.ts +576 -0
  93. package/src/cli/commands/oauth/shared.ts +132 -0
  94. package/src/cli/commands/oauth/status.ts +202 -0
  95. package/src/cli/commands/oauth/token.ts +159 -0
  96. package/src/cli/commands/platform.ts +20 -14
  97. package/src/cli.ts +82 -17
  98. package/src/config/assistant-feature-flags.ts +74 -11
  99. package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
  100. package/src/config/bundled-skills/app-builder/tools/app-create.ts +1 -1
  101. package/src/config/bundled-skills/messaging/SKILL.md +13 -36
  102. package/src/config/bundled-skills/messaging/TOOLS.json +9 -9
  103. package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +1 -1
  104. package/src/config/bundled-skills/notifications/SKILL.md +1 -1
  105. package/src/config/bundled-skills/schedule/SKILL.md +2 -2
  106. package/src/config/bundled-skills/settings/SKILL.md +5 -3
  107. package/src/config/bundled-skills/settings/TOOLS.json +17 -0
  108. package/src/config/bundled-skills/settings/tools/avatar-get.ts +50 -0
  109. package/src/config/bundled-skills/settings/tools/avatar-remove.ts +7 -0
  110. package/src/config/bundled-skills/settings/tools/avatar-update.ts +6 -1
  111. package/src/config/bundled-skills/settings/tools/identity-avatar.ts +55 -0
  112. package/src/config/bundled-skills/skills-catalog/SKILL.md +3 -3
  113. package/src/config/bundled-skills/slack/SKILL.md +58 -44
  114. package/src/config/bundled-tool-registry.ts +2 -19
  115. package/src/config/env.ts +5 -1
  116. package/src/config/feature-flag-registry.json +57 -41
  117. package/src/config/loader.ts +4 -0
  118. package/src/config/schemas/platform.ts +0 -8
  119. package/src/config/schemas/security.ts +9 -1
  120. package/src/config/schemas/services.ts +1 -1
  121. package/src/config/skill-state.ts +1 -3
  122. package/src/config/skills.ts +2 -4
  123. package/src/credential-execution/feature-gates.ts +9 -16
  124. package/src/credential-execution/process-manager.ts +12 -0
  125. package/src/daemon/config-watcher.ts +4 -0
  126. package/src/daemon/conversation-agent-loop-handlers.ts +10 -0
  127. package/src/daemon/conversation-agent-loop.ts +49 -2
  128. package/src/daemon/conversation-memory.ts +0 -1
  129. package/src/daemon/handlers/config-slack-channel.ts +43 -1
  130. package/src/daemon/handlers/conversations.ts +41 -33
  131. package/src/daemon/lifecycle.ts +28 -5
  132. package/src/daemon/message-types/acp.ts +0 -15
  133. package/src/daemon/message-types/memory.ts +0 -1
  134. package/src/daemon/message-types/messages.ts +9 -1
  135. package/src/daemon/message-types/schedules.ts +9 -0
  136. package/src/daemon/server.ts +19 -7
  137. package/src/email/feature-gate.ts +3 -3
  138. package/src/heartbeat/heartbeat-service.ts +48 -0
  139. package/src/inbound/platform-callback-registration.ts +61 -7
  140. package/src/mcp/mcp-oauth-provider.ts +3 -3
  141. package/src/memory/app-store.ts +3 -3
  142. package/src/memory/conversation-crud.ts +124 -0
  143. package/src/memory/conversation-title-service.ts +7 -17
  144. package/src/memory/db-init.ts +8 -0
  145. package/src/memory/embedding-local.ts +47 -2
  146. package/src/memory/indexer.ts +13 -10
  147. package/src/memory/items-extractor.ts +12 -4
  148. package/src/memory/job-utils.ts +5 -0
  149. package/src/memory/jobs-store.ts +10 -2
  150. package/src/memory/journal-memory.ts +6 -2
  151. package/src/memory/llm-request-log-store.ts +88 -21
  152. package/src/memory/memory-recall-log-store.ts +128 -0
  153. package/src/memory/migrations/194-memory-recall-logs.ts +50 -0
  154. package/src/memory/migrations/195-oauth-providers-ping-config.ts +23 -0
  155. package/src/memory/migrations/index.ts +2 -0
  156. package/src/memory/migrations/validate-migration-state.ts +14 -1
  157. package/src/memory/retriever.test.ts +4 -5
  158. package/src/memory/schema/infrastructure.ts +31 -0
  159. package/src/memory/schema/oauth.ts +3 -0
  160. package/src/messaging/providers/telegram-bot/adapter.ts +1 -1
  161. package/src/oauth/connect-orchestrator.ts +54 -0
  162. package/src/oauth/manual-token-connection.ts +5 -5
  163. package/src/oauth/oauth-store.ts +26 -5
  164. package/src/oauth/seed-providers.ts +10 -1
  165. package/src/permissions/checker.ts +2 -2
  166. package/src/permissions/trust-client.ts +2 -2
  167. package/src/platform/client.ts +2 -2
  168. package/src/prompts/journal-context.ts +6 -1
  169. package/src/providers/anthropic/client.ts +143 -1
  170. package/src/runtime/auth/__tests__/middleware.test.ts +19 -0
  171. package/src/runtime/auth/route-policy.ts +0 -1
  172. package/src/runtime/btw-sidechain.ts +7 -1
  173. package/src/runtime/channel-approvals.ts +2 -2
  174. package/src/runtime/channel-readiness-service.ts +30 -7
  175. package/src/runtime/http-router.ts +31 -0
  176. package/src/runtime/http-server.ts +21 -4
  177. package/src/runtime/http-types.ts +2 -0
  178. package/src/runtime/pending-interactions.ts +21 -3
  179. package/src/runtime/routes/acp-routes.ts +46 -28
  180. package/src/runtime/routes/app-management-routes.ts +123 -0
  181. package/src/runtime/routes/app-routes.ts +31 -0
  182. package/src/runtime/routes/approval-routes.ts +108 -3
  183. package/src/runtime/routes/attachment-routes.ts +45 -0
  184. package/src/runtime/routes/avatar-routes.ts +16 -0
  185. package/src/runtime/routes/brain-graph-routes.ts +18 -0
  186. package/src/runtime/routes/btw-routes.ts +20 -0
  187. package/src/runtime/routes/call-routes.ts +81 -0
  188. package/src/runtime/routes/channel-readiness-routes.ts +48 -7
  189. package/src/runtime/routes/channel-routes.ts +18 -0
  190. package/src/runtime/routes/channel-verification-routes.ts +49 -1
  191. package/src/runtime/routes/contact-routes.ts +77 -0
  192. package/src/runtime/routes/conversation-attention-routes.ts +37 -0
  193. package/src/runtime/routes/conversation-management-routes.ts +94 -0
  194. package/src/runtime/routes/conversation-query-routes.ts +78 -0
  195. package/src/runtime/routes/conversation-routes.ts +115 -38
  196. package/src/runtime/routes/conversation-starter-routes.ts +29 -0
  197. package/src/runtime/routes/debug-routes.ts +23 -0
  198. package/src/runtime/routes/diagnostics-routes.ts +30 -0
  199. package/src/runtime/routes/documents-routes.ts +42 -0
  200. package/src/runtime/routes/events-routes.ts +10 -0
  201. package/src/runtime/routes/global-search-routes.ts +35 -0
  202. package/src/runtime/routes/guardian-action-routes.ts +47 -2
  203. package/src/runtime/routes/guardian-approval-prompt.ts +77 -2
  204. package/src/runtime/routes/heartbeat-routes.ts +278 -0
  205. package/src/runtime/routes/host-bash-routes.ts +16 -1
  206. package/src/runtime/routes/host-cu-routes.ts +23 -1
  207. package/src/runtime/routes/host-file-routes.ts +18 -1
  208. package/src/runtime/routes/identity-routes.ts +35 -0
  209. package/src/runtime/routes/inbound-message-handler.ts +46 -25
  210. package/src/runtime/routes/inbound-stages/secret-ingress-check.ts +30 -2
  211. package/src/runtime/routes/inbound-stages/transcribe-audio.ts +1 -2
  212. package/src/runtime/routes/integrations/twilio.ts +32 -22
  213. package/src/runtime/routes/invite-routes.ts +83 -0
  214. package/src/runtime/routes/log-export-routes.ts +14 -0
  215. package/src/runtime/routes/memory-item-routes.ts +99 -1
  216. package/src/runtime/routes/migration-rollback-routes.ts +25 -0
  217. package/src/runtime/routes/migration-routes.ts +40 -0
  218. package/src/runtime/routes/notification-routes.ts +20 -0
  219. package/src/runtime/routes/oauth-apps.ts +11 -3
  220. package/src/runtime/routes/pairing-routes.ts +15 -0
  221. package/src/runtime/routes/recording-routes.ts +72 -0
  222. package/src/runtime/routes/schedule-routes.ts +77 -5
  223. package/src/runtime/routes/secret-routes.ts +63 -1
  224. package/src/runtime/routes/settings-routes.ts +91 -1
  225. package/src/runtime/routes/skills-routes.ts +98 -16
  226. package/src/runtime/routes/subagents-routes.ts +38 -3
  227. package/src/runtime/routes/surface-action-routes.ts +66 -24
  228. package/src/runtime/routes/surface-content-routes.ts +20 -0
  229. package/src/runtime/routes/telemetry-routes.ts +12 -0
  230. package/src/runtime/routes/trace-event-routes.ts +25 -0
  231. package/src/runtime/routes/trust-rules-routes.ts +46 -0
  232. package/src/runtime/routes/tts-routes.ts +15 -4
  233. package/src/runtime/routes/upgrade-broadcast-routes.ts +38 -0
  234. package/src/runtime/routes/usage-routes.ts +59 -0
  235. package/src/runtime/routes/watch-routes.ts +28 -0
  236. package/src/runtime/routes/work-items-routes.ts +59 -0
  237. package/src/runtime/routes/workspace-commit-routes.ts +12 -0
  238. package/src/runtime/routes/workspace-routes.ts +102 -0
  239. package/src/schedule/scheduler.ts +7 -1
  240. package/src/security/AGENTS.md +7 -0
  241. package/src/security/credential-backend.ts +1 -1
  242. package/src/security/encrypted-store.ts +3 -3
  243. package/src/security/oauth2.ts +55 -0
  244. package/src/security/secret-ingress.ts +174 -0
  245. package/src/security/secret-patterns.ts +133 -0
  246. package/src/security/secret-scanner.ts +28 -117
  247. package/src/signals/confirm.ts +12 -8
  248. package/src/signals/user-message.ts +18 -3
  249. package/src/skills/skill-memory.ts +1 -2
  250. package/src/tasks/task-runner.ts +7 -1
  251. package/src/tools/credentials/broker.ts +1 -1
  252. package/src/tools/credentials/metadata-store.ts +1 -1
  253. package/src/tools/credentials/vault.ts +2 -3
  254. package/src/tools/memory/definitions.ts +1 -1
  255. package/src/tools/memory/handlers.test.ts +2 -4
  256. package/src/tools/skills/load.ts +1 -1
  257. package/src/tools/terminal/safe-env.ts +7 -0
  258. package/src/tools/tool-manifest.ts +1 -1
  259. package/src/util/log-redact.ts +9 -34
  260. package/src/workspace/migrations/015-migrate-credentials-to-keychain.ts +13 -148
  261. package/src/workspace/migrations/016-migrate-credentials-from-keychain.ts +7 -145
  262. package/src/workspace/migrations/AGENTS.md +11 -0
  263. package/src/workspace/migrations/runner.ts +16 -6
  264. package/src/workspace/migrations/types.ts +7 -0
  265. package/docs/architecture/keychain-broker.md +0 -69
  266. package/src/__tests__/keychain-broker-client.test.ts +0 -800
  267. package/src/cli/commands/oauth/platform.ts +0 -525
  268. package/src/config/bundled-skills/slack/TOOLS.json +0 -272
  269. package/src/config/bundled-skills/slack/tools/shared.ts +0 -34
  270. package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +0 -27
  271. package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +0 -38
  272. package/src/config/bundled-skills/slack/tools/slack-channel-permissions.ts +0 -146
  273. package/src/config/bundled-skills/slack/tools/slack-configure-channels.ts +0 -105
  274. package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +0 -26
  275. package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +0 -27
  276. package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +0 -25
  277. package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +0 -372
  278. package/src/security/keychain-broker-client.ts +0 -446
@@ -0,0 +1,333 @@
1
+ import type { Command } from "commander";
2
+
3
+ import {
4
+ disconnectOAuthProvider,
5
+ getActiveConnection,
6
+ getConnection,
7
+ getProvider,
8
+ listActiveConnectionsByProvider,
9
+ } from "../../../oauth/oauth-store.js";
10
+ import { deleteCredentialMetadata } from "../../../tools/credentials/metadata-store.js";
11
+ import { deleteSecureKeyViaDaemon } from "../../lib/daemon-credential-client.js";
12
+ import { getCliLogger } from "../../logger.js";
13
+ import { shouldOutputJson, writeOutput } from "../../output.js";
14
+ import {
15
+ fetchActiveConnections,
16
+ isManagedMode,
17
+ requirePlatformClient,
18
+ resolveService,
19
+ toBareProvider,
20
+ } from "./shared.js";
21
+
22
+ const log = getCliLogger("cli");
23
+
24
+ // ---------------------------------------------------------------------------
25
+ // Command registration
26
+ // ---------------------------------------------------------------------------
27
+
28
+ export function registerDisconnectCommand(oauth: Command): void {
29
+ oauth
30
+ .command("disconnect <provider>")
31
+ .description(
32
+ "Disconnect an OAuth provider and remove associated credentials (auto-detects managed vs BYO mode)",
33
+ )
34
+ .option(
35
+ "--account <identifier>",
36
+ "Account identifier to disconnect (e.g. email address)",
37
+ )
38
+ .option("--connection-id <id>", "Exact connection ID to disconnect")
39
+ .addHelpText(
40
+ "after",
41
+ `
42
+ Arguments:
43
+ provider Provider name or key (e.g. google, integration:google, gmail).
44
+ Run 'assistant oauth providers list' to see available providers.
45
+
46
+ Options:
47
+ --account Recommended way to specify which connection to disconnect.
48
+ Works for both managed and BYO modes. Use the account
49
+ identifier shown by 'assistant oauth status <provider>'
50
+ (e.g. an email address for Google).
51
+ --connection-id Exact match on the connection ID shown by
52
+ 'assistant oauth status <provider>'. Useful when account
53
+ labels are ambiguous or absent.
54
+
55
+ At most one of --account or --connection-id may be specified.
56
+
57
+ Disambiguation:
58
+ When a provider has multiple active connections and neither --account nor
59
+ --connection-id is given, the command errors with a list of connections
60
+ (id + account label) and a hint to use --account or --connection-id.
61
+ Run 'assistant oauth status <provider>' to discover available values.
62
+
63
+ Examples:
64
+ $ assistant oauth disconnect google
65
+ $ assistant oauth disconnect google --account user@gmail.com
66
+ $ assistant oauth disconnect google --connection-id conn_abc123`,
67
+ )
68
+ .action(
69
+ async (
70
+ provider: string,
71
+ opts: { account?: string; connectionId?: string },
72
+ cmd: Command,
73
+ ) => {
74
+ const jsonMode = shouldOutputJson(cmd);
75
+
76
+ // Helper: write an error and set exit code
77
+ const writeError = (
78
+ error: string,
79
+ extra?: Record<string, unknown>,
80
+ ): void => {
81
+ writeOutput(cmd, { ok: false, error, ...extra });
82
+ process.exitCode = 1;
83
+ };
84
+
85
+ try {
86
+ // -------------------------------------------------------------------
87
+ // 1. Resolve + validate provider
88
+ // -------------------------------------------------------------------
89
+ const providerKey = resolveService(provider);
90
+
91
+ const providerRow = getProvider(providerKey);
92
+ if (!providerRow) {
93
+ writeError(
94
+ `Unknown provider "${provider}".\n\n` +
95
+ `Run 'assistant oauth providers list' to see available providers.\n` +
96
+ `If this is a custom provider, register it first with 'assistant oauth providers register --help'.`,
97
+ );
98
+ return;
99
+ }
100
+
101
+ // -------------------------------------------------------------------
102
+ // 2. Validate mutual exclusivity
103
+ // -------------------------------------------------------------------
104
+ if (opts.account && opts.connectionId) {
105
+ writeError(
106
+ `Cannot specify both --account and --connection-id. Use one or the other.\n\n` +
107
+ `Run 'assistant oauth status ${provider}' to see connected accounts and IDs.`,
108
+ );
109
+ return;
110
+ }
111
+
112
+ // -------------------------------------------------------------------
113
+ // 3. Detect mode
114
+ // -------------------------------------------------------------------
115
+ const managed = isManagedMode(providerKey);
116
+
117
+ if (managed) {
118
+ // -----------------------------------------------------------------
119
+ // Managed path
120
+ // -----------------------------------------------------------------
121
+ const client = await requirePlatformClient(cmd);
122
+ if (!client) return;
123
+
124
+ const entries = await fetchActiveConnections(
125
+ client,
126
+ providerKey,
127
+ cmd,
128
+ );
129
+ if (!entries) return;
130
+
131
+ let connectionId: string | undefined;
132
+ let accountLabel: string | undefined;
133
+
134
+ if (opts.account) {
135
+ // Filter connections by account_label matching the account value
136
+ const matching = entries.filter(
137
+ (c) => c.account_label === opts.account,
138
+ );
139
+ if (matching.length === 0) {
140
+ writeError(
141
+ `No active connection found for "${toBareProvider(providerKey)}" with account "${opts.account}".\n\n` +
142
+ `Run 'assistant oauth status ${provider}' to see connected accounts.`,
143
+ );
144
+ return;
145
+ }
146
+ connectionId = matching[0].id;
147
+ accountLabel = matching[0].account_label;
148
+ } else if (opts.connectionId) {
149
+ // Verify the supplied ID belongs to this provider
150
+ const match = entries.find((c) => c.id === opts.connectionId);
151
+ if (!match) {
152
+ writeError(
153
+ `Connection "${opts.connectionId}" is not an active ${toBareProvider(providerKey)} connection.\n\n` +
154
+ `Run 'assistant oauth status ${provider}' to see active connections.`,
155
+ );
156
+ return;
157
+ }
158
+ connectionId = match.id;
159
+ accountLabel = match.account_label;
160
+ } else {
161
+ // Neither specified — auto-resolve
162
+ if (entries.length === 0) {
163
+ writeError(
164
+ `No active connections found for "${toBareProvider(providerKey)}".\n\n` +
165
+ `Run 'assistant oauth status ${provider}' to check connection status.`,
166
+ );
167
+ return;
168
+ }
169
+
170
+ if (entries.length > 1) {
171
+ const connectionList = entries.map((c) => ({
172
+ id: c.id,
173
+ account: c.account_label ?? null,
174
+ }));
175
+ writeError(
176
+ `Multiple active connections for "${toBareProvider(providerKey)}". ` +
177
+ `Specify which one to disconnect with --account or --connection-id.\n\n` +
178
+ `Run 'assistant oauth status ${provider}' to see connected accounts and IDs.`,
179
+ { connections: connectionList },
180
+ );
181
+ return;
182
+ }
183
+
184
+ connectionId = entries[0].id;
185
+ accountLabel = entries[0].account_label;
186
+ }
187
+
188
+ // Call platform /disconnect/ endpoint
189
+ const disconnectPath = `/v1/assistants/${encodeURIComponent(client.platformAssistantId)}/oauth/connections/${encodeURIComponent(connectionId)}/disconnect/`;
190
+ const disconnectResponse = await client.fetch(disconnectPath, {
191
+ method: "POST",
192
+ headers: { "Content-Type": "application/json" },
193
+ });
194
+
195
+ if (!disconnectResponse.ok) {
196
+ const errorText = await disconnectResponse.text().catch(() => "");
197
+ writeError(
198
+ `Platform returned HTTP ${disconnectResponse.status}${errorText ? `: ${errorText}` : ""}`,
199
+ );
200
+ return;
201
+ }
202
+
203
+ const result: Record<string, unknown> = {
204
+ ok: true,
205
+ provider: providerKey,
206
+ connectionId,
207
+ };
208
+ if (accountLabel) result.account = accountLabel;
209
+ writeOutput(cmd, result);
210
+
211
+ if (!jsonMode) {
212
+ log.info(
213
+ `Disconnected ${providerKey} connection ${connectionId}`,
214
+ );
215
+ }
216
+ } else {
217
+ // -----------------------------------------------------------------
218
+ // BYO path
219
+ // -----------------------------------------------------------------
220
+ let connectionId: string | undefined;
221
+ let accountLabel: string | undefined;
222
+
223
+ if (opts.account) {
224
+ const conn = getActiveConnection(providerKey, {
225
+ account: opts.account,
226
+ });
227
+ if (!conn) {
228
+ writeError(
229
+ `No active connection found for "${providerKey}" with account "${opts.account}".\n\n` +
230
+ `Run 'assistant oauth status ${provider}' to see connected accounts.`,
231
+ );
232
+ return;
233
+ }
234
+ connectionId = conn.id;
235
+ accountLabel = conn.accountInfo ?? undefined;
236
+ } else if (opts.connectionId) {
237
+ const conn = getConnection(opts.connectionId);
238
+ if (!conn || conn.providerKey !== providerKey) {
239
+ writeError(
240
+ `Connection "${opts.connectionId}" is not an active ${providerKey} connection.\n\n` +
241
+ `Run 'assistant oauth status ${provider}' to see active connections.`,
242
+ );
243
+ return;
244
+ }
245
+ connectionId = conn.id;
246
+ accountLabel = conn.accountInfo ?? undefined;
247
+ } else {
248
+ // Neither specified — auto-resolve
249
+ const active = listActiveConnectionsByProvider(providerKey);
250
+
251
+ if (active.length === 0) {
252
+ writeError(
253
+ `No active connections found for "${providerKey}".\n\n` +
254
+ `Run 'assistant oauth status ${provider}' to check connection status.`,
255
+ );
256
+ return;
257
+ }
258
+
259
+ if (active.length > 1) {
260
+ const connectionList = active.map((c) => ({
261
+ id: c.id,
262
+ account: c.accountInfo ?? null,
263
+ }));
264
+ writeError(
265
+ `Multiple active connections for "${providerKey}". ` +
266
+ `Specify which one to disconnect with --account or --connection-id.\n\n` +
267
+ `Run 'assistant oauth status ${provider}' to see connected accounts and IDs.`,
268
+ { connections: connectionList },
269
+ );
270
+ return;
271
+ }
272
+
273
+ connectionId = active[0].id;
274
+ accountLabel = active[0].accountInfo ?? undefined;
275
+ }
276
+
277
+ // Disconnect the OAuth connection (tokens + connection row)
278
+ const oauthResult = await disconnectOAuthProvider(
279
+ providerKey,
280
+ undefined,
281
+ connectionId,
282
+ );
283
+ if (oauthResult === "error") {
284
+ writeError(
285
+ `Failed to disconnect OAuth provider "${providerKey}" — please try again.`,
286
+ );
287
+ return;
288
+ }
289
+
290
+ // Clean up legacy credential keys
291
+ const legacyFields = [
292
+ "access_token",
293
+ "refresh_token",
294
+ "client_id",
295
+ "client_secret",
296
+ ];
297
+ for (const field of legacyFields) {
298
+ try {
299
+ await deleteSecureKeyViaDaemon(
300
+ "credential",
301
+ `${providerKey}:${field}`,
302
+ );
303
+ } catch {
304
+ // Best-effort cleanup — ignore failures
305
+ }
306
+ try {
307
+ deleteCredentialMetadata(providerKey, field);
308
+ } catch {
309
+ // Best-effort cleanup — ignore failures
310
+ }
311
+ }
312
+
313
+ const result: Record<string, unknown> = {
314
+ ok: true,
315
+ provider: providerKey,
316
+ connectionId,
317
+ };
318
+ if (accountLabel) result.account = accountLabel;
319
+ writeOutput(cmd, result);
320
+
321
+ if (!jsonMode) {
322
+ log.info(
323
+ `Disconnected ${providerKey} connection ${connectionId}`,
324
+ );
325
+ }
326
+ }
327
+ } catch (err) {
328
+ const message = err instanceof Error ? err.message : String(err);
329
+ writeError(message);
330
+ }
331
+ },
332
+ );
333
+ }
@@ -1,9 +1,15 @@
1
1
  import type { Command } from "commander";
2
2
 
3
3
  import { registerAppCommands } from "./apps.js";
4
+ import { registerConnectCommand } from "./connect.js";
4
5
  import { registerConnectionCommands } from "./connections.js";
5
- import { registerPlatformCommands } from "./platform.js";
6
+ import { registerDisconnectCommand } from "./disconnect.js";
7
+ import { registerModeCommand } from "./mode.js";
8
+ import { registerPingCommand } from "./ping.js";
6
9
  import { registerProviderCommands } from "./providers.js";
10
+ import { registerRequestCommand } from "./request.js";
11
+ import { registerStatusCommand } from "./status.js";
12
+ import { registerTokenCommand } from "./token.js";
7
13
 
8
14
  export function registerOAuthCommand(program: Command): void {
9
15
  const oauth = program
@@ -16,21 +22,31 @@ export function registerOAuthCommand(program: Command): void {
16
22
  `
17
23
  The oauth command group manages the full OAuth lifecycle:
18
24
 
25
+ connect Initiate an OAuth flow for a provider (managed or BYO)
26
+ disconnect Disconnect an OAuth provider
27
+ status Show OAuth connection status for a provider
28
+ mode Get or set OAuth mode (managed vs your-own) for a provider
29
+ token Print a valid OAuth access token (BYO providers only)
30
+ ping Verify an OAuth token is valid by hitting the provider's health-check endpoint
31
+ request Make authenticated HTTP requests (curl-like interface)
19
32
  providers Protocol-level configurations (auth URLs, scopes, endpoints)
20
33
  apps Client credentials (client ID / secret pairs)
21
- connections Active token grants per provider (list, get, token, disconnect)
34
+ connections Active token grants per provider (list, get)
22
35
 
23
36
  Providers are seeded on startup for built-in integrations. Apps and connections
24
37
  are created during the OAuth authorization flow or can be managed manually via
25
38
  their respective subcommands.
26
39
 
27
40
  Examples:
28
- $ assistant oauth connections token integration:twitter
29
- $ assistant oauth connections list
30
- $ assistant oauth connections get --provider integration:google
41
+ $ assistant oauth connect google --open-browser
42
+ $ assistant oauth status google
43
+ $ assistant oauth ping google
44
+ $ assistant oauth disconnect google
45
+ $ assistant oauth request --provider integration:google /gmail/v1/users/me/messages
46
+ $ assistant oauth request --provider integration:twitter -X POST -d '{"text":"Hello"}' https://api.x.com/2/tweets
47
+ $ assistant oauth token integration:twitter
31
48
  $ assistant oauth providers list
32
- $ assistant oauth providers get integration:google
33
- $ assistant oauth providers register --provider-key custom:myapi --auth-url https://example.com/auth --token-url https://example.com/token`,
49
+ $ assistant oauth providers get integration:google`,
34
50
  );
35
51
 
36
52
  // ---------------------------------------------------------------------------
@@ -46,14 +62,50 @@ Examples:
46
62
  registerAppCommands(oauth);
47
63
 
48
64
  // ---------------------------------------------------------------------------
49
- // connections — subcommand group (includes token)
65
+ // connections — subcommand group (list, get)
50
66
  // ---------------------------------------------------------------------------
51
67
 
52
68
  registerConnectionCommands(oauth);
53
69
 
54
70
  // ---------------------------------------------------------------------------
55
- // platformsubcommand group
71
+ // requestcurl-like authenticated request command
56
72
  // ---------------------------------------------------------------------------
57
73
 
58
- registerPlatformCommands(oauth);
74
+ registerRequestCommand(oauth);
75
+
76
+ // ---------------------------------------------------------------------------
77
+ // connect — unified connect command (auto-detects managed vs BYO)
78
+ // ---------------------------------------------------------------------------
79
+
80
+ registerConnectCommand(oauth);
81
+
82
+ // ---------------------------------------------------------------------------
83
+ // disconnect — unified disconnect with auto-detected managed/BYO routing
84
+ // ---------------------------------------------------------------------------
85
+
86
+ registerDisconnectCommand(oauth);
87
+
88
+ // ---------------------------------------------------------------------------
89
+ // status — unified connection status (auto-detects managed vs BYO)
90
+ // ---------------------------------------------------------------------------
91
+
92
+ registerStatusCommand(oauth);
93
+
94
+ // ---------------------------------------------------------------------------
95
+ // mode — get or set OAuth mode (managed vs your-own) for a provider
96
+ // ---------------------------------------------------------------------------
97
+
98
+ registerModeCommand(oauth);
99
+
100
+ // ---------------------------------------------------------------------------
101
+ // ping — unified ping command (auto-detects managed vs BYO)
102
+ // ---------------------------------------------------------------------------
103
+
104
+ registerPingCommand(oauth);
105
+
106
+ // ---------------------------------------------------------------------------
107
+ // token — unified token retrieval (BYO only, managed-mode guard)
108
+ // ---------------------------------------------------------------------------
109
+
110
+ registerTokenCommand(oauth);
59
111
  }