@vellumai/assistant 0.5.11 → 0.5.13

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 (209) hide show
  1. package/Dockerfile +42 -9
  2. package/docs/architecture/integrations.md +34 -32
  3. package/node_modules/@vellumai/ces-contracts/src/__tests__/grants.test.ts +7 -7
  4. package/node_modules/@vellumai/ces-contracts/src/handles.ts +5 -4
  5. package/node_modules/@vellumai/ces-contracts/src/index.ts +7 -0
  6. package/node_modules/@vellumai/ces-contracts/src/rpc.ts +5 -0
  7. package/node_modules/@vellumai/credential-storage/src/index.ts +1 -1
  8. package/openapi.yaml +87 -9
  9. package/package.json +1 -1
  10. package/src/__tests__/catalog-cache.test.ts +164 -0
  11. package/src/__tests__/catalog-search.test.ts +61 -0
  12. package/src/__tests__/cli-command-risk-guard.test.ts +181 -6
  13. package/src/__tests__/conversation-delete-schedule-cleanup.test.ts +396 -0
  14. package/src/__tests__/conversation-error.test.ts +3 -2
  15. package/src/__tests__/credential-security-invariants.test.ts +9 -15
  16. package/src/__tests__/credential-vault-unit.test.ts +32 -34
  17. package/src/__tests__/credential-vault.test.ts +25 -33
  18. package/src/__tests__/credentials-cli.test.ts +3 -3
  19. package/src/__tests__/daemon-credential-client.test.ts +2 -2
  20. package/src/__tests__/first-greeting.test.ts +7 -0
  21. package/src/__tests__/host-bash-proxy.test.ts +79 -0
  22. package/src/__tests__/host-cu-proxy.test.ts +90 -0
  23. package/src/__tests__/host-file-proxy.test.ts +89 -0
  24. package/src/__tests__/integration-status.test.ts +5 -5
  25. package/src/__tests__/list-messages-attachments.test.ts +171 -0
  26. package/src/__tests__/mcp-abort-signal.test.ts +205 -0
  27. package/src/__tests__/messaging-send-tool.test.ts +5 -5
  28. package/src/__tests__/navigate-settings-tab.test.ts +6 -2
  29. package/src/__tests__/notification-telegram-adapter.test.ts +125 -0
  30. package/src/__tests__/oauth-cli.test.ts +126 -119
  31. package/src/__tests__/oauth-provider-profiles.test.ts +55 -20
  32. package/src/__tests__/oauth-scope-policy.test.ts +4 -6
  33. package/src/__tests__/onboarding-template-contract.test.ts +2 -2
  34. package/src/__tests__/platform.test.ts +3 -168
  35. package/src/__tests__/secret-routes-managed-proxy.test.ts +78 -0
  36. package/src/__tests__/secure-keys-managed-failover.test.ts +73 -0
  37. package/src/__tests__/skill-feature-flags.test.ts +8 -0
  38. package/src/__tests__/skill-secret-handling-guard.test.ts +212 -0
  39. package/src/__tests__/skills-uninstall.test.ts +2 -2
  40. package/src/__tests__/slack-messaging-token-resolution.test.ts +22 -24
  41. package/src/__tests__/slack-share-routes.test.ts +5 -5
  42. package/src/__tests__/system-prompt.test.ts +39 -0
  43. package/src/__tests__/token-estimator-accuracy.benchmark.test.ts +1 -1
  44. package/src/__tests__/workspace-migration-backfill-installation-id.test.ts +5 -4
  45. package/src/cli/AGENTS.md +47 -7
  46. package/src/cli/commands/browser-relay.ts +2 -17
  47. package/src/cli/commands/contacts.ts +6 -4
  48. package/src/cli/commands/conversations.ts +13 -1
  49. package/src/cli/commands/credential-execution.ts +16 -1
  50. package/src/cli/commands/credentials.ts +2 -8
  51. package/src/cli/commands/oauth/__tests__/connect.test.ts +29 -108
  52. package/src/cli/commands/oauth/__tests__/disconnect.test.ts +13 -87
  53. package/src/cli/commands/oauth/__tests__/mode.test.ts +22 -69
  54. package/src/cli/commands/oauth/__tests__/ping.test.ts +20 -79
  55. package/src/cli/commands/oauth/__tests__/providers-delete.test.ts +574 -0
  56. package/src/cli/commands/oauth/__tests__/providers-update.test.ts +416 -0
  57. package/src/cli/commands/oauth/__tests__/status.test.ts +12 -40
  58. package/src/cli/commands/oauth/__tests__/token.test.ts +3 -50
  59. package/src/cli/commands/oauth/apps.ts +63 -44
  60. package/src/cli/commands/oauth/connect.ts +187 -155
  61. package/src/cli/commands/oauth/disconnect.ts +27 -75
  62. package/src/cli/commands/oauth/index.ts +36 -46
  63. package/src/cli/commands/oauth/mode.ts +22 -34
  64. package/src/cli/commands/oauth/ping.ts +19 -45
  65. package/src/cli/commands/oauth/providers.ts +569 -62
  66. package/src/cli/commands/oauth/request.ts +36 -48
  67. package/src/cli/commands/oauth/shared.ts +1 -19
  68. package/src/cli/commands/oauth/status.ts +14 -25
  69. package/src/cli/commands/oauth/token.ts +25 -34
  70. package/src/cli/commands/platform/__tests__/connect.test.ts +224 -0
  71. package/src/cli/commands/platform/__tests__/disconnect.test.ts +237 -0
  72. package/src/cli/commands/platform/__tests__/status.test.ts +246 -0
  73. package/src/cli/commands/platform/connect.ts +104 -0
  74. package/src/cli/commands/platform/disconnect.ts +118 -0
  75. package/src/cli/commands/{platform.ts → platform/index.ts} +108 -38
  76. package/src/cli/commands/sequence.ts +5 -4
  77. package/src/cli/commands/shotgun.ts +16 -0
  78. package/src/cli/commands/skills.ts +173 -41
  79. package/src/cli/commands/usage.ts +5 -11
  80. package/src/cli/lib/daemon-credential-client.ts +22 -38
  81. package/src/cli/program.ts +1 -1
  82. package/src/config/assistant-feature-flags.ts +3 -7
  83. package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
  84. package/src/config/bundled-skills/conversations/SKILL.md +20 -0
  85. package/src/config/bundled-skills/conversations/TOOLS.json +23 -0
  86. package/src/config/bundled-skills/conversations/tools/rename-conversation.ts +66 -0
  87. package/src/config/bundled-skills/gmail/SKILL.md +13 -13
  88. package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +3 -3
  89. package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +2 -2
  90. package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +1 -1
  91. package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +1 -1
  92. package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +1 -1
  93. package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +1 -1
  94. package/src/config/bundled-skills/gmail/tools/gmail-label.ts +2 -2
  95. package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +1 -1
  96. package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +1 -1
  97. package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +1 -1
  98. package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +1 -1
  99. package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +1 -1
  100. package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +1 -1
  101. package/src/config/bundled-skills/google-calendar/SKILL.md +10 -4
  102. package/src/config/bundled-skills/google-calendar/tools/shared.ts +1 -1
  103. package/src/config/bundled-skills/messaging/SKILL.md +7 -7
  104. package/src/config/bundled-skills/messaging/tools/messaging-send.ts +5 -2
  105. package/src/config/bundled-skills/messaging/tools/shared.ts +5 -6
  106. package/src/config/bundled-skills/settings/TOOLS.json +5 -3
  107. package/src/config/bundled-skills/settings/tools/navigate-settings-tab.ts +4 -2
  108. package/src/config/bundled-tool-registry.ts +5 -0
  109. package/src/config/feature-flag-registry.json +2 -2
  110. package/src/credential-execution/client.ts +15 -3
  111. package/src/daemon/conversation-agent-loop.ts +2 -0
  112. package/src/daemon/conversation-error.ts +36 -6
  113. package/src/daemon/conversation-messaging.ts +9 -0
  114. package/src/daemon/conversation-runtime-assembly.ts +33 -0
  115. package/src/daemon/conversation-surfaces.ts +120 -14
  116. package/src/daemon/conversation.ts +5 -0
  117. package/src/daemon/first-greeting.ts +6 -1
  118. package/src/daemon/handlers/skills.ts +148 -3
  119. package/src/daemon/host-bash-proxy.ts +16 -0
  120. package/src/daemon/host-cu-proxy.ts +16 -0
  121. package/src/daemon/host-file-proxy.ts +16 -0
  122. package/src/daemon/lifecycle.ts +56 -5
  123. package/src/daemon/message-types/conversations.ts +1 -0
  124. package/src/daemon/message-types/guardian-actions.ts +2 -0
  125. package/src/daemon/message-types/host-bash.ts +6 -1
  126. package/src/daemon/message-types/host-cu.ts +6 -1
  127. package/src/daemon/message-types/host-file.ts +6 -1
  128. package/src/daemon/message-types/integrations.ts +0 -1
  129. package/src/daemon/server.ts +29 -2
  130. package/src/hooks/cli.ts +74 -0
  131. package/src/inbound/platform-callback-registration.ts +7 -12
  132. package/src/index.ts +0 -12
  133. package/src/mcp/client.ts +6 -1
  134. package/src/mcp/manager.ts +2 -1
  135. package/src/memory/conversation-crud.ts +92 -3
  136. package/src/memory/conversation-key-store.ts +26 -0
  137. package/src/memory/conversation-queries.ts +6 -6
  138. package/src/memory/db-init.ts +16 -0
  139. package/src/memory/journal-memory.ts +8 -2
  140. package/src/memory/migrations/196-messages-conversation-created-at-index.ts +9 -0
  141. package/src/memory/migrations/196-strip-integration-prefix-from-provider-keys.ts +186 -0
  142. package/src/memory/migrations/197-oauth-providers-behavior-columns.ts +29 -0
  143. package/src/memory/migrations/198-drop-setup-skill-id-column.ts +11 -0
  144. package/src/memory/migrations/index.ts +4 -0
  145. package/src/memory/migrations/registry.ts +8 -0
  146. package/src/memory/schema/oauth.ts +11 -0
  147. package/src/messaging/provider.ts +13 -12
  148. package/src/messaging/providers/gmail/adapter.ts +44 -35
  149. package/src/messaging/providers/slack/adapter.ts +63 -33
  150. package/src/messaging/providers/telegram-bot/adapter.ts +6 -8
  151. package/src/messaging/providers/whatsapp/adapter.ts +6 -8
  152. package/src/notifications/adapters/telegram.ts +78 -2
  153. package/src/oauth/__tests__/identity-verifier.test.ts +464 -0
  154. package/src/oauth/byo-connection.test.ts +22 -24
  155. package/src/oauth/connect-orchestrator.ts +37 -76
  156. package/src/oauth/connect-types.ts +7 -65
  157. package/src/oauth/connection-resolver.test.ts +13 -13
  158. package/src/oauth/connection-resolver.ts +3 -4
  159. package/src/oauth/identity-verifier.ts +177 -0
  160. package/src/oauth/oauth-store.ts +228 -3
  161. package/src/oauth/platform-connection.test.ts +56 -6
  162. package/src/oauth/platform-connection.ts +8 -1
  163. package/src/oauth/seed-providers.ts +247 -34
  164. package/src/permissions/checker.ts +127 -1
  165. package/src/prompts/journal-context.ts +4 -1
  166. package/src/prompts/system-prompt.ts +54 -9
  167. package/src/prompts/templates/BOOTSTRAP.md +16 -5
  168. package/src/providers/anthropic/client.ts +2 -33
  169. package/src/runtime/guardian-action-service.ts +7 -2
  170. package/src/runtime/http-server.ts +12 -18
  171. package/src/runtime/http-types.ts +8 -1
  172. package/src/runtime/migrations/rebind-secrets-screen.ts +2 -2
  173. package/src/runtime/routes/conversation-management-routes.ts +31 -0
  174. package/src/runtime/routes/conversation-routes.ts +79 -4
  175. package/src/runtime/routes/guardian-action-routes.ts +15 -2
  176. package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -8
  177. package/src/runtime/routes/integrations/slack/share.ts +1 -1
  178. package/src/runtime/routes/oauth-apps.ts +2 -1
  179. package/src/runtime/routes/secret-routes.ts +45 -15
  180. package/src/runtime/routes/settings-routes.ts +12 -19
  181. package/src/runtime/routes/skills-routes.ts +45 -4
  182. package/src/schedule/integration-status.ts +2 -2
  183. package/src/security/ces-rpc-credential-backend.ts +19 -16
  184. package/src/security/oauth-completion-page.ts +153 -0
  185. package/src/security/oauth2.ts +3 -17
  186. package/src/security/secure-keys.ts +207 -7
  187. package/src/security/token-manager.ts +3 -6
  188. package/src/signals/bash.ts +6 -1
  189. package/src/skills/catalog-cache.ts +44 -0
  190. package/src/skills/catalog-search.ts +18 -0
  191. package/src/tools/browser/browser-manager.ts +2 -2
  192. package/src/tools/credentials/post-connect-hooks.ts +1 -1
  193. package/src/tools/credentials/vault.ts +34 -45
  194. package/src/tools/host-terminal/host-shell.ts +16 -3
  195. package/src/tools/mcp/mcp-tool-factory.ts +2 -1
  196. package/src/tools/skills/sandbox-runner.ts +16 -3
  197. package/src/tools/terminal/shell.ts +16 -3
  198. package/src/util/logger.ts +11 -1
  199. package/src/util/platform.ts +1 -91
  200. package/src/util/sentry-log-stream.ts +51 -0
  201. package/src/watcher/providers/github.ts +2 -2
  202. package/src/watcher/providers/gmail.ts +1 -1
  203. package/src/watcher/providers/google-calendar.ts +1 -1
  204. package/src/watcher/providers/linear.ts +2 -2
  205. package/src/workspace/migrations/011-backfill-installation-id.ts +5 -3
  206. package/src/workspace/migrations/020-rename-oauth-skill-dirs.ts +119 -0
  207. package/src/workspace/migrations/registry.ts +2 -0
  208. package/src/cli/commands/oauth/connections.ts +0 -255
  209. package/src/oauth/provider-behaviors.ts +0 -634
