@vellumai/assistant 0.4.36 → 0.4.40
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.
- package/ARCHITECTURE.md +3 -3
- package/README.md +13 -13
- package/bun.lock +80 -24
- package/docs/architecture/integrations.md +126 -128
- package/docs/runbook-trusted-contacts.md +1 -1
- package/docs/trusted-contact-access.md +12 -12
- package/package.json +4 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +0 -14
- package/src/__tests__/app-bundler.test.ts +209 -0
- package/src/__tests__/app-compiler.test.ts +279 -0
- package/src/__tests__/app-executors.test.ts +293 -483
- package/src/__tests__/app-migration.test.ts +148 -0
- package/src/__tests__/app-routes-csp.test.ts +202 -0
- package/src/__tests__/avatar-e2e.test.ts +452 -0
- package/src/__tests__/avatar-generator.test.ts +193 -0
- package/src/__tests__/avatar-router.test.ts +186 -0
- package/src/__tests__/browser-download-timeout.test.ts +28 -0
- package/src/__tests__/bundled-skill-retrieval-guard.test.ts +9 -9
- package/src/__tests__/call-domain.test.ts +3 -7
- package/src/__tests__/credential-security-e2e.test.ts +19 -12
- package/src/__tests__/credentials-cli.test.ts +38 -4
- package/src/__tests__/guardian-verify-setup-skill-regression.test.ts +1 -1
- package/src/__tests__/handlers-slack-config.test.ts +0 -72
- package/src/__tests__/handlers-telegram-config.test.ts +19 -12
- package/src/__tests__/handlers-twitter-config.test.ts +105 -48
- package/src/__tests__/inbound-invite-redemption.test.ts +4 -4
- package/src/__tests__/integration-status.test.ts +15 -5
- package/src/__tests__/integrations-cli.test.ts +1 -1
- package/src/__tests__/invite-redemption-service.test.ts +62 -7
- package/src/__tests__/ipc-snapshot.test.ts +0 -8
- package/src/__tests__/managed-avatar-client.test.ts +280 -0
- package/src/__tests__/mcp-cli.test.ts +3 -3
- package/src/__tests__/oauth-cli.test.ts +203 -0
- package/src/__tests__/relay-server.test.ts +3 -3
- package/src/__tests__/secret-onetime-send.test.ts +19 -12
- package/src/__tests__/secure-keys.test.ts +78 -0
- package/src/__tests__/session-messaging-secret-redirect.test.ts +3 -0
- package/src/__tests__/slack-channel-config.test.ts +23 -16
- package/src/__tests__/slack-share-routes.test.ts +263 -0
- package/src/__tests__/sms-messaging-provider.test.ts +3 -1
- package/src/__tests__/trusted-contact-lifecycle-notifications.test.ts +7 -7
- package/src/__tests__/trusted-contact-multichannel.test.ts +3 -3
- package/src/__tests__/trusted-contact-verification.test.ts +10 -10
- package/src/__tests__/twilio-config.test.ts +15 -36
- package/src/__tests__/twilio-provider.test.ts +4 -0
- package/src/__tests__/twitter-auth-handler.test.ts +27 -14
- package/src/__tests__/twitter-cli-error-shaping.test.ts +1 -1
- package/src/__tests__/twitter-cli-routing.test.ts +38 -53
- package/src/__tests__/twitter-oauth-client.test.ts +18 -47
- package/src/__tests__/voice-invite-redemption.test.ts +27 -3
- package/src/amazon/cart.ts +1 -1
- package/src/amazon/client.ts +89 -7
- package/src/approvals/guardian-request-resolvers.ts +2 -2
- package/src/bundler/app-bundler.ts +77 -32
- package/src/bundler/app-compiler.ts +195 -0
- package/src/bundler/manifest.ts +1 -1
- package/src/bundler/package-resolver.ts +185 -0
- package/src/calls/call-domain.ts +4 -14
- package/src/calls/relay-server.ts +2 -2
- package/src/calls/twilio-config.ts +5 -24
- package/src/calls/twilio-rest.ts +19 -5
- package/src/cli/AGENTS.md +1 -1
- package/src/cli/amazon.ts +74 -249
- package/src/cli/audit.ts +2 -2
- package/src/cli/autonomy.ts +9 -9
- package/src/cli/channels.ts +5 -5
- package/src/cli/completions.ts +27 -27
- package/src/cli/config.ts +14 -14
- package/src/cli/contacts.ts +27 -27
- package/src/cli/credentials.ts +29 -29
- package/src/cli/dev.ts +2 -2
- package/src/cli/doctor.ts +2 -2
- package/src/cli/email.ts +86 -83
- package/src/cli/influencer.ts +13 -13
- package/src/cli/integrations.ts +19 -144
- package/src/cli/keys.ts +10 -10
- package/src/cli/map.ts +4 -4
- package/src/cli/mcp.ts +17 -17
- package/src/cli/memory.ts +19 -21
- package/src/cli/notifications.ts +13 -13
- package/src/cli/oauth.ts +77 -0
- package/src/cli/program.ts +2 -0
- package/src/cli/sequence.ts +27 -27
- package/src/cli/sessions.ts +12 -12
- package/src/cli/trust.ts +9 -11
- package/src/cli/twitter.ts +124 -70
- package/src/config/bundled-skills/_shared/CLI_RETRIEVAL_PATTERN.md +1 -1
- package/src/config/bundled-skills/agentmail/SKILL.md +34 -34
- package/src/config/bundled-skills/amazon/SKILL.md +54 -54
- package/src/config/bundled-skills/app-builder/SKILL.md +137 -3
- package/src/config/bundled-skills/app-builder/tools/app-create.ts +10 -4
- package/src/config/bundled-skills/configure-settings/SKILL.md +18 -18
- package/src/config/bundled-skills/contacts/SKILL.md +12 -12
- package/src/config/bundled-skills/doordash/lib/client.ts +7 -9
- package/src/config/bundled-skills/email-setup/SKILL.md +4 -4
- package/src/config/bundled-skills/frontend-design/icon.svg +16 -0
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +143 -162
- package/src/config/bundled-skills/guardian-verify-setup/SKILL.md +4 -4
- package/src/config/bundled-skills/influencer/SKILL.md +13 -13
- package/src/config/bundled-skills/mcp-setup/SKILL.md +11 -11
- package/src/config/bundled-skills/phone-calls/SKILL.md +48 -54
- package/src/config/bundled-skills/public-ingress/SKILL.md +6 -6
- package/src/config/bundled-skills/slack-app-setup/SKILL.md +1 -1
- package/src/config/bundled-skills/sms-setup/SKILL.md +3 -3
- package/src/config/bundled-skills/telegram-setup/SKILL.md +2 -2
- package/src/config/bundled-skills/twilio-setup/SKILL.md +136 -225
- package/src/config/bundled-skills/twitter/SKILL.md +68 -44
- package/src/config/bundled-skills/voice-setup/SKILL.md +2 -2
- package/src/config/core-schema.ts +26 -0
- package/src/config/env.ts +4 -0
- package/src/config/feature-flag-registry.json +9 -1
- package/src/config/schema.ts +8 -0
- package/src/config/system-prompt.ts +6 -3
- package/src/config/templates/BOOTSTRAP.md +7 -5
- package/src/contacts/contacts-write.ts +5 -1
- package/src/daemon/handlers/apps.ts +31 -4
- package/src/daemon/handlers/config-ingress.ts +3 -3
- package/src/daemon/handlers/config-integrations.ts +120 -49
- package/src/daemon/handlers/config-slack-channel.ts +26 -7
- package/src/daemon/handlers/config-slack.ts +1 -54
- package/src/daemon/handlers/config-telegram.ts +28 -10
- package/src/daemon/handlers/config.ts +1 -4
- package/src/daemon/handlers/twitter-auth.ts +11 -4
- package/src/daemon/ipc-contract/apps.ts +0 -13
- package/src/daemon/ipc-contract-inventory.json +0 -2
- package/src/daemon/lifecycle.ts +8 -1
- package/src/daemon/session-messaging.ts +2 -2
- package/src/daemon/tool-side-effects.ts +30 -0
- package/src/email/providers/agentmail.ts +1 -1
- package/src/email/providers/index.ts +1 -1
- package/src/email/service.ts +1 -1
- package/src/gallery/default-gallery.ts +538 -0
- package/src/gallery/gallery-manifest.ts +5 -1
- package/src/influencer/client.ts +8 -6
- package/src/mcp/client.ts +1 -1
- package/src/media/avatar-router.ts +99 -0
- package/src/media/avatar-types.ts +60 -0
- package/src/media/managed-avatar-client.ts +189 -0
- package/src/memory/app-migration.ts +114 -0
- package/src/memory/app-store.ts +11 -0
- package/src/memory/qdrant-client.ts +1 -1
- package/src/messaging/providers/slack/client.ts +12 -2
- package/src/messaging/providers/sms/adapter.ts +6 -10
- package/src/migrations/data-layout.ts +8 -1
- package/src/oauth/token-persistence.ts +9 -6
- package/src/runtime/assistant-scope.ts +5 -0
- package/src/runtime/auth/route-policy.ts +4 -0
- package/src/runtime/channel-readiness-service.ts +9 -4
- package/src/runtime/gateway-internal-client.ts +11 -3
- package/src/runtime/http-server.ts +2 -0
- package/src/runtime/invite-redemption-service.ts +23 -13
- package/src/runtime/middleware/twilio-validation.ts +2 -2
- package/src/runtime/routes/app-routes.ts +131 -3
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +3 -3
- package/src/runtime/routes/integration-routes.ts +2 -2
- package/src/runtime/routes/slack-share-routes.ts +235 -0
- package/src/runtime/routes/twilio-routes.ts +47 -34
- package/src/schedule/integration-status.ts +2 -3
- package/src/security/token-manager.ts +11 -3
- package/src/tools/apps/executors.ts +116 -8
- package/src/tools/browser/browser-manager.ts +30 -2
- package/src/tools/browser/chrome-cdp.ts +31 -3
- package/src/tools/credentials/vault.ts +9 -7
- package/src/tools/executor.ts +4 -0
- package/src/tools/system/avatar-generator.ts +55 -34
- package/src/twitter/client.ts +1 -1
- package/src/twitter/oauth-client.ts +31 -43
- package/src/twitter/router.ts +25 -23
- package/src/util/platform.ts +5 -0
- package/src/slack/slack-webhook.ts +0 -66
|
@@ -190,7 +190,7 @@ sequenceDiagram
|
|
|
190
190
|
|
|
191
191
|
#### Dual-Path Operation Architecture
|
|
192
192
|
|
|
193
|
-
The strategy router (`router.ts`) determines whether to use the OAuth or browser path for each operation. The preferred strategy is read from the `
|
|
193
|
+
The strategy router (`router.ts`) determines whether to use the OAuth or browser path for each operation. The preferred strategy is read from the `twitter.operationStrategy` config field (default: `auto`).
|
|
194
194
|
|
|
195
195
|
```mermaid
|
|
196
196
|
flowchart TD
|
|
@@ -215,19 +215,19 @@ flowchart TD
|
|
|
215
215
|
- **`oauth`**: Uses OAuth exclusively. Fails with an actionable error if credentials are not configured.
|
|
216
216
|
- **`browser`**: Uses CDP exclusively. Fails with an actionable error if the browser session has expired.
|
|
217
217
|
|
|
218
|
-
The strategy is persisted in the Vellum config file as `
|
|
218
|
+
The strategy is persisted in the Vellum config file as `twitter.operationStrategy` and can be changed via `vellum x strategy set <oauth|browser|auto>`.
|
|
219
219
|
|
|
220
220
|
#### Twitter OAuth2 Specifics
|
|
221
221
|
|
|
222
|
-
| Aspect
|
|
223
|
-
|
|
224
|
-
| Auth URL
|
|
225
|
-
| Token URL
|
|
226
|
-
| Flow
|
|
227
|
-
| Default scopes
|
|
228
|
-
| Identity verification | Provider profile `identityVerifier` → `GET https://api.x.com/2/users/me` with Bearer token
|
|
229
|
-
| Credential names
|
|
230
|
-
| IPC messages
|
|
222
|
+
| Aspect | Detail |
|
|
223
|
+
| --------------------- | ------------------------------------------------------------------------------------------------------------------ |
|
|
224
|
+
| Auth URL | `https://twitter.com/i/oauth2/authorize` (from provider profile) |
|
|
225
|
+
| Token URL | `https://api.x.com/2/oauth2/token` (from provider profile) |
|
|
226
|
+
| Flow | PKCE (S256), optional client secret, via connect orchestrator |
|
|
227
|
+
| Default scopes | `tweet.read`, `tweet.write`, `users.read`, `offline.access` (from provider profile) |
|
|
228
|
+
| Identity verification | Provider profile `identityVerifier` → `GET https://api.x.com/2/users/me` with Bearer token |
|
|
229
|
+
| Credential names | Canonical: `client_id`, `client_secret`; reads fall back to legacy `oauth_client_id`, `oauth_client_secret` |
|
|
230
|
+
| IPC messages | `oauth_connect_start` / `oauth_connect_result` (generic), plus legacy `twitter_auth_start` / `twitter_auth_status` |
|
|
231
231
|
|
|
232
232
|
#### Twitter Credential Metadata Structure
|
|
233
233
|
|
|
@@ -254,73 +254,73 @@ When the OAuth2 flow completes, the handler stores credential metadata at `integ
|
|
|
254
254
|
|
|
255
255
|
#### Available Twitter Tools
|
|
256
256
|
|
|
257
|
-
| Tool / Command
|
|
258
|
-
|
|
259
|
-
| `vellum x post`
|
|
260
|
-
| `vellum x reply`
|
|
261
|
-
| `vellum x timeline`
|
|
262
|
-
| `vellum x search`
|
|
263
|
-
| `vellum x home`
|
|
264
|
-
| `vellum x notifications` | CDP
|
|
265
|
-
| `vellum x bookmarks`
|
|
266
|
-
| `vellum x likes`
|
|
267
|
-
| `vellum x followers`
|
|
268
|
-
| `vellum x following`
|
|
269
|
-
| `vellum x media`
|
|
270
|
-
| `vellum x strategy`
|
|
271
|
-
| `vellum x status`
|
|
257
|
+
| Tool / Command | Mechanism | Description |
|
|
258
|
+
| ------------------------ | ------------------------------ | ------------------------------------------------------------------- |
|
|
259
|
+
| `vellum x post` | Strategy router (OAuth or CDP) | Post a tweet. Uses the configured strategy (`auto` by default). |
|
|
260
|
+
| `vellum x reply` | Strategy router (OAuth or CDP) | Reply to a tweet. Uses the configured strategy (`auto` by default). |
|
|
261
|
+
| `vellum x timeline` | CDP | Fetch a user's recent tweets. Browser path only. |
|
|
262
|
+
| `vellum x search` | CDP | Search tweets. Browser path only. |
|
|
263
|
+
| `vellum x home` | CDP | Fetch home timeline. Browser path only. |
|
|
264
|
+
| `vellum x notifications` | CDP | Fetch notifications. Browser path only. |
|
|
265
|
+
| `vellum x bookmarks` | CDP | Fetch bookmarks. Browser path only. |
|
|
266
|
+
| `vellum x likes` | CDP | Fetch a user's liked tweets. Browser path only. |
|
|
267
|
+
| `vellum x followers` | CDP | Fetch a user's followers. Browser path only. |
|
|
268
|
+
| `vellum x following` | CDP | Fetch who a user follows. Browser path only. |
|
|
269
|
+
| `vellum x media` | CDP | Fetch a user's media tweets. Browser path only. |
|
|
270
|
+
| `vellum x strategy` | Config | Get or set the operation strategy (`oauth`, `browser`, `auto`). |
|
|
271
|
+
| `vellum x status` | IPC + local | Check browser session, OAuth connection, and strategy status. |
|
|
272
272
|
|
|
273
273
|
Note: OAuth2 scopes (`tweet.read`, `tweet.write`, `users.read`, `offline.access`) are requested during the auth flow. The `post` and `reply` operations use these tokens when the OAuth path is selected. Read operations require the browser path.
|
|
274
274
|
|
|
275
275
|
### Key Design Decisions
|
|
276
276
|
|
|
277
|
-
| Decision
|
|
278
|
-
|
|
279
|
-
| PKCE by default, optional client_secret
|
|
280
|
-
| Shared connect orchestrator
|
|
281
|
-
| Canonical credential naming
|
|
282
|
-
| Gateway callback transport
|
|
283
|
-
| Unified `MessagingProvider` interface
|
|
284
|
-
| Twitter outside unified messaging
|
|
285
|
-
| Dual-path Twitter strategy
|
|
286
|
-
| Provider auto-selection
|
|
287
|
-
| Token expiry in credential metadata
|
|
288
|
-
| Confidence scores on medium-risk tools
|
|
289
|
-
| Platform-specific extension tools
|
|
290
|
-
| Twitter identity verification before token storage | OAuth2 tokens are only persisted after a successful `GET /2/users/me` call, preventing storage of invalid or mismatched credentials
|
|
277
|
+
| Decision | Rationale |
|
|
278
|
+
| -------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
279
|
+
| PKCE by default, optional client_secret | Desktop apps prefer PKCE; some providers (Slack) require a secret, which is stored in credential metadata for autonomous refresh |
|
|
280
|
+
| Shared connect orchestrator | All OAuth providers route through `orchestrateOAuthConnect()`, which resolves profiles, enforces scope policy, runs the flow, stores tokens, and verifies identity. Adding a provider is a declarative profile entry, not new orchestration code |
|
|
281
|
+
| Canonical credential naming | Writes use `client_id`/`client_secret`; reads fall back to legacy `oauth_client_id`/`oauth_client_secret` for backward compatibility |
|
|
282
|
+
| Gateway callback transport | OAuth callbacks are now routed through the gateway at `${ingress.publicBaseUrl}/webhooks/oauth/callback` instead of a loopback redirect URI. This enables OAuth flows to work in remote and tunneled deployments. |
|
|
283
|
+
| Unified `MessagingProvider` interface | All platforms implement the same contract; generic tools work immediately for new providers |
|
|
284
|
+
| Twitter outside unified messaging | Twitter is a broadcast/read platform, not a conversation platform — it doesn't fit the `MessagingProvider` contract |
|
|
285
|
+
| Dual-path Twitter strategy | OAuth is more reliable for posting (no browser session dependency) but only supports post/reply. Browser path supports all operations. `auto` strategy gives the best of both: OAuth when possible, browser as fallback. User can override via `vellum x strategy set`. |
|
|
286
|
+
| Provider auto-selection | If only one provider is connected, tools skip the `platform` parameter — seamless single-platform UX |
|
|
287
|
+
| Token expiry in credential metadata | Reuses existing `CredentialMetadata` store; `expiresAt` field enables proactive refresh with 5min buffer |
|
|
288
|
+
| Confidence scores on medium-risk tools | LLM self-reports confidence (0-1); enables future trust calibration without blocking execution |
|
|
289
|
+
| Platform-specific extension tools | Operations unique to one platform (e.g. Gmail labels, Slack reactions) are separate tools, not forced into the generic interface |
|
|
290
|
+
| Twitter identity verification before token storage | OAuth2 tokens are only persisted after a successful `GET /2/users/me` call, preventing storage of invalid or mismatched credentials |
|
|
291
291
|
|
|
292
292
|
### Source Files
|
|
293
293
|
|
|
294
|
-
| File
|
|
295
|
-
|
|
296
|
-
| `assistant/src/security/oauth2.ts`
|
|
297
|
-
| `assistant/src/security/token-manager.ts`
|
|
298
|
-
| `assistant/src/messaging/provider.ts`
|
|
299
|
-
| `assistant/src/messaging/provider-types.ts`
|
|
300
|
-
| `assistant/src/messaging/registry.ts`
|
|
301
|
-
| `assistant/src/messaging/activity-analyzer.ts`
|
|
302
|
-
| `assistant/src/messaging/style-analyzer.ts`
|
|
303
|
-
| `assistant/src/messaging/draft-store.ts`
|
|
304
|
-
| `assistant/src/messaging/providers/slack/`
|
|
305
|
-
| `assistant/src/messaging/providers/gmail/`
|
|
306
|
-
| `assistant/src/config/bundled-skills/messaging/`
|
|
307
|
-
| `assistant/src/watcher/providers/slack.ts`
|
|
308
|
-
| `assistant/src/watcher/providers/gmail.ts`
|
|
309
|
-
| `assistant/src/watcher/providers/github.ts`
|
|
310
|
-
| `assistant/src/watcher/providers/linear.ts`
|
|
311
|
-
| `assistant/src/oauth/provider-profiles.ts`
|
|
312
|
-
| `assistant/src/oauth/connect-orchestrator.ts`
|
|
313
|
-
| `assistant/src/oauth/scope-policy.ts`
|
|
314
|
-
| `assistant/src/oauth/connect-types.ts`
|
|
315
|
-
| `assistant/src/oauth/token-persistence.ts`
|
|
316
|
-
| `assistant/src/daemon/handlers/oauth-connect.ts`
|
|
317
|
-
| `assistant/src/daemon/handlers/twitter-auth.ts`
|
|
318
|
-
| `assistant/src/twitter/client.ts`
|
|
319
|
-
| `assistant/src/twitter/oauth-client.ts`
|
|
320
|
-
| `assistant/src/twitter/router.ts`
|
|
321
|
-
| `assistant/src/twitter/session.ts`
|
|
322
|
-
| `assistant/src/cli/twitter.ts`
|
|
323
|
-
| `assistant/src/config/bundled-skills/twitter/SKILL.md` | X (Twitter) bundled skill instructions
|
|
294
|
+
| File | Role |
|
|
295
|
+
| ------------------------------------------------------ | --------------------------------------------------------------------------------------------------------- |
|
|
296
|
+
| `assistant/src/security/oauth2.ts` | OAuth2 flow: PKCE or client_secret, Bun.serve callback, token exchange |
|
|
297
|
+
| `assistant/src/security/token-manager.ts` | `withValidToken()` — auto-refresh, 401 retry, expiry buffer |
|
|
298
|
+
| `assistant/src/messaging/provider.ts` | `MessagingProvider` interface |
|
|
299
|
+
| `assistant/src/messaging/provider-types.ts` | Platform-agnostic types (Conversation, Message, SearchResult) |
|
|
300
|
+
| `assistant/src/messaging/registry.ts` | Provider registry: register, lookup, list connected |
|
|
301
|
+
| `assistant/src/messaging/activity-analyzer.ts` | Activity classification for conversations |
|
|
302
|
+
| `assistant/src/messaging/style-analyzer.ts` | Writing style extraction from message corpus |
|
|
303
|
+
| `assistant/src/messaging/draft-store.ts` | Local draft storage (platform/id JSON files) |
|
|
304
|
+
| `assistant/src/messaging/providers/slack/` | Slack adapter, client, types |
|
|
305
|
+
| `assistant/src/messaging/providers/gmail/` | Gmail adapter, client, types |
|
|
306
|
+
| `assistant/src/config/bundled-skills/messaging/` | Unified messaging skill (SKILL.md, TOOLS.json, tools/) |
|
|
307
|
+
| `assistant/src/watcher/providers/slack.ts` | Slack watcher for DMs, mentions, thread replies |
|
|
308
|
+
| `assistant/src/watcher/providers/gmail.ts` | Gmail watcher using History API |
|
|
309
|
+
| `assistant/src/watcher/providers/github.ts` | GitHub watcher for PRs, issues, review requests, and mentions |
|
|
310
|
+
| `assistant/src/watcher/providers/linear.ts` | Linear watcher for assigned issues, status changes, and @mentions |
|
|
311
|
+
| `assistant/src/oauth/provider-profiles.ts` | Provider profile registry: auth URLs, token URLs, scopes, policies, identity verifiers |
|
|
312
|
+
| `assistant/src/oauth/connect-orchestrator.ts` | Shared OAuth connect orchestrator: profile resolution, scope policy, flow execution, token storage |
|
|
313
|
+
| `assistant/src/oauth/scope-policy.ts` | Deterministic scope resolution and policy enforcement |
|
|
314
|
+
| `assistant/src/oauth/connect-types.ts` | Shared types: `OAuthProviderProfile`, `OAuthScopePolicy`, `OAuthConnectResult` |
|
|
315
|
+
| `assistant/src/oauth/token-persistence.ts` | Token storage helper: persists tokens, metadata, and runs post-connect hooks |
|
|
316
|
+
| `assistant/src/daemon/handlers/oauth-connect.ts` | Generic OAuth connect IPC handler (`oauth_connect_start` / `oauth_connect_result`) |
|
|
317
|
+
| `assistant/src/daemon/handlers/twitter-auth.ts` | Legacy Twitter OAuth2 flow handlers (`twitter_auth_start`, `twitter_auth_status`) |
|
|
318
|
+
| `assistant/src/twitter/client.ts` | Twitter CDP client: GraphQL mutations/queries via Chrome DevTools Protocol |
|
|
319
|
+
| `assistant/src/twitter/oauth-client.ts` | OAuth-backed Twitter client: X API v2 post/reply via stored tokens using `withValidToken()` |
|
|
320
|
+
| `assistant/src/twitter/router.ts` | Strategy router: selects OAuth or browser path based on `twitter.operationStrategy` config |
|
|
321
|
+
| `assistant/src/twitter/session.ts` | Twitter browser session persistence (cookie import/export) |
|
|
322
|
+
| `assistant/src/cli/twitter.ts` | `vellum x` CLI command group (post, reply, strategy, refresh, status, login, logout, and read operations) |
|
|
323
|
+
| `assistant/src/config/bundled-skills/twitter/SKILL.md` | X (Twitter) bundled skill instructions |
|
|
324
324
|
|
|
325
325
|
---
|
|
326
326
|
|
|
@@ -332,15 +332,15 @@ The OAuth extensibility layer makes adding a new OAuth provider a declarative op
|
|
|
332
332
|
|
|
333
333
|
`assistant/src/oauth/provider-profiles.ts` contains the `PROVIDER_PROFILES` map — a canonical registry of well-known OAuth providers. Each profile (`OAuthProviderProfile`) declares:
|
|
334
334
|
|
|
335
|
-
| Field
|
|
336
|
-
|
|
337
|
-
| `authUrl` / `tokenUrl` | OAuth2 authorization and token endpoints
|
|
338
|
-
| `defaultScopes`
|
|
339
|
-
| `scopePolicy`
|
|
340
|
-
| `callbackTransport`
|
|
341
|
-
| `identityVerifier`
|
|
342
|
-
| `setup`
|
|
343
|
-
| `injectionTemplates`
|
|
335
|
+
| Field | Purpose |
|
|
336
|
+
| ---------------------- | ------------------------------------------------------------------------------------------------------ |
|
|
337
|
+
| `authUrl` / `tokenUrl` | OAuth2 authorization and token endpoints |
|
|
338
|
+
| `defaultScopes` | Scopes requested on every connect attempt |
|
|
339
|
+
| `scopePolicy` | Controls whether additional scopes are allowed (see Scope Policy below) |
|
|
340
|
+
| `callbackTransport` | `'loopback'` (local redirect) or `'gateway'` (public ingress) |
|
|
341
|
+
| `identityVerifier` | Async function that fetches human-readable account info (e.g. `@username`, email) after token exchange |
|
|
342
|
+
| `setup` | Optional metadata for the generic OAuth setup skill (display name, dashboard URL, app type) |
|
|
343
|
+
| `injectionTemplates` | Auto-applied credential injection rules for the script proxy |
|
|
344
344
|
|
|
345
345
|
Registered providers: `integration:gmail`, `integration:slack`, `integration:notion`, `integration:twitter`. Short aliases (e.g. `gmail`, `twitter`) are resolved via `SERVICE_ALIASES`.
|
|
346
346
|
|
|
@@ -394,18 +394,17 @@ This replaces provider-specific IPC handlers — any provider in the registry ca
|
|
|
394
394
|
|
|
395
395
|
### Key Source Files
|
|
396
396
|
|
|
397
|
-
| File
|
|
398
|
-
|
|
399
|
-
| `assistant/src/oauth/provider-profiles.ts`
|
|
400
|
-
| `assistant/src/oauth/scope-policy.ts`
|
|
401
|
-
| `assistant/src/oauth/connect-orchestrator.ts`
|
|
402
|
-
| `assistant/src/oauth/connect-types.ts`
|
|
403
|
-
| `assistant/src/oauth/token-persistence.ts`
|
|
404
|
-
| `assistant/src/daemon/handlers/oauth-connect.ts` | Generic `oauth_connect_start` / `oauth_connect_result` IPC handler
|
|
397
|
+
| File | Role |
|
|
398
|
+
| ------------------------------------------------ | ------------------------------------------------------------------------------- |
|
|
399
|
+
| `assistant/src/oauth/provider-profiles.ts` | Provider profile registry and alias resolution |
|
|
400
|
+
| `assistant/src/oauth/scope-policy.ts` | Scope resolution and policy enforcement (pure, no I/O) |
|
|
401
|
+
| `assistant/src/oauth/connect-orchestrator.ts` | Shared connect orchestrator (profile → scopes → flow → tokens) |
|
|
402
|
+
| `assistant/src/oauth/connect-types.ts` | Shared types (`OAuthProviderProfile`, `OAuthScopePolicy`, `OAuthConnectResult`) |
|
|
403
|
+
| `assistant/src/oauth/token-persistence.ts` | Token storage: keychain writes, metadata upsert, post-connect hooks |
|
|
404
|
+
| `assistant/src/daemon/handlers/oauth-connect.ts` | Generic `oauth_connect_start` / `oauth_connect_result` IPC handler |
|
|
405
405
|
|
|
406
406
|
---
|
|
407
407
|
|
|
408
|
-
|
|
409
408
|
---
|
|
410
409
|
|
|
411
410
|
## Script Proxy — Proxied Bash Execution and Credential Injection
|
|
@@ -536,14 +535,14 @@ sequenceDiagram
|
|
|
536
535
|
|
|
537
536
|
**Policy decisions** are deterministic and structured:
|
|
538
537
|
|
|
539
|
-
| Decision
|
|
540
|
-
|
|
541
|
-
| `matched`
|
|
542
|
-
| `ambiguous`
|
|
543
|
-
| `missing`
|
|
544
|
-
| `unauthenticated`
|
|
538
|
+
| Decision | Meaning |
|
|
539
|
+
| ------------------------ | -------------------------------------------------------------------------- |
|
|
540
|
+
| `matched` | Exactly one credential template matches the host — inject it |
|
|
541
|
+
| `ambiguous` | Multiple credential templates match — caller must disambiguate |
|
|
542
|
+
| `missing` | Credentials exist but none match this host — no rewrite |
|
|
543
|
+
| `unauthenticated` | No credentials configured for the session |
|
|
545
544
|
| `ask_missing_credential` | A known template pattern matches but no credential is bound to the session |
|
|
546
|
-
| `ask_unauthenticated`
|
|
545
|
+
| `ask_unauthenticated` | Completely unknown host — prompt for unauthenticated access |
|
|
547
546
|
|
|
548
547
|
**Trust rule persistence**: The `createProxyApprovalCallback` in `session-tool-setup.ts` is wired into the session startup path and routes policy "ask" decisions through the existing `PermissionPrompter` UI. Trust rules use the `network_request` tool name (not `proxy:*`) with URL-based scope patterns (e.g., `https://api.example.com/*`), aligning with the `buildCommandCandidates()` allowlist generation in `checker.ts`.
|
|
549
548
|
|
|
@@ -566,10 +565,10 @@ Each proxy session is bound to a conversation and tracks authorized credential I
|
|
|
566
565
|
|
|
567
566
|
The proxy generates and manages a local Certificate Authority for MITM interception:
|
|
568
567
|
|
|
569
|
-
| Component
|
|
570
|
-
|
|
571
|
-
| CA cert
|
|
572
|
-
| CA key
|
|
568
|
+
| Component | Location | Purpose |
|
|
569
|
+
| ---------- | ------------------------------------------ | -------------------------------------------------------- |
|
|
570
|
+
| CA cert | `{dataDir}/proxy-ca/ca.pem` | Self-signed root cert (valid 10 years, permissions 0644) |
|
|
571
|
+
| CA key | `{dataDir}/proxy-ca/ca-key.pem` | CA private key (permissions 0600) |
|
|
573
572
|
| Leaf certs | `{dataDir}/proxy-ca/issued/{hostname}.pem` | Per-hostname certs (cached, verified against current CA) |
|
|
574
573
|
|
|
575
574
|
`ensureLocalCA()` is idempotent — it only generates the CA if the files do not already exist. Leaf certificates are cached and revalidated via `X509Certificate.checkIssued()` to detect stale certs from a previous CA.
|
|
@@ -602,20 +601,20 @@ The proxy subsystem intercepts outbound HTTPS requests and injects stored creden
|
|
|
602
601
|
|
|
603
602
|
### Key Source Files
|
|
604
603
|
|
|
605
|
-
| File
|
|
606
|
-
|
|
607
|
-
| `assistant/src/tools/network/script-proxy/server.ts`
|
|
608
|
-
| `assistant/src/tools/network/script-proxy/policy.ts`
|
|
609
|
-
| `assistant/src/tools/network/script-proxy/mitm-handler.ts`
|
|
610
|
-
| `assistant/src/tools/network/script-proxy/connect-tunnel.ts`
|
|
611
|
-
| `assistant/src/tools/network/script-proxy/http-forwarder.ts`
|
|
612
|
-
| `assistant/src/tools/network/script-proxy/session-manager.ts` | Session lifecycle — create, start, stop, idle timeout, env var generation
|
|
613
|
-
| `assistant/src/tools/network/script-proxy/certs.ts`
|
|
614
|
-
| `assistant/src/tools/network/script-proxy/logging.ts`
|
|
615
|
-
| `assistant/src/tools/network/script-proxy/types.ts`
|
|
616
|
-
| `assistant/src/tools/executor.ts`
|
|
617
|
-
| `assistant/src/daemon/session-tool-setup.ts`
|
|
618
|
-
| `assistant/src/permissions/checker.ts`
|
|
604
|
+
| File | Role |
|
|
605
|
+
| ------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------- |
|
|
606
|
+
| `assistant/src/tools/network/script-proxy/server.ts` | Proxy server factory — HTTP forwarding, CONNECT handling, MITM dispatch |
|
|
607
|
+
| `assistant/src/tools/network/script-proxy/policy.ts` | Policy engine — evaluates requests against credential templates |
|
|
608
|
+
| `assistant/src/tools/network/script-proxy/mitm-handler.ts` | MITM TLS interception — loopback TLS server, request rewrite, upstream forwarding |
|
|
609
|
+
| `assistant/src/tools/network/script-proxy/connect-tunnel.ts` | Plain CONNECT tunnel — raw TCP bidirectional pipe |
|
|
610
|
+
| `assistant/src/tools/network/script-proxy/http-forwarder.ts` | HTTP proxy forwarder — absolute-URL form forwarding with policy callback |
|
|
611
|
+
| `assistant/src/tools/network/script-proxy/session-manager.ts` | Session lifecycle — create, start, stop, idle timeout, env var generation |
|
|
612
|
+
| `assistant/src/tools/network/script-proxy/certs.ts` | Local CA management — ensureLocalCA, issueLeafCert, getCAPath |
|
|
613
|
+
| `assistant/src/tools/network/script-proxy/logging.ts` | Log sanitization (header/URL redaction) and safe decision trace builders for policy and credential resolution |
|
|
614
|
+
| `assistant/src/tools/network/script-proxy/types.ts` | Type definitions — session, policy decisions, approval callback |
|
|
615
|
+
| `assistant/src/tools/executor.ts` | `persistentDecisionsAllowed` gate — disables trust rule saving for proxied bash |
|
|
616
|
+
| `assistant/src/daemon/session-tool-setup.ts` | `createProxyApprovalCallback` — wired into session startup, uses `network_request` tool name with URL-based trust rules |
|
|
617
|
+
| `assistant/src/permissions/checker.ts` | `network_request` trust rule matching and risk classification (Medium) |
|
|
619
618
|
|
|
620
619
|
### Runtime Wiring Summary
|
|
621
620
|
|
|
@@ -690,13 +689,13 @@ graph TB
|
|
|
690
689
|
|
|
691
690
|
### Search Capabilities
|
|
692
691
|
|
|
693
|
-
| Parameter
|
|
694
|
-
|
|
695
|
-
| `mime_type`
|
|
696
|
-
| `filename`
|
|
697
|
-
| `recency`
|
|
698
|
-
| `conversation_id` | string | Scope results to attachments in a specific conversation
|
|
699
|
-
| `limit`
|
|
692
|
+
| Parameter | Type | Description |
|
|
693
|
+
| ----------------- | ------ | ---------------------------------------------------------------------------------------------- |
|
|
694
|
+
| `mime_type` | string | MIME type filter with wildcard support (`image/*`, `application/pdf`) |
|
|
695
|
+
| `filename` | string | Case-insensitive substring match on original filename |
|
|
696
|
+
| `recency` | enum | Time-based filter: `last_hour`, `last_24_hours`, `last_7_days`, `last_30_days`, `last_90_days` |
|
|
697
|
+
| `conversation_id` | string | Scope results to attachments in a specific conversation |
|
|
698
|
+
| `limit` | number | Maximum results (default 20, max 100) |
|
|
700
699
|
|
|
701
700
|
### Materialize Safeguards
|
|
702
701
|
|
|
@@ -707,13 +706,12 @@ graph TB
|
|
|
707
706
|
|
|
708
707
|
### Key Source Files
|
|
709
708
|
|
|
710
|
-
| File
|
|
711
|
-
|
|
712
|
-
| `assistant/src/tools/assets/search.ts`
|
|
713
|
-
| `assistant/src/tools/assets/materialize.ts`
|
|
714
|
-
| `assistant/src/daemon/media-visibility-policy.ts` | Pure policy module — `isAttachmentVisible()`, `filterVisibleAttachments()`
|
|
715
|
-
| `assistant/src/memory/schema.ts`
|
|
716
|
-
| `assistant/src/memory/conversation-store.ts`
|
|
709
|
+
| File | Role |
|
|
710
|
+
| ------------------------------------------------- | --------------------------------------------------------------------------------------- |
|
|
711
|
+
| `assistant/src/tools/assets/search.ts` | `asset_search` tool — cross-thread attachment metadata search with visibility filtering |
|
|
712
|
+
| `assistant/src/tools/assets/materialize.ts` | `asset_materialize` tool — decode and write attachment to sandbox path |
|
|
713
|
+
| `assistant/src/daemon/media-visibility-policy.ts` | Pure policy module — `isAttachmentVisible()`, `filterVisibleAttachments()` |
|
|
714
|
+
| `assistant/src/memory/schema.ts` | `attachments` and `message_attachments` table schemas |
|
|
715
|
+
| `assistant/src/memory/conversation-store.ts` | `getConversationThreadType()` — thread type lookup for visibility context |
|
|
717
716
|
|
|
718
717
|
---
|
|
719
|
-
|
|
@@ -35,7 +35,7 @@ Design doc defining how unknown users gain access to a Vellum assistant via chan
|
|
|
35
35
|
5. **Guardian receives the verification code.** The assistant delivers the code to the guardian's verified channel (Telegram chat, SMS, etc.).
|
|
36
36
|
6. **Guardian gives the code to the requester out-of-band** (in person, text message, phone call, etc.). This out-of-band transfer is the trust anchor: it proves the requester has a real-world relationship with the guardian.
|
|
37
37
|
7. **Requester enters the code** back to the assistant on the same channel. The inbound message handler intercepts bare 6-digit codes when a pending verification session exists for that channel.
|
|
38
|
-
8. **Assistant verifies the code and activates the user.** `validateAndConsumeChallenge()` hashes the code, matches it against the pending session, verifies identity binding (the code must come from the expected channel identity), consumes the challenge, and calls `
|
|
38
|
+
8. **Assistant verifies the code and activates the user.** `validateAndConsumeChallenge()` hashes the code, matches it against the pending session, verifies identity binding (the code must come from the expected channel identity), consumes the challenge, and calls `upsertContactChannel()` with `status: 'active'` and `policy: 'allow'`.
|
|
39
39
|
9. **All subsequent messages are accepted normally.** The ingress ACL finds an active member record and allows the message through.
|
|
40
40
|
|
|
41
41
|
## Lifecycle States
|
|
@@ -92,11 +92,11 @@ Identity binding ensures the verification code can only be consumed by the inten
|
|
|
92
92
|
|
|
93
93
|
### Stage: `active` (code verified, trusted contact created)
|
|
94
94
|
|
|
95
|
-
| Store | Table | Record
|
|
96
|
-
| --------------------------- | ------------------------------------------ |
|
|
97
|
-
| `contacts-write.ts` | `contacts` / `contact_channels` | Upserted via `
|
|
98
|
-
| `channel-guardian-store.ts` | `channel_guardian_verification_challenges` | Updated to `status: 'consumed'`, `consumedByExternalUserId`, `consumedByChatId` set.
|
|
99
|
-
| `channel-guardian-store.ts` | `channel_guardian_rate_limits` | Reset via `resetRateLimit()` on successful verification.
|
|
95
|
+
| Store | Table | Record |
|
|
96
|
+
| --------------------------- | ------------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
|
97
|
+
| `contacts-write.ts` | `contacts` / `contact_channels` | Upserted via `upsertContactChannel()`: creates a contact record and a `contact_channels` entry with `status: 'active'`, `policy: 'allow'`, channel type, `externalUserId`, `externalChatId`, `displayName`. |
|
|
98
|
+
| `channel-guardian-store.ts` | `channel_guardian_verification_challenges` | Updated to `status: 'consumed'`, `consumedByExternalUserId`, `consumedByChatId` set. |
|
|
99
|
+
| `channel-guardian-store.ts` | `channel_guardian_rate_limits` | Reset via `resetRateLimit()` on successful verification. |
|
|
100
100
|
|
|
101
101
|
### Stage: `denied` (guardian rejected)
|
|
102
102
|
|
|
@@ -132,15 +132,15 @@ Voice calls have a dedicated in-call guardian approval flow that differs from th
|
|
|
132
132
|
3. On name capture, `notifyGuardianOfAccessRequest` creates a canonical guardian request (`kind: 'access_request'`) and notifies the guardian.
|
|
133
133
|
4. Relay transitions to `awaiting_guardian_decision` and polls `canonical_guardian_requests` for status changes.
|
|
134
134
|
5. Guardian approves or denies via any channel. All decisions route through `applyCanonicalGuardianDecision`.
|
|
135
|
-
6. On approval: the `access_request` resolver directly activates the caller as a trusted contact (`
|
|
135
|
+
6. On approval: the `access_request` resolver directly activates the caller as a trusted contact (`upsertContactChannel` with `status: 'active'`, `policy: 'allow'`) — no verification session needed since the caller is already authenticated by their phone number.
|
|
136
136
|
7. On denial or timeout: the caller hears a denial message and the call ends.
|
|
137
137
|
|
|
138
138
|
**Key difference from text-channel flow:** Voice approvals skip the verification session step because the caller's phone identity is already known from the active call. Text-channel approvals still mint a 6-digit verification code for out-of-band identity confirmation.
|
|
139
139
|
|
|
140
|
-
| Store | Table | Record
|
|
141
|
-
| ----------------------------- | ------------------------------- |
|
|
142
|
-
| `canonical-guardian-store.ts` | `canonical_guardian_requests` | `kind: 'access_request'`, `status: 'pending'` -> `'approved'` or `'denied'`
|
|
143
|
-
| `contacts-write.ts` | `contacts` / `contact_channels` | On approval: upserted via `
|
|
140
|
+
| Store | Table | Record |
|
|
141
|
+
| ----------------------------- | ------------------------------- | --------------------------------------------------------------------------------------------- |
|
|
142
|
+
| `canonical-guardian-store.ts` | `canonical_guardian_requests` | `kind: 'access_request'`, `status: 'pending'` -> `'approved'` or `'denied'` |
|
|
143
|
+
| `contacts-write.ts` | `contacts` / `contact_channels` | On approval: upserted via `upsertContactChannel()` with `status: 'active'`, `policy: 'allow'` |
|
|
144
144
|
|
|
145
145
|
## Sequence Diagram
|
|
146
146
|
|
|
@@ -174,7 +174,7 @@ sequenceDiagram
|
|
|
174
174
|
A->>A: validateAndConsumeChallenge()
|
|
175
175
|
A->>A: Identity check: actorId matches expected
|
|
176
176
|
A->>A: Hash matches, not expired → consume
|
|
177
|
-
A->>A:
|
|
177
|
+
A->>A: upsertContactChannel(status: 'active', policy: 'allow')
|
|
178
178
|
A-->>U: "Verification successful! You now have access."
|
|
179
179
|
|
|
180
180
|
U->>A: Subsequent messages
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vellumai/assistant",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.40",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
|
-
"
|
|
6
|
+
"assistant": "./src/index.ts"
|
|
7
7
|
},
|
|
8
8
|
"scripts": {
|
|
9
9
|
"dev": "bun run src/index.ts",
|
|
@@ -39,6 +39,7 @@
|
|
|
39
39
|
"croner": "^10.0.1",
|
|
40
40
|
"dotenv": "^17.3.1",
|
|
41
41
|
"drizzle-orm": "^0.38.4",
|
|
42
|
+
"esbuild": "^0.24.0",
|
|
42
43
|
"ink": "^6.7.0",
|
|
43
44
|
"jszip": "^3.10.1",
|
|
44
45
|
"minimatch": "^10.2.4",
|
|
@@ -46,6 +47,7 @@
|
|
|
46
47
|
"pino": "^9.6.0",
|
|
47
48
|
"pino-pretty": "^13.1.3",
|
|
48
49
|
"playwright": "^1.58.2",
|
|
50
|
+
"preact": "^10.25.0",
|
|
49
51
|
"postgres": "^3.4.8",
|
|
50
52
|
"qrcode": "^1.5.4",
|
|
51
53
|
"react": "^19.2.4",
|
|
@@ -628,13 +628,6 @@ exports[`IPC message snapshots ClientMessage types share_app_cloud serializes to
|
|
|
628
628
|
}
|
|
629
629
|
`;
|
|
630
630
|
|
|
631
|
-
exports[`IPC message snapshots ClientMessage types share_to_slack serializes to expected JSON 1`] = `
|
|
632
|
-
{
|
|
633
|
-
"appId": "app-001",
|
|
634
|
-
"type": "share_to_slack",
|
|
635
|
-
}
|
|
636
|
-
`;
|
|
637
|
-
|
|
638
631
|
exports[`IPC message snapshots ClientMessage types slack_webhook_config serializes to expected JSON 1`] = `
|
|
639
632
|
{
|
|
640
633
|
"action": "get",
|
|
@@ -2234,13 +2227,6 @@ exports[`IPC message snapshots ServerMessage types share_app_cloud_response seri
|
|
|
2234
2227
|
}
|
|
2235
2228
|
`;
|
|
2236
2229
|
|
|
2237
|
-
exports[`IPC message snapshots ServerMessage types share_to_slack_response serializes to expected JSON 1`] = `
|
|
2238
|
-
{
|
|
2239
|
-
"success": true,
|
|
2240
|
-
"type": "share_to_slack_response",
|
|
2241
|
-
}
|
|
2242
|
-
`;
|
|
2243
|
-
|
|
2244
2230
|
exports[`IPC message snapshots ServerMessage types slack_webhook_config_response serializes to expected JSON 1`] = `
|
|
2245
2231
|
{
|
|
2246
2232
|
"success": true,
|