@vellumai/assistant 0.4.49 → 0.4.51
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +24 -33
- package/README.md +3 -3
- package/docs/architecture/integrations.md +2 -2
- package/docs/architecture/keychain-broker.md +6 -6
- package/docs/architecture/memory.md +180 -119
- package/knip.json +32 -0
- package/package.json +3 -2
- package/src/__tests__/agent-loop.test.ts +3 -1
- package/src/__tests__/anthropic-provider.test.ts +114 -23
- package/src/__tests__/approval-cascade.test.ts +1 -15
- package/src/__tests__/approval-routes-http.test.ts +2 -0
- package/src/__tests__/assistant-feature-flag-guard.test.ts +0 -23
- package/src/__tests__/btw-routes.test.ts +61 -5
- package/src/__tests__/canonical-guardian-store.test.ts +95 -0
- package/src/__tests__/checker.test.ts +13 -0
- package/src/__tests__/config-schema.test.ts +1 -68
- package/src/__tests__/config-watcher.test.ts +8 -0
- package/src/__tests__/context-memory-e2e.test.ts +11 -100
- package/src/__tests__/conversation-routes-guardian-reply.test.ts +8 -0
- package/src/__tests__/conversation-routes-slash-commands.test.ts +1 -0
- package/src/__tests__/credential-security-e2e.test.ts +1 -0
- package/src/__tests__/credential-security-invariants.test.ts +8 -7
- package/src/__tests__/credential-vault-unit.test.ts +23 -18
- package/src/__tests__/credential-vault.test.ts +30 -18
- package/src/__tests__/credentials-cli.test.ts +257 -82
- package/src/__tests__/cu-unified-flow.test.ts +532 -0
- package/src/__tests__/date-context.test.ts +93 -77
- package/src/__tests__/deterministic-verification-control-plane.test.ts +64 -0
- package/src/__tests__/guardian-routing-invariants.test.ts +93 -0
- package/src/__tests__/history-repair.test.ts +245 -0
- package/src/__tests__/host-cu-proxy.test.ts +165 -3
- package/src/__tests__/http-user-message-parity.test.ts +1 -0
- package/src/__tests__/inbound-invite-redemption.test.ts +36 -7
- package/src/__tests__/integration-status.test.ts +31 -30
- package/src/__tests__/invite-redemption-service.test.ts +166 -13
- package/src/__tests__/invite-routes-http.test.ts +166 -5
- package/src/__tests__/keychain-broker-client.test.ts +4 -4
- package/src/__tests__/list-messages-attachments.test.ts +193 -0
- package/src/__tests__/memory-context-benchmark.benchmark.test.ts +56 -18
- package/src/__tests__/memory-lifecycle-e2e.test.ts +244 -387
- package/src/__tests__/memory-recall-quality.test.ts +244 -407
- package/src/__tests__/memory-regressions.experimental.test.ts +126 -101
- package/src/__tests__/memory-regressions.test.ts +477 -2841
- package/src/__tests__/memory-retrieval.benchmark.test.ts +33 -150
- package/src/__tests__/memory-upsert-concurrency.test.ts +5 -244
- package/src/__tests__/mime-builder.test.ts +28 -0
- package/src/__tests__/native-web-search.test.ts +1 -0
- package/src/__tests__/oauth-cli.test.ts +824 -31
- package/src/__tests__/oauth-provider-profiles.test.ts +1 -1
- package/src/__tests__/oauth-store.test.ts +363 -17
- package/src/__tests__/qdrant-collection-migration.test.ts +53 -8
- package/src/__tests__/registry.test.ts +0 -1
- package/src/__tests__/relay-server.test.ts +55 -1
- package/src/__tests__/schedule-tools.test.ts +32 -0
- package/src/__tests__/script-proxy-certs.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +1 -0
- package/src/__tests__/secret-routes-managed-proxy.test.ts +183 -0
- package/src/__tests__/secure-keys.test.ts +78 -18
- package/src/__tests__/send-endpoint-busy.test.ts +3 -0
- package/src/__tests__/server-history-render.test.ts +2 -2
- package/src/__tests__/session-abort-tool-results.test.ts +1 -14
- package/src/__tests__/session-agent-loop-overflow.test.ts +1583 -0
- package/src/__tests__/session-agent-loop.test.ts +19 -15
- package/src/__tests__/session-confirmation-signals.test.ts +1 -15
- package/src/__tests__/session-error.test.ts +124 -2
- package/src/__tests__/session-history-web-search.test.ts +918 -0
- package/src/__tests__/session-pre-run-repair.test.ts +1 -14
- package/src/__tests__/session-provider-retry-repair.test.ts +25 -28
- package/src/__tests__/session-queue.test.ts +37 -27
- package/src/__tests__/session-runtime-assembly.test.ts +54 -0
- package/src/__tests__/session-slash-known.test.ts +1 -15
- package/src/__tests__/session-slash-queue.test.ts +1 -15
- package/src/__tests__/session-slash-unknown.test.ts +1 -15
- package/src/__tests__/session-workspace-cache-state.test.ts +3 -33
- package/src/__tests__/session-workspace-injection.test.ts +3 -37
- package/src/__tests__/session-workspace-tool-tracking.test.ts +3 -37
- package/src/__tests__/skills-install-extract.test.ts +93 -0
- package/src/__tests__/skills.test.ts +2 -2
- package/src/__tests__/skillssh-registry.test.ts +451 -0
- package/src/__tests__/slack-channel-config.test.ts +10 -8
- package/src/__tests__/trust-store.test.ts +15 -0
- package/src/__tests__/twilio-config.test.ts +11 -10
- package/src/__tests__/twilio-provider.test.ts +9 -4
- package/src/__tests__/voice-invite-redemption.test.ts +85 -5
- package/src/agent/ax-tree-compaction.test.ts +51 -0
- package/src/agent/loop.ts +39 -12
- package/src/approvals/AGENTS.md +1 -1
- package/src/approvals/guardian-request-resolvers.ts +14 -2
- package/src/bundler/compiler-tools.ts +66 -2
- package/src/calls/call-domain.ts +134 -3
- package/src/calls/call-store.ts +6 -0
- package/src/calls/relay-server.ts +44 -6
- package/src/calls/relay-setup-router.ts +17 -1
- package/src/calls/twilio-config.ts +5 -4
- package/src/calls/twilio-provider.ts +14 -9
- package/src/calls/twilio-rest.ts +10 -7
- package/src/calls/types.ts +3 -1
- package/src/cli/commands/config.ts +14 -9
- package/src/cli/commands/contacts.ts +3 -0
- package/src/cli/commands/credentials.ts +170 -174
- package/src/cli/commands/doctor.ts +11 -8
- package/src/cli/commands/keys.ts +9 -9
- package/src/cli/commands/mcp.ts +46 -59
- package/src/cli/commands/memory.ts +16 -165
- package/src/cli/commands/oauth/apps.ts +68 -10
- package/src/cli/commands/oauth/connections.ts +475 -105
- package/src/cli/commands/oauth/index.ts +3 -3
- package/src/cli/commands/oauth/providers.ts +18 -4
- package/src/cli/commands/sessions.ts +5 -2
- package/src/cli/commands/skills.ts +173 -1
- package/src/cli/http-client.ts +0 -20
- package/src/cli/main-screen.tsx +2 -2
- package/src/cli/program.ts +5 -6
- package/src/cli.ts +20 -22
- package/src/config/__tests__/feature-flag-registry-bundled.test.ts +39 -0
- package/src/config/bundled-skills/computer-use/TOOLS.json +1 -1
- package/src/config/bundled-skills/computer-use/tools/computer-use-observe.ts +12 -0
- package/src/config/bundled-skills/contacts/SKILL.md +35 -11
- package/src/config/bundled-skills/contacts/tools/google-contacts.ts +1 -1
- package/src/config/bundled-skills/gmail/SKILL.md +1 -1
- package/src/config/bundled-skills/gmail/TOOLS.json +52 -0
- package/src/config/bundled-skills/gmail/tools/gmail-archive.ts +13 -3
- package/src/config/bundled-skills/gmail/tools/gmail-attachments.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-filters.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-follow-up.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-forward.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-label.ts +9 -2
- package/src/config/bundled-skills/gmail/tools/gmail-outreach-scan.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-send-draft.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-sender-digest.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-trash.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-unsubscribe.ts +5 -1
- package/src/config/bundled-skills/gmail/tools/gmail-vacation.ts +5 -1
- package/src/config/bundled-skills/google-calendar/TOOLS.json +20 -0
- package/src/config/bundled-skills/google-calendar/tools/calendar-check-availability.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-create-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-get-event.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-list-events.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/calendar-rsvp.ts +2 -1
- package/src/config/bundled-skills/google-calendar/tools/shared.ts +8 -2
- package/src/config/bundled-skills/messaging/SKILL.md +1 -1
- package/src/config/bundled-skills/messaging/tools/messaging-analyze-style.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-archive-by-sender.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-auth-test.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-list-conversations.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-mark-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-read.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-search.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-send.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/messaging-sender-digest.ts +2 -2
- package/src/config/bundled-skills/messaging/tools/shared.ts +7 -5
- package/src/config/bundled-skills/slack/tools/shared.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-add-reaction.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-channel-details.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-delete-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-edit-message.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-leave-channel.ts +1 -1
- package/src/config/bundled-skills/slack/tools/slack-scan-digest.ts +1 -1
- package/src/config/bundled-tool-registry.ts +2 -5
- package/src/config/loader.ts +6 -42
- package/src/config/schema.ts +1 -12
- package/src/config/schemas/memory-lifecycle.ts +0 -9
- package/src/config/schemas/memory-processing.ts +0 -180
- package/src/config/schemas/memory-retrieval.ts +32 -104
- package/src/config/schemas/memory.ts +0 -10
- package/src/config/types.ts +0 -4
- package/src/contacts/contact-store.ts +39 -2
- package/src/contacts/contacts-write.ts +9 -0
- package/src/context/window-manager.ts +4 -1
- package/src/daemon/config-watcher.ts +55 -2
- package/src/daemon/daemon-control.ts +1 -1
- package/src/daemon/date-context.ts +114 -31
- package/src/daemon/handlers/config-ingress.ts +2 -2
- package/src/daemon/handlers/config-slack-channel.ts +59 -39
- package/src/daemon/handlers/config-telegram.ts +23 -14
- package/src/daemon/handlers/session-history.ts +1 -358
- package/src/daemon/handlers/sessions.ts +18 -13
- package/src/daemon/handlers/shared.ts +3 -17
- package/src/daemon/handlers/skills.ts +20 -1
- package/src/daemon/history-repair.ts +72 -8
- package/src/daemon/host-cu-proxy.ts +55 -26
- package/src/daemon/lifecycle.ts +39 -4
- package/src/daemon/mcp-reload-service.ts +2 -2
- package/src/daemon/message-types/computer-use.ts +1 -12
- package/src/daemon/message-types/memory.ts +4 -16
- package/src/daemon/message-types/messages.ts +1 -0
- package/src/daemon/message-types/sessions.ts +4 -42
- package/src/daemon/server.ts +6 -1
- package/src/daemon/session-agent-loop-handlers.ts +38 -0
- package/src/daemon/session-agent-loop.ts +334 -48
- package/src/daemon/session-error.ts +89 -6
- package/src/daemon/session-history.ts +17 -7
- package/src/daemon/session-media-retry.ts +6 -2
- package/src/daemon/session-memory.ts +69 -149
- package/src/daemon/session-process.ts +10 -1
- package/src/daemon/session-runtime-assembly.ts +49 -19
- package/src/daemon/session-slash.ts +3 -5
- package/src/daemon/session-surfaces.ts +4 -1
- package/src/daemon/session-tool-setup.ts +7 -1
- package/src/daemon/session.ts +12 -2
- package/src/email/providers/index.ts +2 -2
- package/src/instrument.ts +61 -1
- package/src/media/avatar-router.ts +1 -1
- package/src/memory/admin.ts +2 -191
- package/src/memory/canonical-guardian-store.ts +38 -2
- package/src/memory/conversation-crud.ts +0 -33
- package/src/memory/conversation-queries.ts +25 -83
- package/src/memory/db-init.ts +32 -0
- package/src/memory/embedding-backend.ts +84 -8
- package/src/memory/embedding-types.ts +9 -1
- package/src/memory/indexer.ts +7 -46
- package/src/memory/invite-store.ts +19 -0
- package/src/memory/items-extractor.ts +274 -76
- package/src/memory/job-handlers/backfill.ts +2 -127
- package/src/memory/job-handlers/cleanup.ts +2 -16
- package/src/memory/job-handlers/extraction.ts +2 -138
- package/src/memory/job-handlers/index-maintenance.ts +1 -6
- package/src/memory/job-handlers/summarization.ts +3 -148
- package/src/memory/job-utils.ts +21 -59
- package/src/memory/jobs-store.ts +1 -159
- package/src/memory/jobs-worker.ts +9 -52
- package/src/memory/migrations/104-core-indexes.ts +3 -3
- package/src/memory/migrations/149-oauth-tables.ts +2 -0
- package/src/memory/migrations/150-oauth-apps-client-secret-path.ts +98 -0
- package/src/memory/migrations/151-oauth-providers-ping-url.ts +11 -0
- package/src/memory/migrations/152-memory-item-supersession.ts +44 -0
- package/src/memory/migrations/153-drop-entity-tables.ts +15 -0
- package/src/memory/migrations/154-drop-fts.ts +20 -0
- package/src/memory/migrations/155-drop-conflicts.ts +7 -0
- package/src/memory/migrations/156-call-session-invite-metadata.ts +24 -0
- package/src/memory/migrations/157-invite-contact-id.ts +104 -0
- package/src/memory/migrations/index.ts +8 -0
- package/src/memory/migrations/registry.ts +6 -0
- package/src/memory/qdrant-client.ts +148 -51
- package/src/memory/raw-query.ts +1 -1
- package/src/memory/retriever.test.ts +294 -273
- package/src/memory/retriever.ts +421 -645
- package/src/memory/schema/calls.ts +2 -0
- package/src/memory/schema/contacts.ts +1 -0
- package/src/memory/schema/memory-core.ts +3 -48
- package/src/memory/schema/oauth.ts +2 -0
- package/src/memory/search/formatting.ts +263 -176
- package/src/memory/search/lexical.ts +1 -254
- package/src/memory/search/ranking.ts +0 -455
- package/src/memory/search/semantic.ts +100 -14
- package/src/memory/search/staleness.ts +47 -0
- package/src/memory/search/tier-classifier.ts +21 -0
- package/src/memory/search/types.ts +15 -77
- package/src/memory/task-memory-cleanup.ts +4 -6
- package/src/messaging/provider.ts +1 -1
- package/src/messaging/providers/gmail/adapter.ts +1 -1
- package/src/messaging/providers/gmail/mime-builder.ts +17 -7
- package/src/messaging/providers/telegram-bot/adapter.ts +17 -8
- package/src/messaging/providers/whatsapp/adapter.ts +13 -9
- package/src/messaging/registry.ts +9 -5
- package/src/oauth/byo-connection.test.ts +40 -25
- package/src/oauth/connect-orchestrator.ts +4 -10
- package/src/oauth/connection-resolver.ts +20 -6
- package/src/oauth/manual-token-connection.ts +5 -5
- package/src/oauth/oauth-store.ts +183 -31
- package/src/oauth/platform-connection.test.ts +1 -1
- package/src/oauth/provider-behaviors.ts +503 -4
- package/src/oauth/seed-providers.ts +214 -8
- package/src/oauth/token-persistence.ts +31 -16
- package/src/permissions/defaults.ts +1 -0
- package/src/permissions/trust-store.ts +23 -1
- package/src/playbooks/playbook-compiler.ts +1 -1
- package/src/prompts/system-prompt.ts +18 -2
- package/src/providers/anthropic/client.ts +56 -126
- package/src/providers/types.ts +7 -1
- package/src/runtime/AGENTS.md +9 -0
- package/src/runtime/auth/route-policy.ts +6 -3
- package/src/runtime/channel-readiness-service.ts +48 -40
- package/src/runtime/guardian-reply-router.ts +24 -22
- package/src/runtime/http-server.ts +2 -2
- package/src/runtime/http-types.ts +2 -0
- package/src/runtime/invite-redemption-service.ts +72 -12
- package/src/runtime/invite-service.ts +43 -0
- package/src/runtime/middleware/twilio-validation.ts +1 -1
- package/src/runtime/pending-interactions.ts +2 -2
- package/src/runtime/routes/brain-graph-routes.ts +10 -90
- package/src/runtime/routes/btw-routes.ts +10 -5
- package/src/runtime/routes/conversation-routes.ts +56 -11
- package/src/runtime/routes/inbound-stages/acl-enforcement.ts +21 -12
- package/src/runtime/routes/integrations/slack/channel.ts +2 -2
- package/src/runtime/routes/integrations/telegram.ts +2 -2
- package/src/runtime/routes/integrations/twilio.ts +17 -17
- package/src/runtime/routes/invite-routes.ts +29 -4
- package/src/runtime/routes/memory-item-routes.test.ts +754 -0
- package/src/runtime/routes/memory-item-routes.ts +503 -0
- package/src/runtime/routes/secret-routes.ts +17 -0
- package/src/runtime/routes/session-management-routes.ts +3 -3
- package/src/runtime/routes/settings-routes.ts +3 -3
- package/src/runtime/routes/trust-rules-routes.ts +14 -0
- package/src/runtime/routes/workspace-routes.ts +9 -4
- package/src/runtime/routes/workspace-utils.ts +8 -2
- package/src/schedule/integration-status.ts +26 -19
- package/src/security/keychain-broker-client.ts +17 -4
- package/src/security/oauth2.ts +6 -7
- package/src/security/secure-keys.ts +44 -19
- package/src/security/token-manager.ts +46 -39
- package/src/services/vercel-deploy.ts +0 -24
- package/src/signals/confirm.ts +78 -0
- package/src/signals/mcp-reload.ts +18 -0
- package/src/skills/catalog-install.ts +74 -18
- package/src/skills/skillssh-registry.ts +503 -0
- package/src/tools/assets/search.ts +5 -1
- package/src/tools/computer-use/definitions.ts +0 -10
- package/src/tools/computer-use/registry.ts +1 -1
- package/src/tools/credentials/vault.ts +22 -7
- package/src/tools/memory/definitions.ts +4 -13
- package/src/tools/memory/handlers.test.ts +83 -103
- package/src/tools/memory/handlers.ts +50 -85
- package/src/tools/network/script-proxy/session-manager.ts +8 -8
- package/src/tools/schedule/create.ts +10 -3
- package/src/tools/schedule/update.ts +8 -1
- package/src/tools/skills/load.ts +25 -2
- package/src/watcher/provider-types.ts +1 -1
- package/src/watcher/providers/github.ts +1 -1
- package/src/watcher/providers/gmail.ts +3 -3
- package/src/watcher/providers/google-calendar.ts +3 -3
- package/src/watcher/providers/linear.ts +1 -1
- package/src/__tests__/clarification-resolver.test.ts +0 -193
- package/src/__tests__/conflict-intent-tokenization.test.ts +0 -160
- package/src/__tests__/conflict-policy.test.ts +0 -269
- package/src/__tests__/conflict-store.test.ts +0 -372
- package/src/__tests__/contradiction-checker.test.ts +0 -361
- package/src/__tests__/entity-extractor.test.ts +0 -211
- package/src/__tests__/entity-search.test.ts +0 -1117
- package/src/__tests__/profile-compiler.test.ts +0 -392
- package/src/__tests__/session-conflict-gate.test.ts +0 -1228
- package/src/__tests__/session-profile-injection.test.ts +0 -557
- package/src/config/bundled-skills/knowledge-graph/SKILL.md +0 -25
- package/src/config/bundled-skills/knowledge-graph/TOOLS.json +0 -66
- package/src/config/bundled-skills/knowledge-graph/tools/graph-query.ts +0 -211
- package/src/daemon/session-conflict-gate.ts +0 -167
- package/src/daemon/session-dynamic-profile.ts +0 -77
- package/src/memory/clarification-resolver.ts +0 -417
- package/src/memory/conflict-intent.ts +0 -205
- package/src/memory/conflict-policy.ts +0 -127
- package/src/memory/conflict-store.ts +0 -410
- package/src/memory/contradiction-checker.ts +0 -508
- package/src/memory/entity-extractor.ts +0 -535
- package/src/memory/format-recall.ts +0 -47
- package/src/memory/fts-reconciler.ts +0 -165
- package/src/memory/job-handlers/conflict.ts +0 -200
- package/src/memory/profile-compiler.ts +0 -195
- package/src/memory/recall-cache.ts +0 -117
- package/src/memory/search/entity.ts +0 -535
- package/src/memory/search/query-expansion.test.ts +0 -70
- package/src/memory/search/query-expansion.ts +0 -118
- package/src/runtime/routes/mcp-routes.ts +0 -20
package/src/cli/commands/mcp.ts
CHANGED
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
|
|
1
4
|
import { UnauthorizedError } from "@modelcontextprotocol/sdk/client/auth.js";
|
|
2
5
|
import { Client } from "@modelcontextprotocol/sdk/client/index.js";
|
|
3
6
|
import { SSEClientTransport } from "@modelcontextprotocol/sdk/client/sse.js";
|
|
@@ -11,7 +14,7 @@ import {
|
|
|
11
14
|
deleteMcpOAuthCredentials,
|
|
12
15
|
McpOAuthProvider,
|
|
13
16
|
} from "../../mcp/mcp-oauth-provider.js";
|
|
14
|
-
import {
|
|
17
|
+
import { getWorkspaceDir } from "../../util/platform.js";
|
|
15
18
|
import { log } from "../logger.js";
|
|
16
19
|
|
|
17
20
|
export const HEALTH_CHECK_TIMEOUT_MS = 10_000;
|
|
@@ -51,6 +54,21 @@ export async function checkServerHealth(
|
|
|
51
54
|
}
|
|
52
55
|
}
|
|
53
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Write a signal file so the daemon's ConfigWatcher triggers an MCP reload.
|
|
59
|
+
* Used by `mcp reload`, `mcp auth`, and any operation that needs the daemon
|
|
60
|
+
* to reconnect MCP servers.
|
|
61
|
+
*/
|
|
62
|
+
function signalMcpReload(): void {
|
|
63
|
+
try {
|
|
64
|
+
const signalsDir = join(getWorkspaceDir(), "signals");
|
|
65
|
+
mkdirSync(signalsDir, { recursive: true });
|
|
66
|
+
writeFileSync(join(signalsDir, "mcp-reload"), "");
|
|
67
|
+
} catch {
|
|
68
|
+
// Best-effort — the daemon may not be running or the directory may not exist.
|
|
69
|
+
}
|
|
70
|
+
}
|
|
71
|
+
|
|
54
72
|
export function registerMcpCommand(program: Command): void {
|
|
55
73
|
const mcp = program
|
|
56
74
|
.command("mcp")
|
|
@@ -67,8 +85,8 @@ server uses one of three transport types:
|
|
|
67
85
|
sse Remote server using Server-Sent Events
|
|
68
86
|
streamable-http Remote server using Streamable HTTP transport
|
|
69
87
|
|
|
70
|
-
|
|
71
|
-
|
|
88
|
+
MCP server configuration changes are detected automatically by the running
|
|
89
|
+
assistant. You can also run 'vellum mcp reload' to trigger a manual reload.
|
|
72
90
|
|
|
73
91
|
Examples:
|
|
74
92
|
$ assistant mcp list
|
|
@@ -251,61 +269,20 @@ Examples:
|
|
|
251
269
|
.addHelpText(
|
|
252
270
|
"after",
|
|
253
271
|
`
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
272
|
+
Signals the running assistant to disconnect and reconnect all MCP servers
|
|
273
|
+
using the current configuration from disk. Active sessions pick up new tools
|
|
274
|
+
on their next turn automatically. The assistant must be running.
|
|
257
275
|
|
|
258
276
|
Examples:
|
|
259
277
|
$ vellum mcp reload
|
|
260
278
|
$ vellum mcp reload # after editing config.json to add a new server
|
|
261
279
|
$ vellum mcp reload # after running "vellum mcp auth <server>"`,
|
|
262
280
|
)
|
|
263
|
-
.action(
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
success: boolean;
|
|
269
|
-
serverCount?: number;
|
|
270
|
-
toolCount?: number;
|
|
271
|
-
servers?: {
|
|
272
|
-
id: string;
|
|
273
|
-
connected: boolean;
|
|
274
|
-
disabled?: boolean;
|
|
275
|
-
toolCount: number;
|
|
276
|
-
tools: string[];
|
|
277
|
-
}[];
|
|
278
|
-
error?: string;
|
|
279
|
-
};
|
|
280
|
-
if (response.success) {
|
|
281
|
-
log.info(
|
|
282
|
-
`MCP servers reloaded: ${response.serverCount} server(s), ${response.toolCount} tool(s)\n`,
|
|
283
|
-
);
|
|
284
|
-
if (response.servers && response.servers.length > 0) {
|
|
285
|
-
for (const server of response.servers) {
|
|
286
|
-
const status = server.disabled
|
|
287
|
-
? "⊘ Disabled"
|
|
288
|
-
: server.connected
|
|
289
|
-
? "\u2713 Connected"
|
|
290
|
-
: "\u2717 Not connected";
|
|
291
|
-
log.info(` ${server.id}`);
|
|
292
|
-
log.info(` Status: ${status}`);
|
|
293
|
-
log.info(
|
|
294
|
-
` Tools: ${server.toolCount > 0 ? server.tools.join(", ") : "(none)"}`,
|
|
295
|
-
);
|
|
296
|
-
log.info("");
|
|
297
|
-
}
|
|
298
|
-
}
|
|
299
|
-
} else {
|
|
300
|
-
log.error(`Failed to reload: ${response.error}`);
|
|
301
|
-
process.exitCode = 1;
|
|
302
|
-
}
|
|
303
|
-
} catch (err) {
|
|
304
|
-
log.error(
|
|
305
|
-
`Failed to send reload request: ${err instanceof Error ? err.message : err}`,
|
|
306
|
-
);
|
|
307
|
-
process.exitCode = 1;
|
|
308
|
-
}
|
|
281
|
+
.action(() => {
|
|
282
|
+
signalMcpReload();
|
|
283
|
+
log.info(
|
|
284
|
+
"MCP reload signal sent. The running assistant will reconnect servers shortly.",
|
|
285
|
+
);
|
|
309
286
|
});
|
|
310
287
|
|
|
311
288
|
mcp
|
|
@@ -422,7 +399,10 @@ Examples:
|
|
|
422
399
|
|
|
423
400
|
saveRawConfig(raw);
|
|
424
401
|
log.info(`Added MCP server "${name}" (${opts.transportType})`);
|
|
425
|
-
log.info(
|
|
402
|
+
log.info(
|
|
403
|
+
"The running assistant will pick up this change automatically. " +
|
|
404
|
+
"Or run 'vellum mcp reload' to apply now.",
|
|
405
|
+
);
|
|
426
406
|
},
|
|
427
407
|
);
|
|
428
408
|
|
|
@@ -444,8 +424,8 @@ OAuth flow. If the server already has valid cached tokens, the command succeeds
|
|
|
444
424
|
immediately without opening a browser. Tokens are cached locally for future use
|
|
445
425
|
by the assistant.
|
|
446
426
|
|
|
447
|
-
After successful authentication,
|
|
448
|
-
|
|
427
|
+
After successful authentication, the running assistant detects the change
|
|
428
|
+
automatically. You can also run 'vellum mcp reload' to apply immediately.
|
|
449
429
|
|
|
450
430
|
Examples:
|
|
451
431
|
$ assistant mcp auth my-server
|
|
@@ -603,7 +583,11 @@ Examples:
|
|
|
603
583
|
provider.stopCallbackServer();
|
|
604
584
|
|
|
605
585
|
log.info(`Authentication successful for "${name}".`);
|
|
606
|
-
log.info(
|
|
586
|
+
log.info(
|
|
587
|
+
"The running assistant will pick up this change automatically. " +
|
|
588
|
+
"Or run 'vellum mcp reload' to apply now.",
|
|
589
|
+
);
|
|
590
|
+
signalMcpReload();
|
|
607
591
|
process.exit(0);
|
|
608
592
|
});
|
|
609
593
|
|
|
@@ -621,8 +605,8 @@ any stored OAuth credentials (tokens, client info, discovery metadata) for
|
|
|
621
605
|
sse/streamable-http servers. If no OAuth credentials exist, the cleanup is
|
|
622
606
|
silently skipped.
|
|
623
607
|
|
|
624
|
-
After removal,
|
|
625
|
-
|
|
608
|
+
After removal, the running assistant detects the change automatically. You
|
|
609
|
+
can also run 'vellum mcp reload' to apply immediately.
|
|
626
610
|
|
|
627
611
|
Examples:
|
|
628
612
|
$ assistant mcp remove my-server
|
|
@@ -655,6 +639,9 @@ Examples:
|
|
|
655
639
|
delete servers[name];
|
|
656
640
|
saveRawConfig(raw);
|
|
657
641
|
log.info(`Removed MCP server "${name}".`);
|
|
658
|
-
log.info(
|
|
642
|
+
log.info(
|
|
643
|
+
"The running assistant will pick up this change automatically. " +
|
|
644
|
+
"Or run 'vellum mcp reload' to apply now.",
|
|
645
|
+
);
|
|
659
646
|
});
|
|
660
647
|
}
|
|
@@ -1,21 +1,16 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
|
|
3
3
|
import {
|
|
4
|
-
dismissPendingConflicts,
|
|
5
4
|
getMemorySystemStatus,
|
|
6
5
|
queryMemory,
|
|
7
6
|
requestMemoryBackfill,
|
|
8
7
|
requestMemoryCleanup,
|
|
9
8
|
requestMemoryRebuildIndex,
|
|
10
9
|
} from "../../memory/admin.js";
|
|
11
|
-
import { listPendingConflictDetails } from "../../memory/conflict-store.js";
|
|
12
10
|
import { listConversations } from "../../memory/conversation-queries.js";
|
|
13
|
-
import { rawGet } from "../../memory/db.js";
|
|
14
11
|
import { initializeDb } from "../db.js";
|
|
15
12
|
import { log } from "../logger.js";
|
|
16
13
|
|
|
17
|
-
const SHORT_HASH_LENGTH = 8;
|
|
18
|
-
|
|
19
14
|
export function registerMemoryCommand(program: Command): void {
|
|
20
15
|
const memory = program
|
|
21
16
|
.command("memory")
|
|
@@ -24,23 +19,20 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
24
19
|
memory.addHelpText(
|
|
25
20
|
"after",
|
|
26
21
|
`
|
|
27
|
-
The memory subsystem indexes conversation segments
|
|
28
|
-
and vector embeddings for semantic recall
|
|
29
|
-
|
|
30
|
-
"pending_clarification" status until explicitly dismissed or resolved.
|
|
22
|
+
The memory subsystem indexes conversation segments using hybrid search (dense
|
|
23
|
+
and sparse vector embeddings) for semantic recall, with tier classification
|
|
24
|
+
to prioritize high-value memories.
|
|
31
25
|
|
|
32
26
|
Key concepts:
|
|
33
27
|
segments Chunks of conversation text extracted for indexing
|
|
34
28
|
items Distilled facts/statements derived from segments
|
|
35
29
|
summaries Compressed representations of conversation history
|
|
36
30
|
embeddings Vector representations used for semantic similarity search
|
|
37
|
-
conflicts Pairs of contradictory statements awaiting resolution
|
|
38
31
|
|
|
39
32
|
Examples:
|
|
40
33
|
$ assistant memory status
|
|
41
34
|
$ assistant memory query "What is the project deadline?"
|
|
42
|
-
$ assistant memory backfill
|
|
43
|
-
$ assistant memory dismiss-conflicts --all`,
|
|
35
|
+
$ assistant memory backfill`,
|
|
44
36
|
);
|
|
45
37
|
|
|
46
38
|
memory
|
|
@@ -59,10 +51,7 @@ Fields shown:
|
|
|
59
51
|
items Total distilled fact items stored
|
|
60
52
|
summaries Total compressed conversation summaries
|
|
61
53
|
embeddings Total vector embeddings computed
|
|
62
|
-
|
|
63
|
-
resolved conflicts Conflicts that have been dismissed or resolved
|
|
64
|
-
oldest pending age How long the oldest unresolved conflict has been waiting
|
|
65
|
-
cleanup backlogs Number of resolved conflicts and superseded items pending cleanup
|
|
54
|
+
cleanup backlogs Number of superseded items pending cleanup
|
|
66
55
|
cleanup throughput Number of cleanup operations completed in the last 24 hours
|
|
67
56
|
jobs Status of background jobs (backfill, cleanup, rebuild-index)
|
|
68
57
|
|
|
@@ -84,29 +73,9 @@ Examples:
|
|
|
84
73
|
log.info(`Items: ${status.counts.items.toLocaleString()}`);
|
|
85
74
|
log.info(`Summaries: ${status.counts.summaries.toLocaleString()}`);
|
|
86
75
|
log.info(`Embeddings: ${status.counts.embeddings.toLocaleString()}`);
|
|
87
|
-
log.info(
|
|
88
|
-
`Pending conflicts: ${status.conflicts.pending.toLocaleString()}`,
|
|
89
|
-
);
|
|
90
|
-
log.info(
|
|
91
|
-
`Resolved conflicts: ${status.conflicts.resolved.toLocaleString()}`,
|
|
92
|
-
);
|
|
93
|
-
if (status.conflicts.oldestPendingAgeMs != null) {
|
|
94
|
-
const oldestMinutes = Math.floor(
|
|
95
|
-
status.conflicts.oldestPendingAgeMs / 60_000,
|
|
96
|
-
);
|
|
97
|
-
log.info(`Oldest pending conflict age: ${oldestMinutes} min`);
|
|
98
|
-
} else {
|
|
99
|
-
log.info("Oldest pending conflict age: n/a");
|
|
100
|
-
}
|
|
101
|
-
log.info(
|
|
102
|
-
`Cleanup backlog (resolved conflicts): ${status.cleanup.resolvedBacklog.toLocaleString()}`,
|
|
103
|
-
);
|
|
104
76
|
log.info(
|
|
105
77
|
`Cleanup backlog (superseded items): ${status.cleanup.supersededBacklog.toLocaleString()}`,
|
|
106
78
|
);
|
|
107
|
-
log.info(
|
|
108
|
-
`Cleanup throughput 24h (resolved conflicts): ${status.cleanup.resolvedCompleted24h.toLocaleString()}`,
|
|
109
|
-
);
|
|
110
79
|
log.info(
|
|
111
80
|
`Cleanup throughput 24h (superseded items): ${status.cleanup.supersededCompleted24h.toLocaleString()}`,
|
|
112
81
|
);
|
|
@@ -123,8 +92,8 @@ Examples:
|
|
|
123
92
|
.addHelpText(
|
|
124
93
|
"after",
|
|
125
94
|
`
|
|
126
|
-
Queues a background job to index unprocessed conversation segments into
|
|
127
|
-
|
|
95
|
+
Queues a background job to index unprocessed conversation segments into
|
|
96
|
+
vector embeddings. The job resumes from where the last backfill left off,
|
|
128
97
|
processing only new or unindexed segments.
|
|
129
98
|
|
|
130
99
|
The --force flag restarts the backfill from the very beginning, reprocessing
|
|
@@ -144,7 +113,7 @@ Examples:
|
|
|
144
113
|
memory
|
|
145
114
|
.command("cleanup")
|
|
146
115
|
.description(
|
|
147
|
-
"Queue cleanup jobs for
|
|
116
|
+
"Queue cleanup jobs for stale superseded items",
|
|
148
117
|
)
|
|
149
118
|
.option(
|
|
150
119
|
"--retention-ms <ms>",
|
|
@@ -153,11 +122,8 @@ Examples:
|
|
|
153
122
|
.addHelpText(
|
|
154
123
|
"after",
|
|
155
124
|
`
|
|
156
|
-
Queues
|
|
157
|
-
|
|
158
|
-
dismissed or resolved past the retention threshold.
|
|
159
|
-
2. Stale superseded items cleanup — removes memory items that have been
|
|
160
|
-
superseded by newer, corrected facts past the retention threshold.
|
|
125
|
+
Queues a background cleanup job to remove memory items that have been
|
|
126
|
+
superseded by newer, corrected facts past the retention threshold.
|
|
161
127
|
|
|
162
128
|
The optional --retention-ms flag sets the minimum age (in milliseconds) a
|
|
163
129
|
record must have before it is eligible for cleanup. If omitted, the system
|
|
@@ -175,9 +141,6 @@ Examples:
|
|
|
175
141
|
const jobs = requestMemoryCleanup(
|
|
176
142
|
Number.isFinite(retentionMs) ? retentionMs : undefined,
|
|
177
143
|
);
|
|
178
|
-
log.info(
|
|
179
|
-
`Queued cleanup_resolved_conflicts job: ${jobs.resolvedConflictsJobId}`,
|
|
180
|
-
);
|
|
181
144
|
log.info(
|
|
182
145
|
`Queued cleanup_stale_superseded_items job: ${jobs.staleSupersededItemsJobId}`,
|
|
183
146
|
);
|
|
@@ -195,8 +158,8 @@ Examples:
|
|
|
195
158
|
Arguments:
|
|
196
159
|
text The recall query string used to search memory (e.g. "What is the
|
|
197
160
|
project deadline?"). Matched against indexed segments using the full
|
|
198
|
-
recall pipeline:
|
|
199
|
-
(time-weighted)
|
|
161
|
+
recall pipeline: semantic (dense + sparse vector similarity) and recency
|
|
162
|
+
(time-weighted).
|
|
200
163
|
|
|
201
164
|
Runs the complete memory recall pipeline and displays hit counts for each
|
|
202
165
|
retrieval strategy, the total injected token count, query latency, and the
|
|
@@ -221,10 +184,8 @@ Examples:
|
|
|
221
184
|
if (result.degraded) {
|
|
222
185
|
log.info(`Memory degraded: ${result.reason ?? "unknown reason"}`);
|
|
223
186
|
}
|
|
224
|
-
log.info(`Lexical hits: ${result.lexicalHits}`);
|
|
225
187
|
log.info(`Semantic hits: ${result.semanticHits}`);
|
|
226
188
|
log.info(`Recency hits: ${result.recencyHits}`);
|
|
227
|
-
log.info(`Entity hits: ${result.entityHits}`);
|
|
228
189
|
log.info(`Injected tokens: ${result.injectedTokens}`);
|
|
229
190
|
log.info(`Latency: ${result.latencyMs}ms`);
|
|
230
191
|
if (result.injectedText.length > 0) {
|
|
@@ -237,13 +198,13 @@ Examples:
|
|
|
237
198
|
|
|
238
199
|
memory
|
|
239
200
|
.command("rebuild-index")
|
|
240
|
-
.description("Queue a memory
|
|
201
|
+
.description("Queue a memory embedding index rebuild job")
|
|
241
202
|
.addHelpText(
|
|
242
203
|
"after",
|
|
243
204
|
`
|
|
244
|
-
Queues a background job that performs a full rebuild of
|
|
245
|
-
|
|
246
|
-
|
|
205
|
+
Queues a background job that performs a full rebuild of the vector embedding
|
|
206
|
+
index. All existing index data is dropped and reconstructed from the source
|
|
207
|
+
memory items.
|
|
247
208
|
|
|
248
209
|
This is useful after schema changes, embedding model upgrades, or if index
|
|
249
210
|
corruption is suspected. The rebuild runs asynchronously; use "assistant memory
|
|
@@ -258,114 +219,4 @@ Examples:
|
|
|
258
219
|
const jobId = requestMemoryRebuildIndex();
|
|
259
220
|
log.info(`Queued rebuild-index job: ${jobId}`);
|
|
260
221
|
});
|
|
261
|
-
|
|
262
|
-
memory
|
|
263
|
-
.command("dismiss-conflicts")
|
|
264
|
-
.description("Dismiss pending memory conflicts (all or matching a pattern)")
|
|
265
|
-
.option("-a, --all", "Dismiss all pending conflicts")
|
|
266
|
-
.option(
|
|
267
|
-
"-p, --pattern <regex>",
|
|
268
|
-
"Dismiss conflicts where either statement matches this regex",
|
|
269
|
-
)
|
|
270
|
-
.option("-s, --scope <id>", 'Memory scope (default: "default")')
|
|
271
|
-
.option("--dry-run", "Show what would be dismissed without making changes")
|
|
272
|
-
.addHelpText(
|
|
273
|
-
"after",
|
|
274
|
-
`
|
|
275
|
-
Two modes of operation:
|
|
276
|
-
--all Dismiss every pending conflict in the scope
|
|
277
|
-
--pattern <regex> Dismiss only conflicts where either the existing or
|
|
278
|
-
candidate statement matches the given regex (case-insensitive)
|
|
279
|
-
|
|
280
|
-
At least one of --all or --pattern must be provided. If both are given,
|
|
281
|
-
--all takes priority and all pending conflicts are dismissed.
|
|
282
|
-
|
|
283
|
-
The --scope flag targets a specific memory scope. Defaults to "default" if
|
|
284
|
-
omitted. The --dry-run flag previews which conflicts would be dismissed
|
|
285
|
-
without actually modifying any records.
|
|
286
|
-
|
|
287
|
-
Examples:
|
|
288
|
-
$ assistant memory dismiss-conflicts --all
|
|
289
|
-
$ assistant memory dismiss-conflicts --pattern "project deadline" --dry-run
|
|
290
|
-
$ assistant memory dismiss-conflicts --pattern "^preferred\\b" --scope work`,
|
|
291
|
-
)
|
|
292
|
-
.action(
|
|
293
|
-
(opts: {
|
|
294
|
-
all?: boolean;
|
|
295
|
-
pattern?: string;
|
|
296
|
-
scope?: string;
|
|
297
|
-
dryRun?: boolean;
|
|
298
|
-
}) => {
|
|
299
|
-
if (!opts.all && !opts.pattern) {
|
|
300
|
-
log.info("At least one of --all or --pattern must be provided.");
|
|
301
|
-
log.info("Use --dry-run to preview without making changes.");
|
|
302
|
-
return;
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
initializeDb();
|
|
306
|
-
|
|
307
|
-
const pattern = opts.pattern
|
|
308
|
-
? new RegExp(opts.pattern, "i")
|
|
309
|
-
: undefined;
|
|
310
|
-
|
|
311
|
-
if (opts.dryRun) {
|
|
312
|
-
const scopeId = opts.scope ?? "default";
|
|
313
|
-
const totalPending =
|
|
314
|
-
rawGet<{ c: number }>(
|
|
315
|
-
`SELECT COUNT(*) AS c FROM memory_item_conflicts WHERE scope_id = ? AND status = 'pending_clarification'`,
|
|
316
|
-
scopeId,
|
|
317
|
-
)?.c ?? 0;
|
|
318
|
-
|
|
319
|
-
// Show a sample of conflicts (can't paginate without dismissing)
|
|
320
|
-
const sample = listPendingConflictDetails(scopeId, 1000);
|
|
321
|
-
let matchCount = 0;
|
|
322
|
-
for (const conflict of sample) {
|
|
323
|
-
const matches =
|
|
324
|
-
opts.all ||
|
|
325
|
-
(pattern &&
|
|
326
|
-
(pattern.test(conflict.existingStatement) ||
|
|
327
|
-
pattern.test(conflict.candidateStatement)));
|
|
328
|
-
if (!matches) continue;
|
|
329
|
-
matchCount++;
|
|
330
|
-
log.info(
|
|
331
|
-
` [${conflict.id.slice(0, SHORT_HASH_LENGTH)}] "${
|
|
332
|
-
conflict.existingStatement
|
|
333
|
-
}" vs "${conflict.candidateStatement}"`,
|
|
334
|
-
);
|
|
335
|
-
}
|
|
336
|
-
|
|
337
|
-
if (opts.all) {
|
|
338
|
-
// --all matches everything, so matchCount is just the sample size
|
|
339
|
-
log.info(
|
|
340
|
-
`\nDry run: ${totalPending} of ${totalPending} pending conflicts would be dismissed.`,
|
|
341
|
-
);
|
|
342
|
-
} else {
|
|
343
|
-
const moreNote =
|
|
344
|
-
totalPending > sample.length
|
|
345
|
-
? ` (showing first ${sample.length} of ${totalPending})`
|
|
346
|
-
: "";
|
|
347
|
-
log.info(
|
|
348
|
-
`\nDry run: ${matchCount} of ${totalPending} pending conflicts would be dismissed.${moreNote}`,
|
|
349
|
-
);
|
|
350
|
-
}
|
|
351
|
-
return;
|
|
352
|
-
}
|
|
353
|
-
|
|
354
|
-
const result = dismissPendingConflicts({
|
|
355
|
-
all: opts.all,
|
|
356
|
-
pattern,
|
|
357
|
-
scopeId: opts.scope,
|
|
358
|
-
});
|
|
359
|
-
for (const detail of result.details) {
|
|
360
|
-
log.info(
|
|
361
|
-
` Dismissed [${detail.id.slice(0, SHORT_HASH_LENGTH)}]: "${
|
|
362
|
-
detail.existingStatement
|
|
363
|
-
}" vs "${detail.candidateStatement}"`,
|
|
364
|
-
);
|
|
365
|
-
}
|
|
366
|
-
log.info(
|
|
367
|
-
`\nDismissed ${result.dismissed} conflicts. ${result.remaining} pending conflicts remain.`,
|
|
368
|
-
);
|
|
369
|
-
},
|
|
370
|
-
);
|
|
371
222
|
}
|
|
@@ -8,6 +8,8 @@ import {
|
|
|
8
8
|
listApps,
|
|
9
9
|
upsertApp,
|
|
10
10
|
} from "../../../oauth/oauth-store.js";
|
|
11
|
+
import { credentialKey } from "../../../security/credential-key.js";
|
|
12
|
+
import { getCredentialMetadata } from "../../../tools/credentials/metadata-store.js";
|
|
11
13
|
import { getCliLogger } from "../../logger.js";
|
|
12
14
|
import { shouldOutputJson, writeOutput } from "../../output.js";
|
|
13
15
|
|
|
@@ -45,8 +47,8 @@ client_secret linked to a provider. Each provider can have multiple apps
|
|
|
45
47
|
Examples:
|
|
46
48
|
$ assistant oauth apps list
|
|
47
49
|
$ assistant oauth apps get --id <uuid>
|
|
48
|
-
$ assistant oauth apps get --provider integration:
|
|
49
|
-
$ assistant oauth apps upsert --provider integration:
|
|
50
|
+
$ assistant oauth apps get --provider integration:google
|
|
51
|
+
$ assistant oauth apps upsert --provider integration:google --client-id abc123
|
|
50
52
|
$ assistant oauth apps delete <id>`,
|
|
51
53
|
);
|
|
52
54
|
|
|
@@ -96,7 +98,7 @@ Examples:
|
|
|
96
98
|
"Look up an OAuth app by ID, provider + client-id, or provider",
|
|
97
99
|
)
|
|
98
100
|
.option("--id <id>", "App ID (UUID)")
|
|
99
|
-
.option("--provider <key>", "Provider key (e.g. integration:
|
|
101
|
+
.option("--provider <key>", "Provider key (e.g. integration:google)")
|
|
100
102
|
.option("--client-id <id>", "OAuth client ID (requires --provider)")
|
|
101
103
|
.addHelpText(
|
|
102
104
|
"after",
|
|
@@ -107,10 +109,10 @@ Three lookup modes are supported:
|
|
|
107
109
|
$ assistant oauth apps get --id <uuid>
|
|
108
110
|
|
|
109
111
|
2. By provider + client ID (exact match):
|
|
110
|
-
$ assistant oauth apps get --provider integration:
|
|
112
|
+
$ assistant oauth apps get --provider integration:google --client-id abc123
|
|
111
113
|
|
|
112
114
|
3. By provider only (returns the most recently created app):
|
|
113
|
-
$ assistant oauth apps get --provider integration:
|
|
115
|
+
$ assistant oauth apps get --provider integration:google
|
|
114
116
|
|
|
115
117
|
At least --id or --provider must be specified.`,
|
|
116
118
|
)
|
|
@@ -159,12 +161,19 @@ At least --id or --provider must be specified.`,
|
|
|
159
161
|
apps
|
|
160
162
|
.command("upsert")
|
|
161
163
|
.description("Create or return an existing OAuth app registration")
|
|
162
|
-
.requiredOption(
|
|
164
|
+
.requiredOption(
|
|
165
|
+
"--provider <key>",
|
|
166
|
+
"Provider key (e.g. integration:google)",
|
|
167
|
+
)
|
|
163
168
|
.requiredOption("--client-id <id>", "OAuth client ID")
|
|
164
169
|
.option(
|
|
165
170
|
"--client-secret <secret>",
|
|
166
171
|
"OAuth client secret (stored in secure keychain)",
|
|
167
172
|
)
|
|
173
|
+
.option(
|
|
174
|
+
"--client-secret-credential-path <path>",
|
|
175
|
+
"Path to an existing client secret in the credential store (mutually exclusive with --client-secret)",
|
|
176
|
+
)
|
|
168
177
|
.addHelpText(
|
|
169
178
|
"after",
|
|
170
179
|
`
|
|
@@ -175,21 +184,70 @@ stored in the secure system keychain — not in the database.
|
|
|
175
184
|
When an existing app is matched and a --client-secret is provided, the stored
|
|
176
185
|
secret is updated. The app row itself is returned as-is.
|
|
177
186
|
|
|
187
|
+
You can supply the client secret directly via --client-secret, or reference an
|
|
188
|
+
existing credential in the store via --client-secret-credential-path. These two
|
|
189
|
+
options are mutually exclusive — providing both is an error.
|
|
190
|
+
|
|
191
|
+
The --client-secret-credential-path accepts two formats:
|
|
192
|
+
1. Full credential path: "credential/integration:google/client_secret"
|
|
193
|
+
2. Short name (service:field): "integration:google:client_secret"
|
|
194
|
+
Resolved via the metadata store by splitting on the last colon.
|
|
195
|
+
|
|
178
196
|
Examples:
|
|
179
|
-
$ assistant oauth apps upsert --provider integration:
|
|
197
|
+
$ assistant oauth apps upsert --provider integration:google --client-id abc123
|
|
180
198
|
$ assistant oauth apps upsert --provider integration:slack --client-id def456 --client-secret s3cret
|
|
181
|
-
$ assistant oauth apps upsert --provider integration:
|
|
199
|
+
$ assistant oauth apps upsert --provider integration:slack --client-id def456 --client-secret-credential-path "credential/integration:slack/client_secret"
|
|
200
|
+
$ assistant oauth apps upsert --provider integration:slack --client-id def456 --client-secret-credential-path "integration:slack:client_secret"
|
|
201
|
+
$ assistant oauth apps upsert --provider integration:google --client-id abc123 --json`,
|
|
182
202
|
)
|
|
183
203
|
.action(
|
|
184
204
|
async (
|
|
185
|
-
opts: {
|
|
205
|
+
opts: {
|
|
206
|
+
provider: string;
|
|
207
|
+
clientId: string;
|
|
208
|
+
clientSecret?: string;
|
|
209
|
+
clientSecretCredentialPath?: string;
|
|
210
|
+
},
|
|
186
211
|
cmd: Command,
|
|
187
212
|
) => {
|
|
188
213
|
try {
|
|
214
|
+
if (opts.clientSecret && opts.clientSecretCredentialPath) {
|
|
215
|
+
writeOutput(cmd, {
|
|
216
|
+
ok: false,
|
|
217
|
+
error:
|
|
218
|
+
"Cannot provide both --client-secret and --client-secret-credential-path",
|
|
219
|
+
});
|
|
220
|
+
process.exitCode = 1;
|
|
221
|
+
return;
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
let resolvedCredentialPath = opts.clientSecretCredentialPath;
|
|
225
|
+
if (
|
|
226
|
+
resolvedCredentialPath &&
|
|
227
|
+
!resolvedCredentialPath.startsWith("credential/")
|
|
228
|
+
) {
|
|
229
|
+
// Attempt to interpret as a credential key — split on the LAST colon to get service/field
|
|
230
|
+
const lastColon = resolvedCredentialPath.lastIndexOf(":");
|
|
231
|
+
if (lastColon > 0) {
|
|
232
|
+
const asService = resolvedCredentialPath.slice(0, lastColon);
|
|
233
|
+
const asField = resolvedCredentialPath.slice(lastColon + 1);
|
|
234
|
+
// If a credential exists in metadata with these coordinates, resolve it
|
|
235
|
+
const meta = getCredentialMetadata(asService, asField);
|
|
236
|
+
if (meta) {
|
|
237
|
+
resolvedCredentialPath = credentialKey(asService, asField);
|
|
238
|
+
}
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const clientSecretOpts = opts.clientSecret
|
|
243
|
+
? { clientSecretValue: opts.clientSecret }
|
|
244
|
+
: resolvedCredentialPath
|
|
245
|
+
? { clientSecretCredentialPath: resolvedCredentialPath }
|
|
246
|
+
: undefined;
|
|
189
247
|
const row = await upsertApp(
|
|
190
248
|
opts.provider,
|
|
191
249
|
opts.clientId,
|
|
192
|
-
|
|
250
|
+
clientSecretOpts,
|
|
193
251
|
);
|
|
194
252
|
|
|
195
253
|
if (!shouldOutputJson(cmd)) {
|