@@ -7,16 +7,12 @@ import {
7
7
  getProvider,
8
8
  listActiveConnectionsByProvider,
9
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
10
  import { getCliLogger } from "../../logger.js";
13
11
  import { shouldOutputJson, writeOutput } from "../../output.js";
14
12
  import {
15
13
  fetchActiveConnections,
16
14
  isManagedMode,
17
15
  requirePlatformClient,
18
- resolveService,
19
- toBareProvider,
20
16
  } from "./shared.js";
21
17
 
22
18
  const log = getCliLogger("cli");
@@ -29,7 +25,7 @@ export function registerDisconnectCommand(oauth: Command): void {
29
25
  oauth
30
26
  .command("disconnect <provider>")
31
27
  .description(
32
- "Disconnect an OAuth provider and remove associated credentials (auto-detects managed vs BYO mode)",
28
+ "Disconnect an OAuth provider and remove associated credentials",
33
29
  )
34
30
  .option(
35
31
  "--account <identifier>",
@@ -40,25 +36,14 @@ export function registerDisconnectCommand(oauth: Command): void {
40
36
  "after",
41
37
  `
42
38
  Arguments:
43
- provider Provider name or key (e.g. google, integration:google, gmail).
39
+ provider Provider name (e.g. google, slack, notion).
44
40
  Run 'assistant oauth providers list' to see available providers.
45
41
 
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.
42
+ At most one of --account or --connection-id may be specified. Use the values
43
+ shown by 'assistant oauth status <provider>' to find the right identifier.
54
44
 
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.
45
+ When a provider has multiple active connections and neither flag is given,
46
+ the command errors with a list of connections and a hint to disambiguate.
62
47
 
63
48
  Examples:
64
49
  $ assistant oauth disconnect google
@@ -84,11 +69,9 @@ Examples:
84
69
 
85
70
  try {
86
71
  // -------------------------------------------------------------------
87
- // 1. Resolve + validate provider
72
+ // 1. Validate provider
88
73
  // -------------------------------------------------------------------
89
- const providerKey = resolveService(provider);
90
-
91
- const providerRow = getProvider(providerKey);
74
+ const providerRow = getProvider(provider);
92
75
  if (!providerRow) {
93
76
  writeError(
94
77
  `Unknown provider "${provider}".\n\n` +
@@ -112,7 +95,7 @@ Examples:
112
95
  // -------------------------------------------------------------------
113
96
  // 3. Detect mode
114
97
  // -------------------------------------------------------------------
115
- const managed = isManagedMode(providerKey);
98
+ const managed = isManagedMode(provider);
116
99
 
117
100
  if (managed) {
118
101
  // -----------------------------------------------------------------
@@ -121,11 +104,7 @@ Examples:
121
104
  const client = await requirePlatformClient(cmd);
122
105
  if (!client) return;
123
106
 
124
- const entries = await fetchActiveConnections(
125
- client,
126
- providerKey,
127
- cmd,
128
- );
107
+ const entries = await fetchActiveConnections(client, provider, cmd);
129
108
  if (!entries) return;
130
109
 
131
110
  let connectionId: string | undefined;
@@ -138,7 +117,7 @@ Examples:
138
117
  );
139
118
  if (matching.length === 0) {
140
119
  writeError(
141
- `No active connection found for "${toBareProvider(providerKey)}" with account "${opts.account}".\n\n` +
120
+ `No active connection found for "${provider}" with account "${opts.account}".\n\n` +
142
121
  `Run 'assistant oauth status ${provider}' to see connected accounts.`,
143
122
  );
144
123
  return;
@@ -150,7 +129,7 @@ Examples:
150
129
  const match = entries.find((c) => c.id === opts.connectionId);
151
130
  if (!match) {
152
131
  writeError(
153
- `Connection "${opts.connectionId}" is not an active ${toBareProvider(providerKey)} connection.\n\n` +
132
+ `Connection "${opts.connectionId}" is not an active ${provider} connection.\n\n` +
154
133
  `Run 'assistant oauth status ${provider}' to see active connections.`,
155
134
  );
156
135
  return;
@@ -161,7 +140,7 @@ Examples:
161
140
  // Neither specified — auto-resolve
162
141
  if (entries.length === 0) {
163
142
  writeError(
164
- `No active connections found for "${toBareProvider(providerKey)}".\n\n` +
143
+ `No active connections found for "${provider}".\n\n` +
165
144
  `Run 'assistant oauth status ${provider}' to check connection status.`,
166
145
  );
167
146
  return;
@@ -173,7 +152,7 @@ Examples:
173
152
  account: c.account_label ?? null,
174
153
  }));
175
154
  writeError(
176
- `Multiple active connections for "${toBareProvider(providerKey)}". ` +
155
+ `Multiple active connections for "${provider}". ` +
177
156
  `Specify which one to disconnect with --account or --connection-id.\n\n` +
178
157
  `Run 'assistant oauth status ${provider}' to see connected accounts and IDs.`,
179
158
  { connections: connectionList },
@@ -202,16 +181,14 @@ Examples:
202
181
 
203
182
  const result: Record<string, unknown> = {
204
183
  ok: true,
205
- provider: providerKey,
184
+ provider: provider,
206
185
  connectionId,
207
186
  };
208
187
  if (accountLabel) result.account = accountLabel;
209
188
  writeOutput(cmd, result);
210
189
 
211
190
  if (!jsonMode) {
212
- log.info(
213
- `Disconnected ${providerKey} connection ${connectionId}`,
214
- );
191
+ log.info(`Disconnected ${provider} connection ${connectionId}`);
215
192
  }
216
193
  } else {
217
194
  // -----------------------------------------------------------------
@@ -221,12 +198,12 @@ Examples:
221
198
  let accountLabel: string | undefined;
222
199
 
223
200
  if (opts.account) {
224
- const conn = getActiveConnection(providerKey, {
201
+ const conn = getActiveConnection(provider, {
225
202
  account: opts.account,
226
203
  });
227
204
  if (!conn) {
228
205
  writeError(
229
- `No active connection found for "${providerKey}" with account "${opts.account}".\n\n` +
206
+ `No active connection found for "${provider}" with account "${opts.account}".\n\n` +
230
207
  `Run 'assistant oauth status ${provider}' to see connected accounts.`,
231
208
  );
232
209
  return;
@@ -235,9 +212,9 @@ Examples:
235
212
  accountLabel = conn.accountInfo ?? undefined;
236
213
  } else if (opts.connectionId) {
237
214
  const conn = getConnection(opts.connectionId);
238
- if (!conn || conn.providerKey !== providerKey) {
215
+ if (!conn || conn.providerKey !== provider) {
239
216
  writeError(
240
- `Connection "${opts.connectionId}" is not an active ${providerKey} connection.\n\n` +
217
+ `Connection "${opts.connectionId}" is not an active ${provider} connection.\n\n` +
241
218
  `Run 'assistant oauth status ${provider}' to see active connections.`,
242
219
  );
243
220
  return;
@@ -246,11 +223,11 @@ Examples:
246
223
  accountLabel = conn.accountInfo ?? undefined;
247
224
  } else {
248
225
  // Neither specified — auto-resolve
249
- const active = listActiveConnectionsByProvider(providerKey);
226
+ const active = listActiveConnectionsByProvider(provider);
250
227
 
251
228
  if (active.length === 0) {
252
229
  writeError(
253
- `No active connections found for "${providerKey}".\n\n` +
230
+ `No active connections found for "${provider}".\n\n` +
254
231
  `Run 'assistant oauth status ${provider}' to check connection status.`,
255
232
  );
256
233
  return;
@@ -262,7 +239,7 @@ Examples:
262
239
  account: c.accountInfo ?? null,
263
240
  }));
264
241
  writeError(
265
- `Multiple active connections for "${providerKey}". ` +
242
+ `Multiple active connections for "${provider}". ` +
266
243
  `Specify which one to disconnect with --account or --connection-id.\n\n` +
267
244
  `Run 'assistant oauth status ${provider}' to see connected accounts and IDs.`,
268
245
  { connections: connectionList },
@@ -276,52 +253,27 @@ Examples:
276
253
 
277
254
  // Disconnect the OAuth connection (tokens + connection row)
278
255
  const oauthResult = await disconnectOAuthProvider(
279
- providerKey,
256
+ provider,
280
257
  undefined,
281
258
  connectionId,
282
259
  );
283
260
  if (oauthResult === "error") {
284
261
  writeError(
285
- `Failed to disconnect OAuth provider "${providerKey}" — please try again.`,
262
+ `Failed to disconnect OAuth provider "${provider}" — please try again.`,
286
263
  );
287
264
  return;
288
265
  }
289
266
 
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
267
  const result: Record<string, unknown> = {
314
268
  ok: true,
315
- provider: providerKey,
269
+ provider: provider,
316
270
  connectionId,
317
271
  };
318
272
  if (accountLabel) result.account = accountLabel;
319
273
  writeOutput(cmd, result);
320
274
 
321
275
  if (!jsonMode) {
322
- log.info(
323
- `Disconnected ${providerKey} connection ${connectionId}`,
324
- );
276
+ log.info(`Disconnected ${provider} connection ${connectionId}`);
325
277
  }
326
278
  }
327
279
  } catch (err) {
@@ -2,7 +2,6 @@ import type { Command } from "commander";
2
2
 
3
3
  import { registerAppCommands } from "./apps.js";
4
4
  import { registerConnectCommand } from "./connect.js";
5
- import { registerConnectionCommands } from "./connections.js";
6
5
  import { registerDisconnectCommand } from "./disconnect.js";
7
6
  import { registerModeCommand } from "./mode.js";
8
7
  import { registerPingCommand } from "./ping.js";
@@ -14,39 +13,36 @@ import { registerTokenCommand } from "./token.js";
14
13
  export function registerOAuthCommand(program: Command): void {
15
14
  const oauth = program
16
15
  .command("oauth")
17
- .description("Manage OAuth providers, apps, connections, and tokens")
16
+ .description(
17
+ "Manage the full OAuth lifecycle — registering providers, creating apps, connecting accounts, and making authenticated requests",
18
+ )
18
19
  .option("--json", "Machine-readable compact JSON output");
19
20
 
20
21
  oauth.addHelpText(
21
22
  "after",
22
23
  `
23
- The oauth command group manages the full OAuth lifecycle:
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)
32
- providers Protocol-level configurations (auth URLs, scopes, endpoints)
33
- apps Client credentials (client ID / secret pairs)
34
- connections Active token grants per provider (list, get)
35
-
36
- Providers are seeded on startup for built-in integrations. Apps and connections
37
- are created during the OAuth authorization flow or can be managed manually via
38
- their respective subcommands.
24
+ OAuth providers may support up to two modes – "managed" and "your-own".
25
+ managed:
26
+ Requires a Vellum Platform account. For providers that support it, managed mode offloads the burden of needing to create and register an oauth app.
27
+ Vellum Platform manages oauth token management and refresh and proxies requests to the provier.
28
+ you-own:
29
+ Provides ultimate control and removes dependency on Vellum Platform, but requires that you set up your own oauth app and register it
30
+ via \`assistant oauth apps upsert\`.
31
+ All commands are intended to work regardless of the provider's mode. Check and set the mode for a given provider with \`assistant oauth mode\`.
32
+
33
+ You can define entirely new oauth providers to integrate with even if they do not show up using \`assistant oauth providers list\` using
34
+ \`assistant oauth providers register\`. Custom-registered providers only support "your-own" mode.
35
+
39
36
 
40
37
  Examples:
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
48
- $ assistant oauth providers list
49
- $ assistant oauth providers get integration:google`,
38
+ assistant oauth providers list
39
+ assistant oauth providers get google
40
+ assistant oauth mode google --set=managed
41
+ assistant oauth connect google --open-browser
42
+ assistant oauth status google
43
+ assistant oauth ping google
44
+ assistant oauth request --provider google /gmail/v1/users/me/messages
45
+ assistant oauth disconnect google`,
50
46
  );
51
47
 
52
48
  // ---------------------------------------------------------------------------
@@ -56,22 +52,16 @@ Examples:
56
52
  registerProviderCommands(oauth);
57
53
 
58
54
  // ---------------------------------------------------------------------------
59
- // appssubcommand group
60
- // ---------------------------------------------------------------------------
61
-
62
- registerAppCommands(oauth);
63
-
64
- // ---------------------------------------------------------------------------
65
- // connections — subcommand group (list, get)
55
+ // modeget or set OAuth mode (managed vs your-own) for a provider
66
56
  // ---------------------------------------------------------------------------
67
57
 
68
- registerConnectionCommands(oauth);
58
+ registerModeCommand(oauth);
69
59
 
70
60
  // ---------------------------------------------------------------------------
71
- // requestcurl-like authenticated request command
61
+ // appssubcommand group
72
62
  // ---------------------------------------------------------------------------
73
63
 
74
- registerRequestCommand(oauth);
64
+ registerAppCommands(oauth);
75
65
 
76
66
  // ---------------------------------------------------------------------------
77
67
  // connect — unified connect command (auto-detects managed vs BYO)
@@ -80,31 +70,31 @@ Examples:
80
70
  registerConnectCommand(oauth);
81
71
 
82
72
  // ---------------------------------------------------------------------------
83
- // disconnect — unified disconnect with auto-detected managed/BYO routing
73
+ // status — unified connection status
84
74
  // ---------------------------------------------------------------------------
85
75
 
86
- registerDisconnectCommand(oauth);
76
+ registerStatusCommand(oauth);
87
77
 
88
78
  // ---------------------------------------------------------------------------
89
- // statusunified connection status (auto-detects managed vs BYO)
79
+ // pingping to see if a provider is connected and healthy
90
80
  // ---------------------------------------------------------------------------
91
81
 
92
- registerStatusCommand(oauth);
82
+ registerPingCommand(oauth);
93
83
 
94
84
  // ---------------------------------------------------------------------------
95
- // modeget or set OAuth mode (managed vs your-own) for a provider
85
+ // requestcurl-like authenticated request command
96
86
  // ---------------------------------------------------------------------------
97
87
 
98
- registerModeCommand(oauth);
88
+ registerRequestCommand(oauth);
99
89
 
100
90
  // ---------------------------------------------------------------------------
101
- // ping — unified ping command (auto-detects managed vs BYO)
91
+ // disconnect — unified disconnect with auto-detected managed/BYO routing
102
92
  // ---------------------------------------------------------------------------
103
93
 
104
- registerPingCommand(oauth);
94
+ registerDisconnectCommand(oauth);
105
95
 
106
96
  // ---------------------------------------------------------------------------
107
- // token — unified token retrieval (BYO only, managed-mode guard)
97
+ // token — retrieve a valid oauth token (your-own mode only)
108
98
  // ---------------------------------------------------------------------------
109
99
 
110
100
  registerTokenCommand(oauth);
@@ -17,8 +17,6 @@ import { shouldOutputJson, writeOutput } from "../../output.js";
17
17
  import {
18
18
  fetchActiveConnections,
19
19
  getManagedServiceConfigKey,
20
- resolveService,
21
- toBareProvider,
22
20
  } from "./shared.js";
23
21
 
24
22
  /**
@@ -30,13 +28,13 @@ import {
30
28
  * command output or set a non-zero exit code.
31
29
  */
32
30
  async function countManagedConnections(
33
- providerKey: string,
31
+ provider: string,
34
32
  cmd: Command,
35
33
  ): Promise<number> {
36
34
  try {
37
35
  const client = await VellumPlatformClient.create();
38
36
  if (!client || !client.platformAssistantId) return 0;
39
- const entries = await fetchActiveConnections(client, providerKey, cmd, {
37
+ const entries = await fetchActiveConnections(client, provider, cmd, {
40
38
  silent: true,
41
39
  });
42
40
  return entries?.length ?? 0;
@@ -63,14 +61,9 @@ export function registerModeCommand(oauth: Command): void {
63
61
  "after",
64
62
  `
65
63
  Arguments:
66
- provider Provider key, alias, or ID (e.g. google, integration:google).
64
+ provider Provider name (e.g. google, slack).
67
65
  Run "assistant oauth providers list" to see available providers.
68
66
 
69
- Options:
70
- --set <mode> Set the mode to "managed" (platform-handled credentials) or
71
- "your-own" (bring-your-own client ID and secret). Omit to
72
- show the current mode.
73
-
74
67
  Modes:
75
68
  managed OAuth credentials are managed by the Vellum platform. The
76
69
  assistant connects via a platform-hosted authorization flow.
@@ -86,10 +79,9 @@ Examples:
86
79
  .action(async (provider: string, opts: { set?: string }, cmd: Command) => {
87
80
  try {
88
81
  // -----------------------------------------------------------------
89
- // Resolve + validate provider
82
+ // Validate provider
90
83
  // -----------------------------------------------------------------
91
- const providerKey = resolveService(provider);
92
- const providerRow = getProvider(providerKey);
84
+ const providerRow = getProvider(provider);
93
85
 
94
86
  if (!providerRow) {
95
87
  writeOutput(cmd, {
@@ -102,7 +94,7 @@ Examples:
102
94
  return;
103
95
  }
104
96
 
105
- const managedKey = getManagedServiceConfigKey(providerKey);
97
+ const managedKey = getManagedServiceConfigKey(provider);
106
98
 
107
99
  // -----------------------------------------------------------------
108
100
  // GET mode (no --set flag)
@@ -113,13 +105,13 @@ Examples:
113
105
  if (shouldOutputJson(cmd)) {
114
106
  writeOutput(cmd, {
115
107
  ok: true,
116
- provider: providerKey,
108
+ provider: provider,
117
109
  mode: "your-own",
118
110
  managedModeSupported: false,
119
111
  });
120
112
  } else {
121
113
  log.info(
122
- `${providerKey} mode: your-own (managed mode not available for this provider)`,
114
+ `${provider} mode: your-own (managed mode not available for this provider)`,
123
115
  );
124
116
  }
125
117
  return;
@@ -132,12 +124,12 @@ Examples:
132
124
  if (shouldOutputJson(cmd)) {
133
125
  writeOutput(cmd, {
134
126
  ok: true,
135
- provider: providerKey,
127
+ provider: provider,
136
128
  mode: currentMode,
137
129
  managedModeSupported: true,
138
130
  });
139
131
  } else {
140
- log.info(`${providerKey} mode: ${currentMode}`);
132
+ log.info(`${provider} mode: ${currentMode}`);
141
133
  }
142
134
  return;
143
135
  }
@@ -164,14 +156,14 @@ Examples:
164
156
  if (shouldOutputJson(cmd)) {
165
157
  writeOutput(cmd, {
166
158
  ok: true,
167
- provider: providerKey,
159
+ provider: provider,
168
160
  mode: "your-own",
169
161
  changed: false,
170
162
  managedModeSupported: false,
171
163
  });
172
164
  } else {
173
165
  log.info(
174
- `${providerKey} is already set to your-own (managed mode not available for this provider)`,
166
+ `${provider} is already set to your-own (managed mode not available for this provider)`,
175
167
  );
176
168
  }
177
169
  return;
@@ -181,7 +173,7 @@ Examples:
181
173
  writeOutput(cmd, {
182
174
  ok: false,
183
175
  error:
184
- `Managed mode is not available for ${providerKey}. ` +
176
+ `Managed mode is not available for ${provider}. ` +
185
177
  `Only providers with platform-managed OAuth support can be switched to managed mode.`,
186
178
  });
187
179
  process.exitCode = 1;
@@ -197,13 +189,13 @@ Examples:
197
189
  if (shouldOutputJson(cmd)) {
198
190
  writeOutput(cmd, {
199
191
  ok: true,
200
- provider: providerKey,
192
+ provider: provider,
201
193
  mode: newMode,
202
194
  changed: false,
203
195
  managedModeSupported: true,
204
196
  });
205
197
  } else {
206
- log.info(`${providerKey} is already set to ${newMode}`);
198
+ log.info(`${provider} is already set to ${newMode}`);
207
199
  }
208
200
  return;
209
201
  }
@@ -216,32 +208,28 @@ Examples:
216
208
  // Best-effort check for active connections on old and new modes
217
209
  let oldModeConnections = 0;
218
210
  let newModeConnections = 0;
219
- const bareProvider = toBareProvider(providerKey);
220
-
221
211
  if (currentMode === "managed") {
222
212
  // Old mode was managed — check platform connections
223
- oldModeConnections = await countManagedConnections(providerKey, cmd);
213
+ oldModeConnections = await countManagedConnections(provider, cmd);
224
214
  // New mode is your-own — check local connections
225
- newModeConnections =
226
- listActiveConnectionsByProvider(providerKey).length;
215
+ newModeConnections = listActiveConnectionsByProvider(provider).length;
227
216
  } else {
228
217
  // Old mode was your-own — check local connections
229
- oldModeConnections =
230
- listActiveConnectionsByProvider(providerKey).length;
218
+ oldModeConnections = listActiveConnectionsByProvider(provider).length;
231
219
  // New mode is managed — check platform connections
232
- newModeConnections = await countManagedConnections(providerKey, cmd);
220
+ newModeConnections = await countManagedConnections(provider, cmd);
233
221
  }
234
222
 
235
223
  // Build hint if there are connections on the old mode but none on the new
236
224
  let hint: string | undefined;
237
225
  if (oldModeConnections > 0 && newModeConnections === 0) {
238
- hint = `No active connections in ${newMode} mode. Run 'assistant oauth connect ${bareProvider}' to connect.`;
226
+ hint = `No active connections in ${newMode} mode. Run 'assistant oauth connect ${provider}' to connect.`;
239
227
  }
240
228
 
241
229
  if (shouldOutputJson(cmd)) {
242
230
  const result: Record<string, unknown> = {
243
231
  ok: true,
244
- provider: providerKey,
232
+ provider: provider,
245
233
  mode: newMode,
246
234
  changed: true,
247
235
  managedModeSupported: true,
@@ -249,7 +237,7 @@ Examples:
249
237
  if (hint) result.hint = hint;
250
238
  writeOutput(cmd, result);
251
239
  } else {
252
- log.info(`${providerKey} mode changed to ${newMode}`);
240
+ log.info(`${provider} mode changed to ${newMode}`);
253
241
  if (hint) {
254
242
  process.stderr.write(hint + "\n");
255
243
  }