@openparachute/vault 0.4.9-rc.9 → 0.5.0-rc.2
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/README.md +51 -54
- package/core/src/core.test.ts +4 -1
- package/core/src/indexed-fields.test.ts +151 -0
- package/core/src/indexed-fields.ts +98 -0
- package/core/src/mcp.ts +66 -43
- package/core/src/notes.ts +26 -2
- package/core/src/portable-md.test.ts +52 -0
- package/core/src/portable-md.ts +48 -0
- package/core/src/schema.ts +87 -14
- package/core/src/store.ts +117 -0
- package/core/src/types.ts +28 -0
- package/package.json +2 -2
- package/src/auth-hub-jwt.test.ts +191 -11
- package/src/auth-status.ts +12 -5
- package/src/auth.test.ts +135 -219
- package/src/auth.ts +158 -107
- package/src/cli.ts +306 -224
- package/src/config.ts +12 -4
- package/src/export-watch.test.ts +23 -0
- package/src/export-watch.ts +14 -0
- package/src/git-preflight.test.ts +70 -0
- package/src/git-preflight.ts +68 -0
- package/src/hub-jwt.test.ts +27 -2
- package/src/hub-jwt.ts +10 -0
- package/src/init-summary.test.ts +4 -4
- package/src/init-summary.ts +36 -10
- package/src/mcp-config.test.ts +4 -2
- package/src/mcp-http.ts +24 -3
- package/src/mcp-install-interactive.test.ts +33 -71
- package/src/mcp-install-interactive.ts +23 -76
- package/src/mcp-install.test.ts +156 -55
- package/src/mcp-install.ts +109 -3
- package/src/mcp-tools.ts +249 -74
- package/src/mirror-config.test.ts +107 -0
- package/src/mirror-config.ts +275 -9
- package/src/mirror-credentials.test.ts +168 -17
- package/src/mirror-credentials.ts +155 -32
- package/src/mirror-deps.ts +25 -16
- package/src/mirror-import.test.ts +122 -16
- package/src/mirror-import.ts +50 -16
- package/src/mirror-manager.test.ts +51 -0
- package/src/mirror-manager.ts +116 -22
- package/src/mirror-per-vault.test.ts +519 -0
- package/src/mirror-registry.ts +91 -14
- package/src/mirror-routes.test.ts +81 -21
- package/src/mirror-routes.ts +90 -16
- package/src/routes.ts +39 -2
- package/src/routing.test.ts +203 -118
- package/src/routing.ts +46 -59
- package/src/scopes.test.ts +0 -86
- package/src/scopes.ts +9 -97
- package/src/server.ts +102 -34
- package/src/storage.test.ts +132 -7
- package/src/token-store.test.ts +88 -169
- package/src/token-store.ts +123 -249
- package/src/vault-create.test.ts +12 -4
- package/src/vault.test.ts +408 -103
- package/web/ui/dist/assets/index-DDRo6F4u.js +60 -0
- package/web/ui/dist/index.html +1 -1
- package/src/tokens-routes.test.ts +0 -727
- package/src/tokens-routes.ts +0 -392
- package/web/ui/dist/assets/index-Degr8snN.js +0 -60
package/src/cli.ts
CHANGED
|
@@ -98,9 +98,8 @@ import {
|
|
|
98
98
|
} from "./daemon.ts";
|
|
99
99
|
import { confirm, ask, askPassword, choose } from "./prompt.ts";
|
|
100
100
|
import { resolveBindHostname } from "./bind.ts";
|
|
101
|
-
import {
|
|
102
|
-
import
|
|
103
|
-
import { resolveCreateTokenFlags, VAULT_SCOPES } from "./scopes.ts";
|
|
101
|
+
import { listTokens, revokeToken, migrateVaultKeys } from "./token-store.ts";
|
|
102
|
+
import { VAULT_SCOPES } from "./scopes.ts";
|
|
104
103
|
import { validateVaultName, decideInitVaultName } from "./vault-name.ts";
|
|
105
104
|
import { getVaultStore } from "./vault-store.ts";
|
|
106
105
|
import { selfRegister } from "./self-register.ts";
|
|
@@ -161,7 +160,7 @@ switch (command) {
|
|
|
161
160
|
await cmdInit(cmdArgs);
|
|
162
161
|
break;
|
|
163
162
|
case "create":
|
|
164
|
-
cmdCreate(cmdArgs);
|
|
163
|
+
await cmdCreate(cmdArgs);
|
|
165
164
|
break;
|
|
166
165
|
case "list":
|
|
167
166
|
case "ls":
|
|
@@ -222,6 +221,9 @@ switch (command) {
|
|
|
222
221
|
case "export":
|
|
223
222
|
await cmdExport(cmdArgs);
|
|
224
223
|
break;
|
|
224
|
+
case "schema":
|
|
225
|
+
await cmdSchema(cmdArgs);
|
|
226
|
+
break;
|
|
225
227
|
case "help":
|
|
226
228
|
case "--help":
|
|
227
229
|
case "-h":
|
|
@@ -295,12 +297,19 @@ async function cmdInit(args: string[] = []) {
|
|
|
295
297
|
// piped installs keep working unchanged.
|
|
296
298
|
const vaults = listVaults();
|
|
297
299
|
let apiKey: string | undefined;
|
|
300
|
+
// Guidance carried from the bootstrap-credential step — surfaced at the end
|
|
301
|
+
// when no token could be issued (standalone, no hub) so the operator knows
|
|
302
|
+
// how to make the vault reachable. vault#282 Stage 2.
|
|
303
|
+
let credentialGuidance: string | undefined;
|
|
298
304
|
if (vaults.length === 0) {
|
|
299
305
|
const chosenName =
|
|
300
306
|
nameDecision.kind === "name" ? nameDecision.name : await promptVaultName();
|
|
301
307
|
console.log(`Creating vault "${chosenName}"...`);
|
|
302
|
-
|
|
308
|
+
const credential = await createVault(chosenName);
|
|
309
|
+
apiKey = credential.token ?? undefined;
|
|
310
|
+
credentialGuidance = credential.guidance;
|
|
303
311
|
console.log(` Created vault: ${chosenName}`);
|
|
312
|
+
console.log(` ${credential.guidance}`);
|
|
304
313
|
} else {
|
|
305
314
|
if (vaultNameFlagSupplied) {
|
|
306
315
|
console.log(
|
|
@@ -482,25 +491,29 @@ async function cmdInit(args: string[] = []) {
|
|
|
482
491
|
}
|
|
483
492
|
|
|
484
493
|
// Mint a token if we need one (for the claude.json entry and/or for
|
|
485
|
-
// prominent display) and don't already have one from vault creation
|
|
486
|
-
//
|
|
487
|
-
//
|
|
494
|
+
// prominent display) and don't already have one from vault creation —
|
|
495
|
+
// e.g. a re-run of init against an existing vault. vault#282 Stage 2: vault
|
|
496
|
+
// no longer mints pvt_* tokens, so this is a hub JWT via the operator.token
|
|
497
|
+
// → hub mint-token path (`mintBootstrapCredential`). When no hub is
|
|
498
|
+
// reachable, `apiKey` stays undefined and we carry the guidance to the
|
|
499
|
+
// summary — the operator runs `mcp-install` once a hub is up, or sets
|
|
500
|
+
// VAULT_AUTH_TOKEN.
|
|
488
501
|
const defaultVault = globalConfig.default_vault || "default";
|
|
489
502
|
const needToken = addMcp || addToken;
|
|
490
503
|
if (needToken && !apiKey) {
|
|
491
|
-
const
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
apiKey
|
|
504
|
+
const credential = await mintBootstrapCredential(defaultVault);
|
|
505
|
+
apiKey = credential.token ?? undefined;
|
|
506
|
+
credentialGuidance = credential.guidance;
|
|
507
|
+
if (!apiKey) console.log(` ${credential.guidance}`);
|
|
495
508
|
}
|
|
496
509
|
|
|
497
510
|
if (addMcp) {
|
|
498
|
-
//
|
|
499
|
-
//
|
|
500
|
-
//
|
|
501
|
-
//
|
|
502
|
-
//
|
|
503
|
-
//
|
|
511
|
+
// Goes through `buildMcpEntryPlan` for entryKey + url so this path shares
|
|
512
|
+
// the writer-side invariant with `executeMcpInstall` — a future URL-shape
|
|
513
|
+
// change can't drift between init and mcp-install. The bearer is the hub
|
|
514
|
+
// JWT minted above (omitted when no hub was reachable — the entry is then
|
|
515
|
+
// written unauthenticated, and the operator re-runs `mcp-install` once a
|
|
516
|
+
// hub is up).
|
|
504
517
|
const target = resolveInstallTarget("user");
|
|
505
518
|
const { entryKey, url, source } = buildMcpEntryPlan({
|
|
506
519
|
vaultName: defaultVault,
|
|
@@ -531,6 +544,7 @@ async function cmdInit(args: string[] = []) {
|
|
|
531
544
|
bindHost,
|
|
532
545
|
port,
|
|
533
546
|
mcpUrl,
|
|
547
|
+
noTokenGuidance: credentialGuidance,
|
|
534
548
|
});
|
|
535
549
|
for (const line of lines) console.log(line);
|
|
536
550
|
}
|
|
@@ -794,7 +808,7 @@ async function cmd2fa(args: string[]) {
|
|
|
794
808
|
process.exit(1);
|
|
795
809
|
}
|
|
796
810
|
|
|
797
|
-
function cmdCreate(args: string[]) {
|
|
811
|
+
async function cmdCreate(args: string[]) {
|
|
798
812
|
// --json: emit a single machine-readable object on stdout instead of the
|
|
799
813
|
// human-friendly multi-line print. Designed for orchestrators (the hub's
|
|
800
814
|
// POST /vaults shells out to this CLI and parses stdout). Errors still go
|
|
@@ -832,7 +846,7 @@ function cmdCreate(args: string[]) {
|
|
|
832
846
|
|
|
833
847
|
ensureConfigDirSync();
|
|
834
848
|
const wasFirst = listVaults().length === 0;
|
|
835
|
-
const
|
|
849
|
+
const credential = await createVault(name);
|
|
836
850
|
|
|
837
851
|
// If this is the only vault now, make it the default so unscoped routes
|
|
838
852
|
// (/mcp, /api/*, /oauth/*) target it. Avoids the "single vault named
|
|
@@ -867,9 +881,16 @@ function cmdCreate(args: string[]) {
|
|
|
867
881
|
});
|
|
868
882
|
|
|
869
883
|
if (jsonMode) {
|
|
884
|
+
// Contract (hub's admin-vaults.ts requires `typeof token === "string"`):
|
|
885
|
+
// emit the minted hub JWT when present. When no hub was reachable
|
|
886
|
+
// (standalone create — no operator.token / no hub origin), `token` is the
|
|
887
|
+
// empty string and `token_guidance` carries the operator's next step. Hub
|
|
888
|
+
// only shells out to `create --json` while IT is the orchestrator (a hub is
|
|
889
|
+
// running, operator.token present), so that path always mints a real JWT.
|
|
870
890
|
const payload = {
|
|
871
891
|
name,
|
|
872
|
-
token:
|
|
892
|
+
token: credential.token ?? "",
|
|
893
|
+
token_guidance: credential.guidance,
|
|
873
894
|
paths: {
|
|
874
895
|
vault_dir: vaultDir(name),
|
|
875
896
|
vault_db: vaultDbPath(name),
|
|
@@ -883,8 +904,13 @@ function cmdCreate(args: string[]) {
|
|
|
883
904
|
|
|
884
905
|
console.log(`Vault "${name}" created.`);
|
|
885
906
|
console.log(` Path: ${vaultDir(name)}`);
|
|
886
|
-
|
|
887
|
-
|
|
907
|
+
if (credential.token) {
|
|
908
|
+
console.log(` API token: ${credential.token}`);
|
|
909
|
+
console.log(` ${credential.guidance}`);
|
|
910
|
+
console.log(` Save this — it will not be shown again.`);
|
|
911
|
+
} else {
|
|
912
|
+
console.log(` ${credential.guidance}`);
|
|
913
|
+
}
|
|
888
914
|
if (defaultNote) {
|
|
889
915
|
console.log(` ${defaultNote}`);
|
|
890
916
|
}
|
|
@@ -922,22 +948,20 @@ function takeArgValue(args: string[], name: string): { value?: string; missingVa
|
|
|
922
948
|
|
|
923
949
|
/**
|
|
924
950
|
* `parachute-vault mcp-install` — install the vault MCP server into an
|
|
925
|
-
* AI client's config.
|
|
951
|
+
* AI client's config. Two auth modes (mutually exclusive — vault#282 Stage 2
|
|
952
|
+
* dropped the `--legacy-pat` pvt_* mint; vault is a pure hub resource-server):
|
|
926
953
|
*
|
|
927
954
|
* --mint (default) Mint a hub JWT via `POST <hub>/api/auth/mint-token`
|
|
928
955
|
* using the local operator token.
|
|
929
|
-
* --token <bearer> Use an existing
|
|
930
|
-
* --legacy-pat Mint a vault-DB `pvt_*` token (deprecated;
|
|
931
|
-
* self-hosted-without-hub setups).
|
|
956
|
+
* --token <bearer> Use an existing bearer (hub JWT or VAULT_AUTH_TOKEN).
|
|
932
957
|
*
|
|
933
958
|
* Targeting:
|
|
934
959
|
* --scope <verb> vault:read | vault:write | vault:admin (default: vault:read).
|
|
935
960
|
* For --mint, expands to vault:<vault-name>:<verb>.
|
|
936
|
-
* vault:admin
|
|
937
|
-
* per-vault admin
|
|
938
|
-
*
|
|
939
|
-
*
|
|
940
|
-
* is rejected pre-flight.
|
|
961
|
+
* vault:admin is mintable via --mint as of hub PR-A
|
|
962
|
+
* (hub#449): hub mints per-vault admin when the operator
|
|
963
|
+
* bearer carries parachute:host:admin (the default
|
|
964
|
+
* operator.token does). Requires a hub running PR-A.
|
|
941
965
|
* --install-scope <s> local (default) | user | project. local writes to
|
|
942
966
|
* ~/.claude.json under projects[<cwd>].mcpServers
|
|
943
967
|
* (private, this directory only — matches Claude
|
|
@@ -958,7 +982,6 @@ async function cmdMcpInstall(args: string[]): Promise<void> {
|
|
|
958
982
|
// dead zone when the function body first executes from that dispatch.
|
|
959
983
|
const MCP_INSTALL_FLAG_NAMES = [
|
|
960
984
|
"--mint",
|
|
961
|
-
"--legacy-pat",
|
|
962
985
|
"--token",
|
|
963
986
|
"--scope",
|
|
964
987
|
"--install-scope",
|
|
@@ -980,22 +1003,21 @@ async function cmdMcpInstall(args: string[]): Promise<void> {
|
|
|
980
1003
|
return await cmdMcpInstallInteractive();
|
|
981
1004
|
}
|
|
982
1005
|
|
|
983
|
-
// --- Auth-mode parsing (mutually exclusive)
|
|
1006
|
+
// --- Auth-mode parsing (mutually exclusive). vault#282 Stage 2 dropped
|
|
1007
|
+
// --legacy-pat (the pvt_* mint) — vault is a pure hub resource-server, so
|
|
1008
|
+
// the only auth modes are --mint (hub JWT, default) and --token (paste). ---
|
|
984
1009
|
const wantMint = args.includes("--mint");
|
|
985
|
-
const wantLegacy = args.includes("--legacy-pat");
|
|
986
1010
|
const tokenArg = takeArgValue(args, "--token");
|
|
987
1011
|
if (tokenArg.missingValue) {
|
|
988
1012
|
console.error("--token requires a value (the bearer token to embed).");
|
|
989
1013
|
process.exit(1);
|
|
990
1014
|
}
|
|
991
1015
|
const wantToken = tokenArg.value !== undefined;
|
|
992
|
-
|
|
993
|
-
|
|
994
|
-
console.error("--mint, --token, and --legacy-pat are mutually exclusive.");
|
|
1016
|
+
if (wantMint && wantToken) {
|
|
1017
|
+
console.error("--mint and --token are mutually exclusive.");
|
|
995
1018
|
process.exit(1);
|
|
996
1019
|
}
|
|
997
|
-
const mode: "mint" | "token"
|
|
998
|
-
wantToken ? "token" : wantLegacy ? "legacy-pat" : "mint";
|
|
1020
|
+
const mode: "mint" | "token" = wantToken ? "token" : "mint";
|
|
999
1021
|
|
|
1000
1022
|
// --- Scope parsing. Default vault:read (least-privilege). ---
|
|
1001
1023
|
const scopeArg = takeArgValue(args, "--scope");
|
|
@@ -1130,7 +1152,7 @@ async function cmdMcpInstallInteractive(): Promise<void> {
|
|
|
1130
1152
|
* the canonical synthesizer — the JSON shape is owned here once.
|
|
1131
1153
|
*
|
|
1132
1154
|
* No state is mutated; this only emits to stdout. The bearer is read from
|
|
1133
|
-
* `--token <
|
|
1155
|
+
* `--token <bearer>` or `PARACHUTE_VAULT_TOKEN` env (deliberate — we don't
|
|
1134
1156
|
* mint here, since this is a stdout-piped subprocess where prompting would
|
|
1135
1157
|
* deadlock the parent script). If neither is present, we exit 1 with a
|
|
1136
1158
|
* clear stderr message; runners get a fail-fast.
|
|
@@ -1147,7 +1169,7 @@ async function cmdMcpInstallInteractive(): Promise<void> {
|
|
|
1147
1169
|
async function cmdMcpConfig(args: string[]): Promise<void> {
|
|
1148
1170
|
const vaultName = args[0];
|
|
1149
1171
|
if (!vaultName || vaultName.startsWith("--")) {
|
|
1150
|
-
console.error("Usage: parachute-vault mcp-config <vault-name> [--token <
|
|
1172
|
+
console.error("Usage: parachute-vault mcp-config <vault-name> [--token <bearer>] [--base-url <url>] [--env-vars]");
|
|
1151
1173
|
console.error("");
|
|
1152
1174
|
console.error("Emits the JSON config consumed by `claude -p --mcp-config '<json>'`.");
|
|
1153
1175
|
console.error("Pattern: claude -p --mcp-config \"$(parachute-vault mcp-config <name>)\" --strict-mcp-config ...");
|
|
@@ -1192,7 +1214,7 @@ async function cmdMcpConfig(args: string[]): Promise<void> {
|
|
|
1192
1214
|
const bearer = tokenArg.value ?? process.env.PARACHUTE_VAULT_TOKEN;
|
|
1193
1215
|
if (!bearer) {
|
|
1194
1216
|
console.error("No bearer token provided. Pass --token <bearer> or set PARACHUTE_VAULT_TOKEN.");
|
|
1195
|
-
console.error(" Mint a
|
|
1217
|
+
console.error(" Mint a hub JWT with: parachute-vault mcp-install --vault " + vaultName + " (or `parachute auth mint-token`)");
|
|
1196
1218
|
console.error(" Or use --env-vars to emit the template form (safe to commit; expands at runtime).");
|
|
1197
1219
|
process.exit(1);
|
|
1198
1220
|
}
|
|
@@ -1219,7 +1241,7 @@ async function cmdMcpConfig(args: string[]): Promise<void> {
|
|
|
1219
1241
|
}
|
|
1220
1242
|
|
|
1221
1243
|
interface ExecuteMcpInstallOpts {
|
|
1222
|
-
mode: "mint" | "token"
|
|
1244
|
+
mode: "mint" | "token";
|
|
1223
1245
|
/** Full scope string (e.g. "vault:read"). The verb segment narrows downstream. */
|
|
1224
1246
|
rawScope: string;
|
|
1225
1247
|
installScope: InstallScope;
|
|
@@ -1303,59 +1325,24 @@ async function executeMcpInstall(opts: ExecuteMcpInstallOpts): Promise<void> {
|
|
|
1303
1325
|
}
|
|
1304
1326
|
bearer = pastedToken;
|
|
1305
1327
|
console.log(`Using supplied token (skipping mint).`);
|
|
1306
|
-
} else if (mode === "legacy-pat") {
|
|
1307
|
-
console.error(
|
|
1308
|
-
"Note: --legacy-pat mints a vault-DB pvt_* token. The hub-issued JWT path (--mint, default) " +
|
|
1309
|
-
"is the canonical install going forward; pvt_* support is preserved for self-hosted-without-hub " +
|
|
1310
|
-
"setups, tracked at vault#288, planned removal 0.6.0.",
|
|
1311
|
-
);
|
|
1312
|
-
const store = getVaultStore(vaultName);
|
|
1313
|
-
const { fullToken } = generateToken();
|
|
1314
|
-
// Narrow the pvt_* to the requested verb's scope set when not full-admin.
|
|
1315
|
-
// `scopes: undefined` leaves the token at full vault permissions
|
|
1316
|
-
// (admin); narrowing to a single-scope array gates it to that verb.
|
|
1317
|
-
const createTokenOpts: Parameters<typeof createToken>[2] = {
|
|
1318
|
-
label: "mcp-install",
|
|
1319
|
-
permission: verb === "read" ? "read" : "full",
|
|
1320
|
-
vault_name: vaultName,
|
|
1321
|
-
};
|
|
1322
|
-
if (verb !== "admin") {
|
|
1323
|
-
createTokenOpts.scopes = [rawScope];
|
|
1324
|
-
}
|
|
1325
|
-
createToken(store.db, fullToken, createTokenOpts);
|
|
1326
|
-
bearer = fullToken;
|
|
1327
1328
|
} else {
|
|
1328
1329
|
// mode === "mint"
|
|
1329
|
-
//
|
|
1330
|
-
//
|
|
1331
|
-
//
|
|
1332
|
-
//
|
|
1333
|
-
//
|
|
1334
|
-
//
|
|
1335
|
-
//
|
|
1336
|
-
//
|
|
1337
|
-
//
|
|
1338
|
-
// `parachute-hub/src/scope-explanations.ts` (VAULT_ADMIN_RE) and
|
|
1339
|
-
// `parachute-hub/src/api-mint-token.ts` (non-requestable guard).
|
|
1340
|
-
if (verb === "admin") {
|
|
1341
|
-
console.error(
|
|
1342
|
-
"Hub policy: vault:<name>:admin is not requestable via mint-token " +
|
|
1343
|
-
"(per-vault admin is operator-only, minted only by the session-cookie-gated " +
|
|
1344
|
-
"admin SPA at <hub>/admin/vaults/" + vaultName + ").\n" +
|
|
1345
|
-
" Fix: use `--legacy-pat --scope vault:admin` to mint a vault-DB pvt_* with admin scope " +
|
|
1346
|
-
"(the right shape for an MCP entry needing schema management).\n" +
|
|
1347
|
-
" Or: drop --scope to default to vault:read (least privilege), or use --scope vault:write.",
|
|
1348
|
-
);
|
|
1349
|
-
process.exit(1);
|
|
1350
|
-
}
|
|
1330
|
+
// `vault:<name>:admin` is mintable via the hub mint-token endpoint as
|
|
1331
|
+
// of hub PR-A (hub#449): the hub mints per-vault admin when the calling
|
|
1332
|
+
// operator bearer carries `parachute:host:admin` (which the default
|
|
1333
|
+
// operator.token does). No admin pre-flight reject — the narrowScope
|
|
1334
|
+
// below produces `vault:<name>:admin` and the hub honors it. This
|
|
1335
|
+
// requires a hub running PR-A; older hubs reject admin with HTTP 400
|
|
1336
|
+
// invalid_scope, surfaced via the api-error branch below. There is no
|
|
1337
|
+
// local pvt_* fallback anymore (vault#282 Stage 2) — without a hub, the
|
|
1338
|
+
// operator pastes an existing bearer via `--token` or sets VAULT_AUTH_TOKEN.
|
|
1351
1339
|
const operatorToken = readOperatorToken();
|
|
1352
1340
|
if (!operatorToken) {
|
|
1353
1341
|
console.error(
|
|
1354
1342
|
"No operator token found at ~/.parachute/operator.token. The default install path " +
|
|
1355
1343
|
"(--mint) requires a hub-issued operator token to mint scope-narrow JWTs.\n" +
|
|
1356
1344
|
" Fix: run `parachute auth rotate-operator` to create one, then re-run.\n" +
|
|
1357
|
-
" Or: use `--token <bearer>` to paste an existing token, or
|
|
1358
|
-
"mint a vault-DB pvt_* token (self-hosted-without-hub).",
|
|
1345
|
+
" Or: use `--token <bearer>` to paste an existing token, or set VAULT_AUTH_TOKEN.",
|
|
1359
1346
|
);
|
|
1360
1347
|
process.exit(1);
|
|
1361
1348
|
}
|
|
@@ -1367,7 +1354,7 @@ async function executeMcpInstall(opts: ExecuteMcpInstallOpts): Promise<void> {
|
|
|
1367
1354
|
"Hub-mint (--mint) needs a real hub URL to call. Either:\n" +
|
|
1368
1355
|
" - Start the hub and set PARACHUTE_HUB_ORIGIN, OR\n" +
|
|
1369
1356
|
" - Bring up an exposure (`parachute expose tailnet`), OR\n" +
|
|
1370
|
-
" - Use --
|
|
1357
|
+
" - Use --token <bearer> to paste an existing token instead.",
|
|
1371
1358
|
);
|
|
1372
1359
|
process.exit(1);
|
|
1373
1360
|
}
|
|
@@ -1384,13 +1371,24 @@ async function executeMcpInstall(opts: ExecuteMcpInstallOpts): Promise<void> {
|
|
|
1384
1371
|
console.error(
|
|
1385
1372
|
`Hub unreachable at ${result.origin} — ${result.cause}.\n` +
|
|
1386
1373
|
` Fix: verify the hub is running and PARACHUTE_HUB_ORIGIN is set, ` +
|
|
1387
|
-
`or use --
|
|
1374
|
+
`or use --token <bearer> to skip hub-mint.`,
|
|
1388
1375
|
);
|
|
1389
1376
|
break;
|
|
1390
1377
|
case "api-error":
|
|
1391
1378
|
console.error(
|
|
1392
1379
|
`Hub mint-token rejected (HTTP ${result.status}, ${result.error}): ${result.description}`,
|
|
1393
1380
|
);
|
|
1381
|
+
// Older hubs (pre-hub#449) reject vault:<name>:admin as a
|
|
1382
|
+
// non-requestable scope with HTTP 400 invalid_scope. Surface an
|
|
1383
|
+
// actionable hint so the operator reaches for the upgrade rather
|
|
1384
|
+
// than chasing the wire-level error.
|
|
1385
|
+
if (result.status === 400 && verb === "admin") {
|
|
1386
|
+
console.error(
|
|
1387
|
+
" Hint: minting vault:admin requires a hub with per-vault admin mint support " +
|
|
1388
|
+
"(hub#449). Your hub may predate it — upgrade the hub, or use --token <bearer> " +
|
|
1389
|
+
"to paste an existing admin token instead.",
|
|
1390
|
+
);
|
|
1391
|
+
}
|
|
1394
1392
|
break;
|
|
1395
1393
|
}
|
|
1396
1394
|
process.exit(1);
|
|
@@ -1580,94 +1578,29 @@ function cmdTokens(args: string[]) {
|
|
|
1580
1578
|
}
|
|
1581
1579
|
|
|
1582
1580
|
if (!anyTokens) {
|
|
1583
|
-
console.log(
|
|
1581
|
+
console.log(
|
|
1582
|
+
"No vault-DB tokens found. Vault tokens are now hub-issued JWTs — " +
|
|
1583
|
+
"run `parachute-vault mcp-install` to mint one.",
|
|
1584
|
+
);
|
|
1584
1585
|
}
|
|
1585
1586
|
return;
|
|
1586
1587
|
}
|
|
1587
1588
|
|
|
1588
|
-
//
|
|
1589
|
-
//
|
|
1590
|
-
//
|
|
1591
|
-
//
|
|
1592
|
-
//
|
|
1593
|
-
//
|
|
1594
|
-
// (vault_name = NULL) and authenticates against any vault. --all is
|
|
1595
|
-
// the explicit opt-out — there's no implicit fall-through to server-wide.
|
|
1589
|
+
// `tokens create` was removed at 0.5.0 (vault#282 Stage 2). Vault no longer
|
|
1590
|
+
// mints its own (pvt_*) tokens — it's a pure hub resource-server. Tokens are
|
|
1591
|
+
// now hub-issued JWTs: run `parachute-vault mcp-install` to mint + wire one
|
|
1592
|
+
// for an MCP client, or `parachute auth mint-token --scope vault:<name>:<verb>`
|
|
1593
|
+
// for scripts. `tokens list` / `tokens revoke` remain for cleaning up any
|
|
1594
|
+
// vestigial pre-0.5.0 rows.
|
|
1596
1595
|
if (subcmd === "create") {
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1600
|
-
|
|
1601
|
-
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
console.error("--vault requires a value.");
|
|
1606
|
-
process.exit(1);
|
|
1607
|
-
}
|
|
1608
|
-
|
|
1609
|
-
const vc = readVaultConfig(vaultName);
|
|
1610
|
-
if (!vc) {
|
|
1611
|
-
console.error(`Vault "${vaultName}" not found.`);
|
|
1612
|
-
process.exit(1);
|
|
1613
|
-
}
|
|
1614
|
-
|
|
1615
|
-
// Combining --scope / --read / --permission is always an error: a
|
|
1616
|
-
// user minting a token expects exactly one narrowing signal, and
|
|
1617
|
-
// silently picking one would mint the opposite of what the other
|
|
1618
|
-
// reading intended. See resolveCreateTokenFlags.
|
|
1619
|
-
const resolved = resolveCreateTokenFlags(args);
|
|
1620
|
-
if (resolved.error) {
|
|
1621
|
-
console.error(resolved.error);
|
|
1622
|
-
process.exit(1);
|
|
1623
|
-
}
|
|
1624
|
-
const scopes = resolved.scopes;
|
|
1625
|
-
const permission: TokenPermission = resolved.permission;
|
|
1626
|
-
|
|
1627
|
-
const expiresFlag = args.indexOf("--expires");
|
|
1628
|
-
let expiresAt: string | null = null;
|
|
1629
|
-
if (expiresFlag !== -1) {
|
|
1630
|
-
const dur = args[expiresFlag + 1];
|
|
1631
|
-
if (!dur) {
|
|
1632
|
-
console.error("--expires requires a value (e.g. 7d, 30d, 24h, 1y).");
|
|
1633
|
-
process.exit(1);
|
|
1634
|
-
}
|
|
1635
|
-
expiresAt = parseDuration(dur);
|
|
1636
|
-
if (!expiresAt) {
|
|
1637
|
-
console.error(`Invalid duration: ${dur}. Use format like 7d, 30d, 24h, 1y.`);
|
|
1638
|
-
process.exit(1);
|
|
1639
|
-
}
|
|
1640
|
-
}
|
|
1641
|
-
|
|
1642
|
-
const labelFlag = args.indexOf("--label");
|
|
1643
|
-
const label = (labelFlag !== -1 ? args[labelFlag + 1] : undefined) ?? "default";
|
|
1644
|
-
|
|
1645
|
-
const store = getVaultStore(vaultName);
|
|
1646
|
-
const { fullToken } = generateToken();
|
|
1647
|
-
createToken(store.db, fullToken, {
|
|
1648
|
-
label,
|
|
1649
|
-
permission,
|
|
1650
|
-
scopes,
|
|
1651
|
-
expires_at: expiresAt,
|
|
1652
|
-
// v16 binding: pin to the vault we minted in unless --all was passed
|
|
1653
|
-
// (which leaves vault_name NULL = legacy server-wide).
|
|
1654
|
-
vault_name: allFlag ? null : vaultName,
|
|
1655
|
-
});
|
|
1656
|
-
|
|
1657
|
-
const displayScopes = scopes ?? [...VAULT_SCOPES];
|
|
1658
|
-
const heading = allFlag
|
|
1659
|
-
? `Created server-wide token (authenticates against any vault):`
|
|
1660
|
-
: `Created token for vault "${vaultName}":`;
|
|
1661
|
-
console.log(heading);
|
|
1662
|
-
console.log(` Token: ${fullToken}`);
|
|
1663
|
-
console.log(` Permission: ${permission}`);
|
|
1664
|
-
console.log(` Scopes: ${displayScopes.join(" ")}`);
|
|
1665
|
-
if (expiresAt) console.log(` Expires: ${expiresAt}`);
|
|
1666
|
-
console.log(` Label: ${label}`);
|
|
1667
|
-
if (!allFlag) console.log(` Vault: ${vaultName}`);
|
|
1668
|
-
console.log();
|
|
1669
|
-
console.log("Save this token — it will not be shown again.");
|
|
1670
|
-
return;
|
|
1596
|
+
console.error(
|
|
1597
|
+
"`parachute-vault tokens create` was removed at 0.5.0 — vault no longer mints its own tokens.\n" +
|
|
1598
|
+
" Mint a hub-issued JWT instead:\n" +
|
|
1599
|
+
" parachute-vault mcp-install --scope vault:<verb> # wire an MCP client\n" +
|
|
1600
|
+
" parachute auth mint-token --scope vault:<name>:<verb> # for scripts\n" +
|
|
1601
|
+
" See UPGRADING.md (pvt_* token removal, vault#282).",
|
|
1602
|
+
);
|
|
1603
|
+
process.exit(1);
|
|
1671
1604
|
}
|
|
1672
1605
|
|
|
1673
1606
|
// parachute-vault tokens revoke <token-id> --vault <name>
|
|
@@ -1706,23 +1639,6 @@ function cmdTokens(args: string[]) {
|
|
|
1706
1639
|
process.exit(1);
|
|
1707
1640
|
}
|
|
1708
1641
|
|
|
1709
|
-
function parseDuration(dur: string): string | null {
|
|
1710
|
-
const match = dur.match(/^(\d+)(h|d|w|m|y)$/);
|
|
1711
|
-
if (!match) return null;
|
|
1712
|
-
const n = parseInt(match[1]!, 10);
|
|
1713
|
-
const unit = match[2]!;
|
|
1714
|
-
const now = new Date();
|
|
1715
|
-
switch (unit) {
|
|
1716
|
-
case "h": now.setHours(now.getHours() + n); break;
|
|
1717
|
-
case "d": now.setDate(now.getDate() + n); break;
|
|
1718
|
-
case "w": now.setDate(now.getDate() + n * 7); break;
|
|
1719
|
-
case "m": now.setMonth(now.getMonth() + n); break;
|
|
1720
|
-
case "y": now.setFullYear(now.getFullYear() + n); break;
|
|
1721
|
-
default: return null;
|
|
1722
|
-
}
|
|
1723
|
-
return now.toISOString();
|
|
1724
|
-
}
|
|
1725
|
-
|
|
1726
1642
|
async function cmdServe() {
|
|
1727
1643
|
await import("./server.ts");
|
|
1728
1644
|
}
|
|
@@ -3217,6 +3133,92 @@ async function cmdExport(args: string[]) {
|
|
|
3217
3133
|
await new Promise(() => {});
|
|
3218
3134
|
}
|
|
3219
3135
|
|
|
3136
|
+
// ---------------------------------------------------------------------------
|
|
3137
|
+
// Schema maintenance — `parachute-vault schema <subcommand>`
|
|
3138
|
+
// ---------------------------------------------------------------------------
|
|
3139
|
+
|
|
3140
|
+
/**
|
|
3141
|
+
* `parachute-vault schema prune` — drop orphaned indexed-field columns +
|
|
3142
|
+
* indexes whose declaring tags no longer exist (the gitcoin orphaned-fields
|
|
3143
|
+
* bug). Dry-run by default; `--apply` (alias `--yes`) executes. A field
|
|
3144
|
+
* co-declared by a still-live tag is never dropped — only the dead declarers
|
|
3145
|
+
* are trimmed. Dropping a generated column loses only the index; the source
|
|
3146
|
+
* values stay in notes.metadata, so the column rebuilds when the field is
|
|
3147
|
+
* declared again.
|
|
3148
|
+
*/
|
|
3149
|
+
async function cmdSchema(args: string[] = []) {
|
|
3150
|
+
const sub = args[0];
|
|
3151
|
+
if (sub !== "prune") {
|
|
3152
|
+
console.error("Usage: parachute-vault schema prune [--vault <name>] [--dry-run|--apply|--yes]");
|
|
3153
|
+
console.error("\nSubcommands:");
|
|
3154
|
+
console.error(" prune Drop orphaned indexed-field columns whose declaring tags are gone.");
|
|
3155
|
+
console.error(" Dry-run by default (--dry-run is an explicit alias); pass --apply (or --yes) to execute.");
|
|
3156
|
+
process.exit(1);
|
|
3157
|
+
}
|
|
3158
|
+
|
|
3159
|
+
let vaultName = "default";
|
|
3160
|
+
let apply = false;
|
|
3161
|
+
for (let i = 1; i < args.length; i++) {
|
|
3162
|
+
const arg = args[i]!;
|
|
3163
|
+
if (arg === "--vault") {
|
|
3164
|
+
const v = args[++i];
|
|
3165
|
+
if (!v) {
|
|
3166
|
+
console.error("--vault requires a value.");
|
|
3167
|
+
process.exit(1);
|
|
3168
|
+
}
|
|
3169
|
+
vaultName = v;
|
|
3170
|
+
} else if (arg === "--apply" || arg === "--yes") {
|
|
3171
|
+
apply = true;
|
|
3172
|
+
} else if (arg === "--dry-run") {
|
|
3173
|
+
// Dry-run is the default; accept the flag as an explicit affirmative
|
|
3174
|
+
// for convention + scriptability. --apply wins if both are passed.
|
|
3175
|
+
} else {
|
|
3176
|
+
console.error(`Unknown flag for \`schema prune\`: ${arg}`);
|
|
3177
|
+
process.exit(1);
|
|
3178
|
+
}
|
|
3179
|
+
}
|
|
3180
|
+
|
|
3181
|
+
const config = readVaultConfig(vaultName);
|
|
3182
|
+
if (!config) {
|
|
3183
|
+
console.error(`Vault "${vaultName}" not found.`);
|
|
3184
|
+
process.exit(1);
|
|
3185
|
+
}
|
|
3186
|
+
|
|
3187
|
+
const { getVaultStore } = await import("./vault-store.ts");
|
|
3188
|
+
const store = getVaultStore(vaultName);
|
|
3189
|
+
const plan = await store.pruneIndexedFields({ dryRun: !apply });
|
|
3190
|
+
|
|
3191
|
+
const dropped = plan.filter((p) => p.dropped);
|
|
3192
|
+
const trimmed = plan.filter((p) => !p.dropped);
|
|
3193
|
+
|
|
3194
|
+
if (plan.length === 0) {
|
|
3195
|
+
console.log(`No orphaned indexed fields in vault "${vaultName}". Nothing to prune.`);
|
|
3196
|
+
return;
|
|
3197
|
+
}
|
|
3198
|
+
|
|
3199
|
+
console.log(
|
|
3200
|
+
apply
|
|
3201
|
+
? `Pruned orphaned indexed fields in vault "${vaultName}":`
|
|
3202
|
+
: `Would prune orphaned indexed fields in vault "${vaultName}" (dry-run):`,
|
|
3203
|
+
);
|
|
3204
|
+
for (const p of dropped) {
|
|
3205
|
+
console.log(
|
|
3206
|
+
` ${apply ? "DROPPED" : "drop "} ${p.field} (dead declarers: ${p.deadDeclarers.join(", ")})`,
|
|
3207
|
+
);
|
|
3208
|
+
}
|
|
3209
|
+
for (const p of trimmed) {
|
|
3210
|
+
console.log(
|
|
3211
|
+
` ${apply ? "TRIMMED" : "trim "} ${p.field} (removed dead declarers: ${p.deadDeclarers.join(", ")}; column kept — still co-declared)`,
|
|
3212
|
+
);
|
|
3213
|
+
}
|
|
3214
|
+
console.log(
|
|
3215
|
+
`\n${apply ? "Dropped" : "Would drop"} ${dropped.length} orphaned field(s); ${apply ? "trimmed" : "would trim"} ${trimmed.length} co-declared field(s).`,
|
|
3216
|
+
);
|
|
3217
|
+
if (!apply) {
|
|
3218
|
+
console.log("Re-run with --apply (or --yes) to execute.");
|
|
3219
|
+
}
|
|
3220
|
+
}
|
|
3221
|
+
|
|
3220
3222
|
// ---------------------------------------------------------------------------
|
|
3221
3223
|
// Export-watch glue. The git-shell + commit-message logic lives in
|
|
3222
3224
|
// `./export-watch.ts` for unit-testability; cli.ts just wires it in.
|
|
@@ -3269,7 +3271,86 @@ async function firstChangedNoteTitle(
|
|
|
3269
3271
|
// Helpers
|
|
3270
3272
|
// ---------------------------------------------------------------------------
|
|
3271
3273
|
|
|
3272
|
-
|
|
3274
|
+
/**
|
|
3275
|
+
* Outcome of bootstrapping a fresh vault's first credential (vault#282 Stage 2).
|
|
3276
|
+
*
|
|
3277
|
+
* Vault no longer mints `pvt_*` tokens. The first credential for a new vault is
|
|
3278
|
+
* a hub-issued JWT, minted via the same operator.token → hub mint-token path
|
|
3279
|
+
* `mcp-install --mint` uses (cli.ts ~`cmdMcpInstall`). When no hub is reachable
|
|
3280
|
+
* (standalone install, no operator.token, or no real hub origin), `token` is
|
|
3281
|
+
* null and `guidance` carries the operator's next step.
|
|
3282
|
+
*/
|
|
3283
|
+
interface VaultCredential {
|
|
3284
|
+
/** Hub-issued JWT scoped to `vault:<name>:admin`, or null when no hub is reachable. */
|
|
3285
|
+
token: string | null;
|
|
3286
|
+
/** Human-readable note: how the token was issued, or why it wasn't. */
|
|
3287
|
+
guidance: string;
|
|
3288
|
+
}
|
|
3289
|
+
|
|
3290
|
+
/**
|
|
3291
|
+
* Mint the first credential for a freshly-created vault.
|
|
3292
|
+
*
|
|
3293
|
+
* Decision (vault#282 Stage 2): when a hub is reachable (operator.token present
|
|
3294
|
+
* AND a real hub origin resolves), mint a `vault:<name>:admin` hub JWT and
|
|
3295
|
+
* return it as the bootstrap credential — preserving the `create --json`
|
|
3296
|
+
* `token` string contract hub's admin-vaults.ts requires. When no hub is
|
|
3297
|
+
* reachable, return `token: null` plus explicit standalone guidance. There is
|
|
3298
|
+
* no local pvt_* fallback anymore.
|
|
3299
|
+
*/
|
|
3300
|
+
async function mintBootstrapCredential(name: string): Promise<VaultCredential> {
|
|
3301
|
+
const operatorToken = readOperatorToken();
|
|
3302
|
+
if (!operatorToken) {
|
|
3303
|
+
return {
|
|
3304
|
+
token: null,
|
|
3305
|
+
guidance:
|
|
3306
|
+
"No token issued — no hub operator token at ~/.parachute/operator.token. " +
|
|
3307
|
+
"Install the hub (`bun add -g @openparachute/hub` + `parachute init`) and re-run, " +
|
|
3308
|
+
"or set VAULT_AUTH_TOKEN for an operator-channel bearer.",
|
|
3309
|
+
};
|
|
3310
|
+
}
|
|
3311
|
+
const port = readGlobalConfig().port || DEFAULT_PORT;
|
|
3312
|
+
const hub = chooseHubOrigin(port);
|
|
3313
|
+
if (hub.source === "loopback") {
|
|
3314
|
+
return {
|
|
3315
|
+
token: null,
|
|
3316
|
+
guidance:
|
|
3317
|
+
"No token issued — no hub origin configured (PARACHUTE_HUB_ORIGIN unset, no active " +
|
|
3318
|
+
"expose-state). Start the hub and set PARACHUTE_HUB_ORIGIN (or bring up an exposure), " +
|
|
3319
|
+
"then run `parachute-vault mcp-install`, or set VAULT_AUTH_TOKEN.",
|
|
3320
|
+
};
|
|
3321
|
+
}
|
|
3322
|
+
const result = await mintHubJwt({
|
|
3323
|
+
hubOrigin: hub.url,
|
|
3324
|
+
operatorToken,
|
|
3325
|
+
scope: `vault:${name}:admin`,
|
|
3326
|
+
subject: "parachute-vault-bootstrap",
|
|
3327
|
+
});
|
|
3328
|
+
if ("kind" in result) {
|
|
3329
|
+
const detail =
|
|
3330
|
+
result.kind === "network"
|
|
3331
|
+
? `hub unreachable at ${result.origin} — ${result.cause}`
|
|
3332
|
+
: `hub mint-token rejected (HTTP ${result.status}, ${result.error}): ${result.description}`;
|
|
3333
|
+
return {
|
|
3334
|
+
token: null,
|
|
3335
|
+
guidance:
|
|
3336
|
+
`No token issued — ${detail}. Verify the hub is running (hub#449 for vault:admin mint), ` +
|
|
3337
|
+
"then run `parachute-vault mcp-install`, or set VAULT_AUTH_TOKEN.",
|
|
3338
|
+
};
|
|
3339
|
+
}
|
|
3340
|
+
return {
|
|
3341
|
+
token: result.token,
|
|
3342
|
+
guidance: `Minted hub JWT (jti=${result.jti}, expires ${result.expires_at}, scope ${result.scope}).`,
|
|
3343
|
+
};
|
|
3344
|
+
}
|
|
3345
|
+
|
|
3346
|
+
/**
|
|
3347
|
+
* Create a vault's config + DB and mint its first credential.
|
|
3348
|
+
*
|
|
3349
|
+
* Returns the bootstrap credential (a hub JWT, or null + guidance when no hub
|
|
3350
|
+
* is reachable — vault#282 Stage 2). The DB is created lazily via
|
|
3351
|
+
* `getVaultStore` so migrations + schema run; we no longer write any pvt_* row.
|
|
3352
|
+
*/
|
|
3353
|
+
async function createVault(name: string): Promise<VaultCredential> {
|
|
3273
3354
|
const config: VaultConfig = {
|
|
3274
3355
|
name,
|
|
3275
3356
|
api_keys: [],
|
|
@@ -3277,11 +3358,10 @@ function createVault(name: string): string {
|
|
|
3277
3358
|
};
|
|
3278
3359
|
writeVaultConfig(config);
|
|
3279
3360
|
|
|
3280
|
-
//
|
|
3281
|
-
|
|
3282
|
-
|
|
3283
|
-
|
|
3284
|
-
return fullToken;
|
|
3361
|
+
// Touch the store so the vault's SQLite DB + schema are created. No token
|
|
3362
|
+
// row is written — vault is a pure hub resource-server post-0.5.0.
|
|
3363
|
+
getVaultStore(name);
|
|
3364
|
+
return mintBootstrapCredential(name);
|
|
3285
3365
|
}
|
|
3286
3366
|
|
|
3287
3367
|
interface InstallMcpConfigOpts {
|
|
@@ -3388,7 +3468,7 @@ Vaults:
|
|
|
3388
3468
|
parachute-vault create <name> [--json] Create a new vault (--json: emit { name, token, paths, set_as_default })
|
|
3389
3469
|
parachute-vault list List all vaults
|
|
3390
3470
|
parachute-vault remove <name> [--yes] Remove a vault
|
|
3391
|
-
parachute-vault mcp-install [--mint|--token <t
|
|
3471
|
+
parachute-vault mcp-install [--mint|--token <t>]
|
|
3392
3472
|
[--scope vault:read|vault:write|vault:admin]
|
|
3393
3473
|
[--install-scope local|user|project]
|
|
3394
3474
|
[--vault <name>] [--client claude-code]
|
|
@@ -3406,16 +3486,17 @@ Vaults:
|
|
|
3406
3486
|
matches Claude Code's claude-mcp-add
|
|
3407
3487
|
default) with vault:read scope.
|
|
3408
3488
|
--token <t>: paste an existing bearer
|
|
3409
|
-
(
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3489
|
+
(hub JWT or VAULT_AUTH_TOKEN) instead of
|
|
3490
|
+
minting. (vault#282 Stage 2 removed the
|
|
3491
|
+
--legacy-pat pvt_* mint — vault is a pure
|
|
3492
|
+
hub resource-server now; without a hub,
|
|
3493
|
+
paste a bearer or set VAULT_AUTH_TOKEN.)
|
|
3494
|
+
--scope vault:admin IS mintable via
|
|
3495
|
+
--mint (hub#449): hub mints
|
|
3496
|
+
vault:<name>:admin when the operator
|
|
3497
|
+
bearer carries parachute:host:admin
|
|
3498
|
+
(the default operator.token does).
|
|
3499
|
+
Requires a hub running hub#449.
|
|
3419
3500
|
--install-scope local (default) writes
|
|
3420
3501
|
~/.claude.json under
|
|
3421
3502
|
projects[<cwd>].mcpServers (this
|
|
@@ -3437,7 +3518,7 @@ Vaults:
|
|
|
3437
3518
|
without touching disk or hitting the
|
|
3438
3519
|
hub. Useful for probing.
|
|
3439
3520
|
|
|
3440
|
-
parachute-vault mcp-config <vault-name> [--token <
|
|
3521
|
+
parachute-vault mcp-config <vault-name> [--token <bearer>] [--base-url <url>]
|
|
3441
3522
|
[--env-vars]
|
|
3442
3523
|
Emit the JSON config consumed by
|
|
3443
3524
|
\`claude -p --mcp-config '<json>'\`.
|
|
@@ -3455,22 +3536,13 @@ Vaults:
|
|
|
3455
3536
|
\${PARACHUTE_VAULT_TOKEN} placeholders
|
|
3456
3537
|
(safe to commit; expanded at runtime).
|
|
3457
3538
|
|
|
3458
|
-
Tokens
|
|
3459
|
-
|
|
3539
|
+
Tokens (vault#282 Stage 2 — vault is a pure hub resource-server; it no longer
|
|
3540
|
+
mints its own tokens. Mint a hub-issued JWT with \`parachute-vault mcp-install\`
|
|
3541
|
+
or \`parachute auth mint-token --scope vault:<name>:<verb>\`. \`list\` / \`revoke\`
|
|
3542
|
+
below operate on any vestigial pre-0.5.0 rows for cleanup.):
|
|
3543
|
+
parachute-vault tokens List vault-DB tokens (every vault)
|
|
3460
3544
|
parachute-vault tokens list --vault <name> List tokens for one vault only
|
|
3461
|
-
parachute-vault tokens
|
|
3462
|
-
parachute-vault tokens create --vault <name> Create a token bound to a specific vault
|
|
3463
|
-
parachute-vault tokens create --all Create a server-wide token (vault_name=NULL).
|
|
3464
|
-
Authenticates against any vault — use sparingly,
|
|
3465
|
-
for cross-vault automation only.
|
|
3466
|
-
parachute-vault tokens create --read Read-only token (shorthand for --scope vault:read)
|
|
3467
|
-
parachute-vault tokens create --scope vault:write
|
|
3468
|
-
Narrow the token's scopes. Accepts a comma-separated
|
|
3469
|
-
list or repeated --scope flags. Valid scopes:
|
|
3470
|
-
vault:read, vault:write, vault:admin.
|
|
3471
|
-
parachute-vault tokens create --label x Set a label
|
|
3472
|
-
parachute-vault tokens create --expires 30d Expiring token
|
|
3473
|
-
parachute-vault tokens revoke <token-id> Revoke a token (default vault)
|
|
3545
|
+
parachute-vault tokens revoke <token-id> Revoke a vestigial token (default vault)
|
|
3474
3546
|
|
|
3475
3547
|
OAuth — owner password + 2FA (LEGACY):
|
|
3476
3548
|
Vault's standalone OAuth consent page was retired in 0.4.x (workstream E).
|
|
@@ -3513,6 +3585,16 @@ Import/Export:
|
|
|
3513
3585
|
template via --git-message-template;
|
|
3514
3586
|
--git-push to push after commit)
|
|
3515
3587
|
|
|
3588
|
+
Schema maintenance:
|
|
3589
|
+
parachute-vault schema prune [--vault <name>] Drop orphaned indexed-field columns +
|
|
3590
|
+
indexes whose declaring tags no longer
|
|
3591
|
+
exist. Dry-run by default (--dry-run is an
|
|
3592
|
+
explicit alias) — prints the drop plan
|
|
3593
|
+
without changing anything.
|
|
3594
|
+
parachute-vault schema prune --apply Execute the prune (alias: --yes). Co-declared
|
|
3595
|
+
fields keep their column; a drop loses only
|
|
3596
|
+
the index (data lives in notes.metadata).
|
|
3597
|
+
|
|
3516
3598
|
── Advanced / standalone ──────────────────────────────────────────────
|
|
3517
3599
|
|
|
3518
3600
|
Direct daemon controls. For normal use, prefer the Parachute Hub wrappers
|