@vellumai/assistant 0.4.35 → 0.4.37
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/AGENTS.md +1 -1
- package/ARCHITECTURE.md +44 -49
- package/README.md +32 -20
- package/docs/architecture/keychain-broker.md +186 -0
- package/docs/architecture/security.md +110 -116
- package/docs/runbook-trusted-contacts.md +2 -2
- package/docs/skills.md +25 -25
- package/package.json +5 -2
- package/src/__tests__/__snapshots__/ipc-snapshot.test.ts.snap +11 -2
- package/src/__tests__/actor-token-service.test.ts +1 -0
- package/src/__tests__/amazon-cdp-integration.test.ts +74 -0
- package/src/__tests__/assistant-feature-flags-integration.test.ts +38 -9
- package/src/__tests__/assistant-id-boundary-guard.test.ts +29 -0
- package/src/__tests__/browser-fill-credential.test.ts +1 -1
- package/src/__tests__/bundle-scanner.test.ts +1 -1
- package/src/__tests__/channel-guardian.test.ts +102 -102
- package/src/__tests__/channel-invite-transport.test.ts +155 -256
- package/src/__tests__/channel-readiness-routes.test.ts +336 -0
- package/src/__tests__/checker.test.ts +6 -6
- package/src/__tests__/chrome-cdp.test.ts +350 -0
- package/src/__tests__/computer-use-session-lifecycle.test.ts +3 -3
- package/src/__tests__/computer-use-session-working-dir.test.ts +86 -52
- package/src/__tests__/computer-use-skill-lifecycle-cleanup.test.ts +1 -1
- package/src/__tests__/config-loader-migration.test.ts +85 -0
- package/src/__tests__/conversation-pairing.test.ts +370 -5
- package/src/__tests__/credential-broker-browser-fill.test.ts +1 -10
- package/src/__tests__/credential-broker-server-use.test.ts +1 -10
- package/src/__tests__/credential-security-e2e.test.ts +7 -1
- package/src/__tests__/credential-security-invariants.test.ts +14 -20
- package/src/__tests__/credential-vault-unit.test.ts +1 -11
- package/src/__tests__/credential-vault.test.ts +5 -19
- package/src/__tests__/credentials-cli.test.ts +814 -0
- package/src/__tests__/dynamic-skill-workflow-prompt.test.ts +23 -4
- package/src/__tests__/email-invite-adapter.test.ts +78 -0
- package/src/__tests__/email-service-config-fallback.test.ts +102 -0
- package/src/__tests__/encrypted-store.test.ts +6 -6
- package/src/__tests__/ephemeral-permissions.test.ts +3 -3
- package/src/__tests__/gateway-only-enforcement.test.ts +5 -1
- package/src/__tests__/guardian-actions-endpoint.test.ts +70 -12
- package/src/__tests__/guardian-outbound-http.test.ts +53 -47
- package/src/__tests__/handle-user-message-secret-resume.test.ts +23 -0
- package/src/__tests__/handlers-add-trust-rule-metadata.test.ts +32 -23
- package/src/__tests__/handlers-telegram-config.test.ts +8 -2
- package/src/__tests__/handlers-twitter-config.test.ts +2 -2
- package/src/__tests__/handlers-user-message-approval-consumption.test.ts +108 -7
- package/src/__tests__/ingress-reconcile.test.ts +6 -0
- package/src/__tests__/intent-routing.test.ts +23 -4
- package/src/__tests__/invite-routes-http.test.ts +12 -0
- package/src/__tests__/ipc-snapshot.test.ts +8 -2
- package/src/__tests__/keychain-broker-client.test.ts +543 -0
- package/src/__tests__/llm-usage-store.test.ts +344 -0
- package/src/__tests__/mcp-client-auth.test.ts +2 -2
- package/src/__tests__/media-reuse-story.e2e.test.ts +1 -1
- package/src/__tests__/migration-transport.test.ts +49 -0
- package/src/__tests__/notification-broadcaster.test.ts +205 -5
- package/src/__tests__/notification-deep-link.test.ts +365 -1
- package/src/__tests__/oauth-connect-handler.test.ts +2 -2
- package/src/__tests__/onboarding-starter-tasks.test.ts +17 -4
- package/src/__tests__/proxy-approval-callback.test.ts +1 -1
- package/src/__tests__/recording-handler.test.ts +1 -1
- package/src/__tests__/recording-intent-handler.test.ts +6 -1
- package/src/__tests__/recording-state-machine.test.ts +1 -1
- package/src/__tests__/relay-server.test.ts +9 -1
- package/src/__tests__/ride-shotgun-handler.test.ts +499 -0
- package/src/__tests__/runtime-attachment-metadata.test.ts +160 -1
- package/src/__tests__/script-proxy-injection-runtime.test.ts +299 -2
- package/src/__tests__/script-proxy-profile-template-fallback.test.ts +1 -1
- package/src/__tests__/secret-onetime-send.test.ts +8 -2
- package/src/__tests__/secure-keys.test.ts +175 -216
- package/src/__tests__/session-confirmation-signals.test.ts +1 -1
- package/src/__tests__/session-messaging-secret-redirect.test.ts +1 -1
- package/src/__tests__/session-queue.test.ts +2 -1
- package/src/__tests__/session-tool-setup-app-refresh.test.ts +2 -2
- package/src/__tests__/skill-feature-flags-integration.test.ts +29 -4
- package/src/__tests__/skill-feature-flags.test.ts +12 -9
- package/src/__tests__/skill-load-feature-flag.test.ts +26 -5
- package/src/__tests__/skill-projection.benchmark.test.ts +0 -1
- package/src/__tests__/skills.test.ts +34 -4
- package/src/__tests__/slack-channel-config.test.ts +2 -2
- package/src/__tests__/system-prompt.test.ts +26 -4
- package/src/__tests__/telegram-bot-username-resolution.test.ts +212 -0
- package/src/__tests__/telegram-invite-adapter.test.ts +164 -0
- package/src/__tests__/tool-execution-pipeline.benchmark.test.ts +1 -1
- package/src/__tests__/tool-permission-simulate-handler.test.ts +8 -2
- package/src/__tests__/trusted-contact-approval-notifier.test.ts +9 -1
- package/src/__tests__/twitter-auth-handler.test.ts +2 -2
- package/src/__tests__/twitter-oauth-client.test.ts +1 -1
- package/src/__tests__/usage-routes.test.ts +339 -0
- package/src/__tests__/whatsapp-invite-adapter.test.ts +94 -0
- package/src/agent/loop.ts +3 -0
- package/src/amazon/checkout.ts +0 -1
- package/src/approvals/guardian-request-resolvers.ts +9 -1
- package/src/bundler/app-bundler.ts +28 -12
- package/src/bundler/bundle-scanner.ts +1 -1
- package/src/bundler/bundle-signer.ts +3 -3
- package/src/bundler/manifest.ts +1 -1
- package/src/bundler/signature-verifier.ts +3 -3
- package/src/channels/config.ts +1 -1
- package/src/cli/AGENTS.md +63 -0
- package/src/cli/__tests__/notifications.test.ts +470 -0
- package/src/cli/amazon.ts +344 -167
- package/src/cli/audit.ts +85 -0
- package/src/cli/autonomy.ts +369 -0
- package/src/cli/channels.ts +51 -0
- package/src/cli/completions.ts +208 -0
- package/src/cli/config.ts +220 -0
- package/src/cli/contacts.ts +471 -0
- package/src/cli/credentials.ts +564 -0
- package/src/cli/default-action.ts +14 -0
- package/src/cli/dev.ts +131 -0
- package/src/cli/doctor.ts +398 -0
- package/src/cli/email.ts +494 -0
- package/src/cli/influencer.ts +72 -0
- package/src/cli/integrations.ts +248 -57
- package/src/cli/keys.ts +114 -0
- package/src/cli/map.ts +46 -54
- package/src/cli/mcp.ts +111 -3
- package/src/cli/{config-commands.ts → memory.ts} +134 -245
- package/src/cli/notifications.ts +407 -0
- package/src/cli/program.ts +65 -0
- package/src/cli/reference.ts +48 -0
- package/src/cli/sequence.ts +154 -0
- package/src/cli/sessions.ts +262 -0
- package/src/cli/trust.ts +175 -0
- package/src/cli/twitter.ts +323 -106
- package/src/config/__tests__/build-cli-reference-section.test.ts +49 -0
- package/src/config/bundled-skills/amazon/SKILL.md +2 -2
- package/src/config/bundled-skills/app-builder/TOOLS.json +26 -0
- package/src/config/bundled-skills/app-builder/tools/app-generate-icon.ts +13 -0
- package/src/config/bundled-skills/contacts/SKILL.md +178 -10
- package/src/config/bundled-skills/doordash/doordash-cli.ts +23 -168
- package/src/config/bundled-skills/google-oauth-setup/SKILL.md +135 -34
- package/src/config/bundled-skills/messaging/tools/shared.ts +4 -1
- package/src/config/bundled-skills/twilio-setup/SKILL.md +70 -17
- package/src/config/bundled-tool-registry.ts +2 -0
- package/src/config/core-schema.ts +7 -0
- package/src/config/feature-flag-registry.json +16 -0
- package/src/config/loader.ts +26 -0
- package/src/config/schema.ts +4 -0
- package/src/config/skill-state.ts +0 -13
- package/src/config/system-prompt.ts +27 -0
- package/src/contacts/contact-store.ts +25 -0
- package/src/daemon/computer-use-session.ts +1 -1
- package/src/daemon/handlers/apps.ts +1 -0
- package/src/daemon/handlers/config-channels.ts +3 -3
- package/src/daemon/handlers/config-dispatch.ts +29 -0
- package/src/daemon/handlers/config-inbox.ts +4 -3
- package/src/daemon/handlers/config.ts +3 -43
- package/src/daemon/handlers/contacts.ts +34 -0
- package/src/daemon/handlers/index.ts +17 -3
- package/src/daemon/handlers/session-user-message.ts +7 -0
- package/src/daemon/handlers/sessions.ts +21 -2
- package/src/daemon/handlers/shared.ts +17 -0
- package/src/daemon/ipc-contract/apps.ts +2 -0
- package/src/daemon/ipc-contract/computer-use.ts +9 -0
- package/src/daemon/ipc-contract/contacts.ts +3 -3
- package/src/daemon/ipc-contract/inbox.ts +2 -0
- package/src/daemon/ipc-contract/messages.ts +4 -0
- package/src/daemon/ipc-contract/sessions.ts +8 -0
- package/src/daemon/ipc-contract-inventory.json +1 -0
- package/src/daemon/lifecycle.ts +0 -5
- package/src/daemon/ride-shotgun-handler.ts +139 -25
- package/src/daemon/session-agent-loop-handlers.ts +100 -0
- package/src/daemon/session-agent-loop.ts +72 -0
- package/src/daemon/session-tool-setup.ts +7 -0
- package/src/daemon/session.ts +23 -1
- package/src/daemon/tool-side-effects.ts +39 -1
- package/src/email/service.ts +59 -2
- package/src/index.ts +2 -60
- package/src/mcp/mcp-oauth-provider.ts +90 -8
- package/src/media/app-icon-generator.ts +86 -0
- package/src/memory/db-init.ts +11 -0
- package/src/memory/llm-usage-store.ts +186 -0
- package/src/memory/migrations/137-usage-dashboard-indexes.ts +26 -0
- package/src/memory/migrations/139-drop-usage-composite-indexes.ts +30 -0
- package/src/memory/migrations/index.ts +2 -0
- package/src/memory/schema-migration.ts +1 -0
- package/src/memory/shared-app-links-store.ts +1 -1
- package/src/messaging/registry.ts +27 -0
- package/src/notifications/README.md +79 -70
- package/src/notifications/broadcaster.ts +2 -1
- package/src/notifications/conversation-pairing.ts +147 -13
- package/src/notifications/copy-composer.ts +7 -3
- package/src/notifications/destination-resolver.ts +14 -1
- package/src/notifications/emit-signal.ts +3 -2
- package/src/notifications/signal.ts +105 -1
- package/src/notifications/types.ts +16 -0
- package/src/permissions/checker.ts +29 -3
- package/src/permissions/prompter.ts +11 -3
- package/src/runtime/access-request-helper.ts +2 -1
- package/src/runtime/auth/route-policy.ts +7 -1
- package/src/runtime/channel-invite-transport.ts +40 -63
- package/src/runtime/channel-invite-transports/email.ts +13 -39
- package/src/runtime/channel-invite-transports/slack.ts +5 -34
- package/src/runtime/channel-invite-transports/sms.ts +8 -29
- package/src/runtime/channel-invite-transports/telegram.ts +69 -28
- package/src/runtime/channel-invite-transports/voice.ts +0 -7
- package/src/runtime/channel-invite-transports/whatsapp.ts +43 -0
- package/src/runtime/channel-readiness-service.ts +202 -45
- package/src/runtime/confirmation-request-guardian-bridge.ts +2 -1
- package/src/runtime/guardian-outbound-actions.ts +8 -5
- package/src/runtime/http-server.ts +2 -0
- package/src/runtime/invite-instruction-generator.ts +178 -0
- package/src/runtime/invite-service.ts +22 -25
- package/src/runtime/migrations/migration-transport.ts +13 -0
- package/src/runtime/routes/app-routes.ts +1 -1
- package/src/runtime/routes/approval-strategies/guardian-callback-strategy.ts +8 -7
- package/src/runtime/routes/channel-readiness-routes.ts +30 -11
- package/src/runtime/routes/contact-routes.ts +54 -26
- package/src/runtime/routes/inbound-stages/bootstrap-intercept.ts +1 -1
- package/src/runtime/routes/inbound-stages/escalation-intercept.ts +2 -1
- package/src/runtime/routes/inbound-stages/verification-intercept.ts +2 -1
- package/src/runtime/routes/integration-routes.ts +1 -1
- package/src/runtime/routes/invite-routes.ts +1 -1
- package/src/runtime/routes/secret-routes.ts +31 -7
- package/src/runtime/routes/twilio-routes.ts +32 -1
- package/src/runtime/routes/usage-routes.ts +114 -0
- package/src/runtime/tool-grant-request-helper.ts +2 -1
- package/src/security/encrypted-store.ts +9 -5
- package/src/security/keychain-broker-client.ts +393 -0
- package/src/security/secure-keys.ts +106 -321
- package/src/tools/apps/executors.ts +73 -0
- package/src/tools/browser/auto-navigate.ts +15 -6
- package/src/tools/browser/chrome-cdp.ts +211 -0
- package/src/tools/browser/network-recorder.test.ts +83 -0
- package/src/tools/browser/network-recorder.ts +8 -7
- package/src/tools/browser/x-auto-navigate.ts +12 -6
- package/src/tools/credentials/policy-types.ts +24 -0
- package/src/tools/credentials/vault.ts +22 -27
- package/src/tools/network/script-proxy/session-manager.ts +47 -3
- package/src/tools/permission-checker.ts +1 -0
- package/src/tools/types.ts +2 -0
- package/src/tools/ui-surface/definitions.ts +1 -2
- package/src/tools/watch/watch-state.ts +2 -0
- package/src/__tests__/key-migration.test.ts +0 -240
- package/src/__tests__/keychain.test.ts +0 -286
- package/src/cli/core-commands.ts +0 -899
- package/src/security/keychain-to-encrypted-migration.ts +0 -66
- package/src/security/keychain.ts +0 -490
|
@@ -1,12 +1,5 @@
|
|
|
1
1
|
import type { Command } from "commander";
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
API_KEY_PROVIDERS,
|
|
5
|
-
getNestedValue,
|
|
6
|
-
loadRawConfig,
|
|
7
|
-
saveRawConfig,
|
|
8
|
-
setNestedValue,
|
|
9
|
-
} from "../config/loader.js";
|
|
10
3
|
import {
|
|
11
4
|
dismissPendingConflicts,
|
|
12
5
|
getMemorySystemStatus,
|
|
@@ -18,255 +11,65 @@ import {
|
|
|
18
11
|
import { listPendingConflictDetails } from "../memory/conflict-store.js";
|
|
19
12
|
import { listConversations } from "../memory/conversation-store.js";
|
|
20
13
|
import { initializeDb, rawGet } from "../memory/db.js";
|
|
21
|
-
import {
|
|
22
|
-
clearAllRules,
|
|
23
|
-
getAllRules,
|
|
24
|
-
removeRule,
|
|
25
|
-
} from "../permissions/trust-store.js";
|
|
26
|
-
import {
|
|
27
|
-
deleteSecureKey,
|
|
28
|
-
getSecureKey,
|
|
29
|
-
setSecureKey,
|
|
30
|
-
} from "../security/secure-keys.js";
|
|
31
14
|
import { getCliLogger } from "../util/logger.js";
|
|
32
15
|
|
|
33
16
|
const log = getCliLogger("cli");
|
|
34
17
|
|
|
35
18
|
const SHORT_HASH_LENGTH = 8;
|
|
36
19
|
|
|
37
|
-
export function registerConfigCommand(program: Command): void {
|
|
38
|
-
const config = program.command("config").description("Manage configuration");
|
|
39
|
-
|
|
40
|
-
config
|
|
41
|
-
.command("set <key> <value>")
|
|
42
|
-
.description(
|
|
43
|
-
"Set a config value (supports dotted paths like apiKeys.anthropic)",
|
|
44
|
-
)
|
|
45
|
-
.action((key: string, value: string) => {
|
|
46
|
-
const raw = loadRawConfig();
|
|
47
|
-
// Try to parse as JSON for booleans/numbers, fall back to string
|
|
48
|
-
let parsed: unknown = value;
|
|
49
|
-
try {
|
|
50
|
-
parsed = JSON.parse(value);
|
|
51
|
-
} catch {
|
|
52
|
-
// keep as string
|
|
53
|
-
}
|
|
54
|
-
setNestedValue(raw, key, parsed);
|
|
55
|
-
saveRawConfig(raw);
|
|
56
|
-
log.info(`Set ${key} = ${JSON.stringify(parsed)}`);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
config
|
|
60
|
-
.command("get <key>")
|
|
61
|
-
.description("Get a config value (supports dotted paths)")
|
|
62
|
-
.action((key: string) => {
|
|
63
|
-
const raw = loadRawConfig();
|
|
64
|
-
const value = getNestedValue(raw, key);
|
|
65
|
-
if (value === undefined) {
|
|
66
|
-
log.info(`(not set)`);
|
|
67
|
-
} else {
|
|
68
|
-
log.info(
|
|
69
|
-
typeof value === "object"
|
|
70
|
-
? JSON.stringify(value, null, 2)
|
|
71
|
-
: String(value),
|
|
72
|
-
);
|
|
73
|
-
}
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
config
|
|
77
|
-
.command("list")
|
|
78
|
-
.description("List all config values")
|
|
79
|
-
.action(() => {
|
|
80
|
-
const raw = loadRawConfig();
|
|
81
|
-
if (Object.keys(raw).length === 0) {
|
|
82
|
-
log.info("No configuration set");
|
|
83
|
-
} else {
|
|
84
|
-
log.info(JSON.stringify(raw, null, 2));
|
|
85
|
-
}
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
config
|
|
89
|
-
.command("validate-allowlist")
|
|
90
|
-
.description("Validate regex patterns in secret-allowlist.json")
|
|
91
|
-
.action(() => {
|
|
92
|
-
const { validateAllowlistFile } =
|
|
93
|
-
// eslint-disable-next-line @typescript-eslint/no-require-imports
|
|
94
|
-
require("../security/secret-allowlist.js") as typeof import("../security/secret-allowlist.js");
|
|
95
|
-
try {
|
|
96
|
-
const errors = validateAllowlistFile();
|
|
97
|
-
if (errors == null) {
|
|
98
|
-
log.info("No secret-allowlist.json file found");
|
|
99
|
-
return;
|
|
100
|
-
}
|
|
101
|
-
if (errors.length === 0) {
|
|
102
|
-
log.info("All patterns in secret-allowlist.json are valid");
|
|
103
|
-
return;
|
|
104
|
-
}
|
|
105
|
-
log.error(
|
|
106
|
-
`Found ${errors.length} invalid pattern(s) in secret-allowlist.json:`,
|
|
107
|
-
);
|
|
108
|
-
for (const e of errors) {
|
|
109
|
-
log.error(` [${e.index}] "${e.pattern}": ${e.message}`);
|
|
110
|
-
}
|
|
111
|
-
process.exit(1);
|
|
112
|
-
} catch (err) {
|
|
113
|
-
log.error(
|
|
114
|
-
`Failed to read secret-allowlist.json: ${(err as Error).message}`,
|
|
115
|
-
);
|
|
116
|
-
process.exit(1);
|
|
117
|
-
}
|
|
118
|
-
});
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
export function registerKeysCommand(program: Command): void {
|
|
122
|
-
const keys = program
|
|
123
|
-
.command("keys")
|
|
124
|
-
.description("Manage API keys in secure storage");
|
|
125
|
-
|
|
126
|
-
keys
|
|
127
|
-
.command("list")
|
|
128
|
-
.description("List all stored API key names")
|
|
129
|
-
.action(() => {
|
|
130
|
-
const stored: string[] = [];
|
|
131
|
-
for (const provider of API_KEY_PROVIDERS) {
|
|
132
|
-
const value = getSecureKey(provider);
|
|
133
|
-
if (value) stored.push(provider);
|
|
134
|
-
}
|
|
135
|
-
if (stored.length === 0) {
|
|
136
|
-
log.info("No API keys stored");
|
|
137
|
-
} else {
|
|
138
|
-
for (const name of stored) {
|
|
139
|
-
log.info(` ${name}`);
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
keys
|
|
145
|
-
.command("set <provider> <key>")
|
|
146
|
-
.description("Store an API key (e.g. vellum keys set anthropic sk-ant-...)")
|
|
147
|
-
.action((provider: string, key: string) => {
|
|
148
|
-
if (setSecureKey(provider, key)) {
|
|
149
|
-
log.info(`Stored API key for "${provider}"`);
|
|
150
|
-
} else {
|
|
151
|
-
log.error(`Failed to store API key for "${provider}"`);
|
|
152
|
-
process.exit(1);
|
|
153
|
-
}
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
keys
|
|
157
|
-
.command("delete <provider>")
|
|
158
|
-
.description("Delete a stored API key")
|
|
159
|
-
.action((provider: string) => {
|
|
160
|
-
if (deleteSecureKey(provider)) {
|
|
161
|
-
log.info(`Deleted API key for "${provider}"`);
|
|
162
|
-
} else {
|
|
163
|
-
log.error(`No API key found for "${provider}"`);
|
|
164
|
-
process.exit(1);
|
|
165
|
-
}
|
|
166
|
-
});
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
export function registerTrustCommand(program: Command): void {
|
|
170
|
-
const trust = program.command("trust").description("Manage trust rules");
|
|
171
|
-
|
|
172
|
-
trust
|
|
173
|
-
.command("list")
|
|
174
|
-
.description("List all trust rules")
|
|
175
|
-
.action(() => {
|
|
176
|
-
const rules = getAllRules();
|
|
177
|
-
if (rules.length === 0) {
|
|
178
|
-
log.info("No trust rules");
|
|
179
|
-
return;
|
|
180
|
-
}
|
|
181
|
-
const idW = 8;
|
|
182
|
-
const toolW = 12;
|
|
183
|
-
const patternW = 30;
|
|
184
|
-
const scopeW = 20;
|
|
185
|
-
const decW = 6;
|
|
186
|
-
const priW = 4;
|
|
187
|
-
log.info(
|
|
188
|
-
"ID".padEnd(idW) +
|
|
189
|
-
"Tool".padEnd(toolW) +
|
|
190
|
-
"Pattern".padEnd(patternW) +
|
|
191
|
-
"Scope".padEnd(scopeW) +
|
|
192
|
-
"Dcn".padEnd(decW) +
|
|
193
|
-
"Pri".padEnd(priW) +
|
|
194
|
-
"Created",
|
|
195
|
-
);
|
|
196
|
-
log.info("-".repeat(idW + toolW + patternW + scopeW + decW + priW + 20));
|
|
197
|
-
for (const r of rules) {
|
|
198
|
-
const id = r.id.slice(0, SHORT_HASH_LENGTH);
|
|
199
|
-
const created = new Date(r.createdAt).toISOString().slice(0, 10);
|
|
200
|
-
log.info(
|
|
201
|
-
id.padEnd(idW) +
|
|
202
|
-
r.tool.padEnd(toolW) +
|
|
203
|
-
r.pattern.slice(0, patternW - 2).padEnd(patternW) +
|
|
204
|
-
r.scope.slice(0, scopeW - 2).padEnd(scopeW) +
|
|
205
|
-
r.decision.slice(0, decW - 1).padEnd(decW) +
|
|
206
|
-
String(r.priority).padEnd(priW) +
|
|
207
|
-
created,
|
|
208
|
-
);
|
|
209
|
-
}
|
|
210
|
-
});
|
|
211
|
-
|
|
212
|
-
trust
|
|
213
|
-
.command("remove <id>")
|
|
214
|
-
.description("Remove a trust rule by ID (or prefix)")
|
|
215
|
-
.action((id: string) => {
|
|
216
|
-
const rules = getAllRules();
|
|
217
|
-
const match = rules.find((r) => r.id.startsWith(id));
|
|
218
|
-
if (!match) {
|
|
219
|
-
log.error(`No rule found matching "${id}"`);
|
|
220
|
-
process.exit(1);
|
|
221
|
-
}
|
|
222
|
-
try {
|
|
223
|
-
removeRule(match.id);
|
|
224
|
-
} catch (err) {
|
|
225
|
-
log.error(err instanceof Error ? err.message : String(err));
|
|
226
|
-
process.exit(1);
|
|
227
|
-
}
|
|
228
|
-
log.info(
|
|
229
|
-
`Removed rule ${match.id.slice(0, SHORT_HASH_LENGTH)} (${match.tool}: ${
|
|
230
|
-
match.pattern
|
|
231
|
-
})`,
|
|
232
|
-
);
|
|
233
|
-
});
|
|
234
|
-
|
|
235
|
-
trust
|
|
236
|
-
.command("clear")
|
|
237
|
-
.description("Remove all trust rules")
|
|
238
|
-
.action(async () => {
|
|
239
|
-
const rules = getAllRules();
|
|
240
|
-
if (rules.length === 0) {
|
|
241
|
-
log.info("No trust rules to clear");
|
|
242
|
-
return;
|
|
243
|
-
}
|
|
244
|
-
const readline = await import("node:readline");
|
|
245
|
-
const rl = readline.createInterface({
|
|
246
|
-
input: process.stdin,
|
|
247
|
-
output: process.stdout,
|
|
248
|
-
});
|
|
249
|
-
const answer = await new Promise<string>((resolve) => {
|
|
250
|
-
rl.question(`Remove all ${rules.length} trust rules? (y/N) `, resolve);
|
|
251
|
-
});
|
|
252
|
-
rl.close();
|
|
253
|
-
if (answer.toLowerCase() === "y") {
|
|
254
|
-
clearAllRules();
|
|
255
|
-
log.info(`Cleared ${rules.length} trust rules`);
|
|
256
|
-
} else {
|
|
257
|
-
log.info("Cancelled");
|
|
258
|
-
}
|
|
259
|
-
});
|
|
260
|
-
}
|
|
261
|
-
|
|
262
20
|
export function registerMemoryCommand(program: Command): void {
|
|
263
21
|
const memory = program
|
|
264
22
|
.command("memory")
|
|
265
23
|
.description("Manage long-term memory indexing/retrieval");
|
|
266
24
|
|
|
25
|
+
memory.addHelpText(
|
|
26
|
+
"after",
|
|
27
|
+
`
|
|
28
|
+
The memory subsystem indexes conversation segments into full-text search (FTS)
|
|
29
|
+
and vector embeddings for semantic recall. When the assistant encounters new
|
|
30
|
+
information that contradicts a stored fact, a conflict is created and held in
|
|
31
|
+
"pending_clarification" status until explicitly dismissed or resolved.
|
|
32
|
+
|
|
33
|
+
Key concepts:
|
|
34
|
+
segments Chunks of conversation text extracted for indexing
|
|
35
|
+
items Distilled facts/statements derived from segments
|
|
36
|
+
summaries Compressed representations of conversation history
|
|
37
|
+
embeddings Vector representations used for semantic similarity search
|
|
38
|
+
conflicts Pairs of contradictory statements awaiting resolution
|
|
39
|
+
|
|
40
|
+
Examples:
|
|
41
|
+
$ vellum memory status
|
|
42
|
+
$ vellum memory query "What is the project deadline?"
|
|
43
|
+
$ vellum memory backfill
|
|
44
|
+
$ vellum memory dismiss-conflicts --all`,
|
|
45
|
+
);
|
|
46
|
+
|
|
267
47
|
memory
|
|
268
48
|
.command("status")
|
|
269
49
|
.description("Show memory subsystem status")
|
|
50
|
+
.addHelpText(
|
|
51
|
+
"after",
|
|
52
|
+
`
|
|
53
|
+
Displays a comprehensive snapshot of the memory subsystem's health and counts.
|
|
54
|
+
|
|
55
|
+
Fields shown:
|
|
56
|
+
enabled/degraded Whether memory is active and whether it is running in a
|
|
57
|
+
degraded mode (e.g. missing embedding backend)
|
|
58
|
+
embedding backend The provider/model pair used for vector embeddings (or "none")
|
|
59
|
+
segments Total conversation segments indexed
|
|
60
|
+
items Total distilled fact items stored
|
|
61
|
+
summaries Total compressed conversation summaries
|
|
62
|
+
embeddings Total vector embeddings computed
|
|
63
|
+
pending conflicts Conflicts awaiting user resolution
|
|
64
|
+
resolved conflicts Conflicts that have been dismissed or resolved
|
|
65
|
+
oldest pending age How long the oldest unresolved conflict has been waiting
|
|
66
|
+
cleanup backlogs Number of resolved conflicts and superseded items pending cleanup
|
|
67
|
+
cleanup throughput Number of cleanup operations completed in the last 24 hours
|
|
68
|
+
jobs Status of background jobs (backfill, cleanup, rebuild-index)
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
$ vellum memory status`,
|
|
72
|
+
)
|
|
270
73
|
.action(() => {
|
|
271
74
|
initializeDb();
|
|
272
75
|
const status = getMemorySystemStatus();
|
|
@@ -318,6 +121,21 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
318
121
|
.command("backfill")
|
|
319
122
|
.description("Queue a memory backfill job")
|
|
320
123
|
.option("-f, --force", "Restart backfill from the beginning")
|
|
124
|
+
.addHelpText(
|
|
125
|
+
"after",
|
|
126
|
+
`
|
|
127
|
+
Queues a background job to index unprocessed conversation segments into FTS
|
|
128
|
+
and vector embeddings. The job resumes from where the last backfill left off,
|
|
129
|
+
processing only new or unindexed segments.
|
|
130
|
+
|
|
131
|
+
The --force flag restarts the backfill from the very beginning, reprocessing
|
|
132
|
+
all segments regardless of whether they have already been indexed. This is
|
|
133
|
+
useful after bulk imports or if the incremental state has become inconsistent.
|
|
134
|
+
|
|
135
|
+
Examples:
|
|
136
|
+
$ vellum memory backfill
|
|
137
|
+
$ vellum memory backfill --force`,
|
|
138
|
+
)
|
|
321
139
|
.action((opts: { force?: boolean }) => {
|
|
322
140
|
initializeDb();
|
|
323
141
|
const jobId = requestMemoryBackfill(Boolean(opts?.force));
|
|
@@ -333,6 +151,23 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
333
151
|
"--retention-ms <ms>",
|
|
334
152
|
"Optional retention threshold in milliseconds",
|
|
335
153
|
)
|
|
154
|
+
.addHelpText(
|
|
155
|
+
"after",
|
|
156
|
+
`
|
|
157
|
+
Queues two background cleanup jobs:
|
|
158
|
+
1. Resolved conflicts cleanup — removes conflict records that have been
|
|
159
|
+
dismissed or resolved past the retention threshold.
|
|
160
|
+
2. Stale superseded items cleanup — removes memory items that have been
|
|
161
|
+
superseded by newer, corrected facts past the retention threshold.
|
|
162
|
+
|
|
163
|
+
The optional --retention-ms flag sets the minimum age (in milliseconds) a
|
|
164
|
+
record must have before it is eligible for cleanup. If omitted, the system
|
|
165
|
+
default retention period is used.
|
|
166
|
+
|
|
167
|
+
Examples:
|
|
168
|
+
$ vellum memory cleanup
|
|
169
|
+
$ vellum memory cleanup --retention-ms 86400000`,
|
|
170
|
+
)
|
|
336
171
|
.action((opts: { retentionMs?: string }) => {
|
|
337
172
|
initializeDb();
|
|
338
173
|
const retentionMs = opts.retentionMs
|
|
@@ -355,6 +190,27 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
355
190
|
"Run a memory recall query and print the injected memory payload",
|
|
356
191
|
)
|
|
357
192
|
.option("-s, --session <id>", "Optional conversation/session ID")
|
|
193
|
+
.addHelpText(
|
|
194
|
+
"after",
|
|
195
|
+
`
|
|
196
|
+
Arguments:
|
|
197
|
+
text The recall query string used to search memory (e.g. "What is the
|
|
198
|
+
project deadline?"). Matched against indexed segments using the full
|
|
199
|
+
recall pipeline: lexical (FTS), semantic (vector similarity), recency
|
|
200
|
+
(time-weighted), and entity (named entity extraction).
|
|
201
|
+
|
|
202
|
+
Runs the complete memory recall pipeline and displays hit counts for each
|
|
203
|
+
retrieval strategy, the total injected token count, query latency, and the
|
|
204
|
+
assembled memory text that would be injected into context.
|
|
205
|
+
|
|
206
|
+
The optional --session flag provides a conversation/session ID for
|
|
207
|
+
context-aware recall. If omitted, the most recent conversation is used.
|
|
208
|
+
|
|
209
|
+
Examples:
|
|
210
|
+
$ vellum memory query "What is the project deadline?"
|
|
211
|
+
$ vellum memory query "preferred communication style" --session conv_abc123
|
|
212
|
+
$ vellum memory query "API rate limits"`,
|
|
213
|
+
)
|
|
358
214
|
.action(async (text: string, opts?: { session?: string }) => {
|
|
359
215
|
initializeDb();
|
|
360
216
|
let sessionId = opts?.session;
|
|
@@ -383,6 +239,21 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
383
239
|
memory
|
|
384
240
|
.command("rebuild-index")
|
|
385
241
|
.description("Queue a memory FTS+embedding index rebuild job")
|
|
242
|
+
.addHelpText(
|
|
243
|
+
"after",
|
|
244
|
+
`
|
|
245
|
+
Queues a background job that performs a full rebuild of both the FTS (full-text
|
|
246
|
+
search) index and the vector embedding index. All existing index data is
|
|
247
|
+
dropped and reconstructed from the source memory items.
|
|
248
|
+
|
|
249
|
+
This is useful after schema changes, embedding model upgrades, or if index
|
|
250
|
+
corruption is suspected. The rebuild runs asynchronously; use "vellum memory
|
|
251
|
+
status" to monitor job progress.
|
|
252
|
+
|
|
253
|
+
Examples:
|
|
254
|
+
$ vellum memory rebuild-index
|
|
255
|
+
$ vellum memory status`,
|
|
256
|
+
)
|
|
386
257
|
.action(() => {
|
|
387
258
|
initializeDb();
|
|
388
259
|
const jobId = requestMemoryRebuildIndex();
|
|
@@ -399,6 +270,26 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
399
270
|
)
|
|
400
271
|
.option("-s, --scope <id>", 'Memory scope (default: "default")')
|
|
401
272
|
.option("--dry-run", "Show what would be dismissed without making changes")
|
|
273
|
+
.addHelpText(
|
|
274
|
+
"after",
|
|
275
|
+
`
|
|
276
|
+
Two modes of operation:
|
|
277
|
+
--all Dismiss every pending conflict in the scope
|
|
278
|
+
--pattern <regex> Dismiss only conflicts where either the existing or
|
|
279
|
+
candidate statement matches the given regex (case-insensitive)
|
|
280
|
+
|
|
281
|
+
At least one of --all or --pattern must be provided. If both are given,
|
|
282
|
+
--all takes priority and all pending conflicts are dismissed.
|
|
283
|
+
|
|
284
|
+
The --scope flag targets a specific memory scope. Defaults to "default" if
|
|
285
|
+
omitted. The --dry-run flag previews which conflicts would be dismissed
|
|
286
|
+
without actually modifying any records.
|
|
287
|
+
|
|
288
|
+
Examples:
|
|
289
|
+
$ vellum memory dismiss-conflicts --all
|
|
290
|
+
$ vellum memory dismiss-conflicts --pattern "project deadline" --dry-run
|
|
291
|
+
$ vellum memory dismiss-conflicts --pattern "^preferred\\b" --scope work`,
|
|
292
|
+
)
|
|
402
293
|
.action(
|
|
403
294
|
(opts: {
|
|
404
295
|
all?: boolean;
|
|
@@ -407,9 +298,7 @@ export function registerMemoryCommand(program: Command): void {
|
|
|
407
298
|
dryRun?: boolean;
|
|
408
299
|
}) => {
|
|
409
300
|
if (!opts.all && !opts.pattern) {
|
|
410
|
-
log.info(
|
|
411
|
-
"Usage: vellum memory dismiss-conflicts --all OR --pattern <regex>",
|
|
412
|
-
);
|
|
301
|
+
log.info("At least one of --all or --pattern must be provided.");
|
|
413
302
|
log.info("Use --dry-run to preview without making changes.");
|
|
414
303
|
return;
|
|
415
304
|
}
|