@partrocks/tokenvault 0.1.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 ADDED
@@ -0,0 +1,122 @@
1
+ # @partrocks/tokenvault
2
+
3
+ TypeScript library for **Node 20+** and **Bun** that drives the **[tokenvault](https://github.com/partrocks/tokenVault)** CLI from your app. It wraps `tokenvault` as a subprocess (`node:child_process`): no in-process vault API.
4
+
5
+ Use it to **bootstrap** a profile (credential, connection, attach, model cache, capability selection), **list** vault contents, **resolve secrets** per **capability** (`chat`, `embeddings`, …), and **change the model** for a capability without reimplementing CLI flags.
6
+
7
+ ## How it works
8
+
9
+ 1. **Locate** the `tokenvault` binary: `TOKENVAULT_BIN` env, else `PATH`.
10
+ 2. **Environment**: merges `TOKENVAULT_SECURE_STORE` defaults by OS (Keychain / Windows / Linux secret service) when unset, same idea as the hand-rolled bootstrap in the tokenVault project.
11
+ 3. **JSON vs TTY**: non-interactive steps use `tokenvault --json …` with captured stdout/stderr; interactive steps (e.g. `credential add`) inherit stdio.
12
+ 4. **Providers**: pluggable **`TokenVaultBootstrapProvider`** (OpenAI built in as **`builtInProviders.openai`**). You pass one into **`createTokenVault`**. Validation after `resolve` is provider-specific (e.g. OpenAI expects `providerId === "openai"`).
13
+ 5. **Published build**: npm tarball contains **`dist/`** only (ESM + `.d.ts`). **`prepublishOnly`** runs **`bun run build`** (`tsup`).
14
+
15
+ ## Install
16
+
17
+ ```bash
18
+ bun add @partrocks/tokenvault
19
+ # or
20
+ npm install @partrocks/tokenvault
21
+ ```
22
+
23
+ Local development: point your app at this directory with a `file:` dependency.
24
+
25
+ ## Requirements
26
+
27
+ - **`tokenvault`** on `PATH`, or **`TOKENVAULT_BIN`** set to the executable.
28
+ - Optional: **`TOKENVAULT_PASSPHRASE`**, **`TOKENVAULT_SECURE_STORE`** — same semantics as the tokenVault CLI.
29
+
30
+ ## Quick start
31
+
32
+ ```ts
33
+ import {
34
+ createTokenVault,
35
+ CAPABILITY,
36
+ builtInProviders,
37
+ } from "@partrocks/tokenvault";
38
+
39
+ const tokenVault = createTokenVault({
40
+ provider: builtInProviders.openai,
41
+ namespace: "myapp",
42
+ appLabel: "myapp",
43
+ defaultModelByCapability: { [CAPABILITY.chat]: "gpt-4o-mini" },
44
+ });
45
+
46
+ // Idempotent: resolve first; if missing, interactive bootstrap (TTY) for chat
47
+ const chat = await tokenVault.ensure();
48
+ // VaultResolution: apiKey, modelId, providerId, baseURL?, connectionId?, credentialId?
49
+
50
+ tokenVault.useProfile("other");
51
+ const otherChat = await tokenVault.key(CAPABILITY.chat);
52
+
53
+ await tokenVault.setCapabilityModel(
54
+ CAPABILITY.chat,
55
+ "myapp-openai",
56
+ "gpt-4o",
57
+ );
58
+
59
+ const snapshot = await tokenVault.listProfiles();
60
+ // snapshot.profiles, snapshot.connections, snapshot.credentials, snapshot.providers
61
+ ```
62
+
63
+ ## API
64
+
65
+ ### `createTokenVault(options)`
66
+
67
+ **Options** (summary):
68
+
69
+ | Field | Purpose |
70
+ | ----- | ------- |
71
+ | `provider` | e.g. `builtInProviders.openai` |
72
+ | `namespace` | Profile id; connection/credential id becomes `<namespace>-<providerId>` (e.g. `myapp-openai`) |
73
+ | `profileId` + `connectionId` + `credentialId` | Explicit ids instead of `namespace` |
74
+ | `appLabel` | Prefix for stderr messages |
75
+ | `defaultModelByCapability` | Must include the **bootstrap** capability (default `chat`) |
76
+ | `bootstrapCapability` | Capability wired by `ensure()` (default `CAPABILITY.chat`) |
77
+ | `executablePath` | Override binary path |
78
+ | `allowInteractiveBootstrap` | `false` to forbid interactive setup; `true` to force allow even in CI |
79
+ | `logger` | Custom `{ notice, success }` |
80
+
81
+ ### `TokenVault` instance
82
+
83
+ | Method | Behavior |
84
+ | ------ | -------- |
85
+ | `ensure(namespaceOverride?)` | Ensures bootstrap capability is resolvable; runs bootstrap if needed. Optional override uses same id convention for that namespace only. Returns **`VaultResolution`**. |
86
+ | `listProfiles()` | `tokenvault list` as structured data. |
87
+ | `useProfile(profileId)` | Sets active profile for `key()` / `setCapabilityModel`. |
88
+ | `get activeProfileId` | Current active profile id. |
89
+ | `key(capability)` | `resolve <profile> --capability <cap> --with-secret`. |
90
+ | `setCapabilityModel(capability, connectionId, modelId)` | `tokenvault profile select …`. |
91
+
92
+ ### `CAPABILITY`
93
+
94
+ Stable string constants aligned with tokenVault (`chat`, `reasoning`, `embeddings`, `image`, `audio`, `vision`, `tools`). Prefer these over raw strings.
95
+
96
+ ### Lower-level exports
97
+
98
+ - **`builtInProviders`**, **`TokenVaultBootstrapProvider`**
99
+ - **`createVaultCliRunner`**, **`VaultCliRunner`** (testing / custom spawn)
100
+ - **`vaultProcessEnv`**, **`resolveTokenvaultExecutable`**
101
+ - **`parseResolveStdout`**, **`parseVaultListPayload`**
102
+ - Types: **`VaultResolution`**, **`VaultListResult`**, etc.
103
+
104
+ ## Interactive bootstrap and CI
105
+
106
+ `ensure()` may spawn interactive `tokenvault` commands (TTY + stdin). By default interactive bootstrap is **disabled** when **`is-in-ci`** is true or stdin is not a TTY. Set **`allowInteractiveBootstrap: true`** only if you intend to run setup in CI with a fake TTY.
107
+
108
+ ## Publishing (maintainers)
109
+
110
+ From the **tokenVault** repo root:
111
+
112
+ ```bash
113
+ bun run publish:packages # patch bump + bun publish
114
+ bun run publish:packages -- minor
115
+ bun run publish:packages -- --dry-run # no version bump
116
+ ```
117
+
118
+ See `bin/publish-packages.sh` in the parent repository.
119
+
120
+ ## License
121
+
122
+ MIT
@@ -0,0 +1,134 @@
1
+ /** Aligned with tokenVault `src/domain/capability.ts` — keep in sync when adding capabilities. */
2
+ declare const CAPABILITY: {
3
+ readonly chat: "chat";
4
+ readonly reasoning: "reasoning";
5
+ readonly embeddings: "embeddings";
6
+ readonly image: "image";
7
+ readonly audio: "audio";
8
+ readonly vision: "vision";
9
+ readonly tools: "tools";
10
+ };
11
+ type Capability = (typeof CAPABILITY)[keyof typeof CAPABILITY];
12
+ declare function isCapability(s: string): s is Capability;
13
+ declare function assertCapability(s: string): Capability;
14
+
15
+ type VaultResolution = {
16
+ apiKey: string;
17
+ modelId: string;
18
+ providerId: string;
19
+ baseURL?: string;
20
+ connectionId?: string;
21
+ credentialId?: string;
22
+ };
23
+ type ListPayload = {
24
+ providers?: unknown[];
25
+ credentials?: {
26
+ id: string;
27
+ providerId: string;
28
+ }[];
29
+ connections?: {
30
+ id: string;
31
+ providerId: string;
32
+ credentialId: string;
33
+ }[];
34
+ profiles?: {
35
+ id: string;
36
+ attachedConnectionIds?: string[];
37
+ }[];
38
+ };
39
+ type CredentialCopyPick = {
40
+ profileId: string;
41
+ connectionId: string;
42
+ credentialId: string;
43
+ };
44
+ type VaultListResult = {
45
+ providers: ListPayload["providers"];
46
+ credentials: NonNullable<ListPayload["credentials"]>;
47
+ connections: NonNullable<ListPayload["connections"]>;
48
+ profiles: NonNullable<ListPayload["profiles"]>;
49
+ };
50
+ type Logger = {
51
+ notice: (message: string) => void;
52
+ success: (message: string) => void;
53
+ };
54
+ type ValidationContext = {
55
+ profileId: string;
56
+ capability: Capability;
57
+ };
58
+
59
+ type TokenVaultBootstrapProvider = {
60
+ /** tokenVault adapter id (e.g. `openai`) */
61
+ readonly tokenvaultProviderId: string;
62
+ /** After parse, enforce provider / model rules */
63
+ validateResolution(resolution: VaultResolution, ctx: ValidationContext): void;
64
+ /** Connections on other profiles eligible for credential copy during bootstrap */
65
+ listCredentialCopyPicks(payload: ListPayload, excludeProfileId: string): CredentialCopyPick[];
66
+ /** Run `connection refresh-models` after wiring (model-capable providers) */
67
+ readonly refreshModelsAfterBootstrap: boolean;
68
+ };
69
+ declare const builtInProviders: {
70
+ readonly openai: TokenVaultBootstrapProvider;
71
+ };
72
+
73
+ type RunJsonResult = {
74
+ code: number;
75
+ stdout: string;
76
+ stderr: string;
77
+ };
78
+ type VaultCliRunner = {
79
+ runJson: (args: string[]) => Promise<RunJsonResult>;
80
+ runInherit: (args: string[]) => Promise<number>;
81
+ };
82
+ declare function createVaultCliRunner(options: {
83
+ executablePath?: string;
84
+ env?: () => NodeJS.ProcessEnv;
85
+ }): VaultCliRunner;
86
+
87
+ type CreateTokenVaultOptions = {
88
+ provider: TokenVaultBootstrapProvider;
89
+ appLabel: string;
90
+ /** Default model per capability; must include entry for `bootstrapCapability` */
91
+ defaultModelByCapability: Partial<Record<Capability, string>>;
92
+ /** Capability wired by `ensure()` (default: chat) */
93
+ bootstrapCapability?: Capability;
94
+ executablePath?: string;
95
+ allowInteractiveBootstrap?: boolean;
96
+ logger?: Logger;
97
+ /** @internal Inject for tests */
98
+ runner?: VaultCliRunner;
99
+ } & ({
100
+ namespace: string;
101
+ } | {
102
+ profileId: string;
103
+ connectionId: string;
104
+ credentialId: string;
105
+ });
106
+ type TokenVault = {
107
+ /** Bootstrap `bootstrapCapability` for the given profile triple; optional one-off namespace convention. */
108
+ ensure: (namespaceOverride?: string) => Promise<VaultResolution>;
109
+ listProfiles: () => Promise<VaultListResult>;
110
+ /** Profile used by `key()` and `setCapabilityModel` (default: bootstrap profile). */
111
+ useProfile: (profileId: string) => void;
112
+ get activeProfileId(): string;
113
+ key: (capability: Capability | string) => Promise<VaultResolution>;
114
+ setCapabilityModel: (capability: Capability | string, connectionId: string, modelId: string) => Promise<void>;
115
+ };
116
+ declare function createTokenVault(options: CreateTokenVaultOptions): TokenVault;
117
+
118
+ /**
119
+ * Prefer the OS secure store (Keychain / Secret Service / DPAPI) so tokenVault does not create a
120
+ * passphrase-backed vault. Ignored if the user already has `vault/passphrase-envelope.json` or
121
+ * sets TOKENVAULT_SECURE_STORE themselves.
122
+ */
123
+ declare function vaultProcessEnv(): NodeJS.ProcessEnv;
124
+
125
+ /**
126
+ * Resolve `tokenvault` on PATH (Windows respects PATHEXT).
127
+ * @throws if not found and no explicit path
128
+ */
129
+ declare function resolveTokenvaultExecutable(explicit?: string): string;
130
+
131
+ declare function parseVaultListPayload(stdout: string): ListPayload | null;
132
+ declare function parseResolveStdout(stdout: string, provider: TokenVaultBootstrapProvider, ctx: ValidationContext): VaultResolution;
133
+
134
+ export { CAPABILITY, type Capability, type CreateTokenVaultOptions, type CredentialCopyPick, type ListPayload, type Logger, type TokenVault, type TokenVaultBootstrapProvider, type ValidationContext, type VaultCliRunner, type VaultListResult, type VaultResolution, assertCapability, builtInProviders, createTokenVault, createVaultCliRunner, isCapability, parseResolveStdout, parseVaultListPayload, resolveTokenvaultExecutable, vaultProcessEnv };
package/dist/index.js ADDED
@@ -0,0 +1,648 @@
1
+ // src/capability.ts
2
+ var CAPABILITY = {
3
+ chat: "chat",
4
+ reasoning: "reasoning",
5
+ embeddings: "embeddings",
6
+ image: "image",
7
+ audio: "audio",
8
+ vision: "vision",
9
+ tools: "tools"
10
+ };
11
+ var CAP_VALUES = Object.values(CAPABILITY);
12
+ function isCapability(s) {
13
+ return CAP_VALUES.includes(s);
14
+ }
15
+ function assertCapability(s) {
16
+ if (!isCapability(s)) {
17
+ throw new Error(
18
+ `Unknown capability "${s}". Expected one of: ${CAP_VALUES.join(", ")}`
19
+ );
20
+ }
21
+ return s;
22
+ }
23
+
24
+ // src/bootstrap.ts
25
+ import * as readline from "readline";
26
+ import isInCi from "is-in-ci";
27
+
28
+ // src/parse.ts
29
+ function parseVaultListPayload(stdout) {
30
+ try {
31
+ return JSON.parse(stdout);
32
+ } catch {
33
+ return null;
34
+ }
35
+ }
36
+ function parseResolveStdout(stdout, provider, ctx) {
37
+ let data;
38
+ try {
39
+ data = JSON.parse(stdout);
40
+ } catch {
41
+ throw new Error(
42
+ "Could not parse JSON from `tokenvault resolve` (unexpected output)."
43
+ );
44
+ }
45
+ const resolution = data.resolution;
46
+ if (!resolution || typeof resolution !== "object") {
47
+ throw new Error(
48
+ "`tokenvault resolve` JSON did not include a resolution object."
49
+ );
50
+ }
51
+ const apiKey = typeof resolution.apiKey === "string" ? resolution.apiKey.trim() : "";
52
+ const modelId = typeof resolution.modelId === "string" ? resolution.modelId.trim() : "";
53
+ const providerId = typeof resolution.providerId === "string" ? resolution.providerId.trim() : "";
54
+ const apiBaseUrl = typeof resolution.apiBaseUrl === "string" && resolution.apiBaseUrl.trim() ? resolution.apiBaseUrl.trim() : void 0;
55
+ const connectionId = typeof resolution.connectionId === "string" ? resolution.connectionId.trim() : void 0;
56
+ const credentialId = typeof resolution.credentialId === "string" ? resolution.credentialId.trim() : void 0;
57
+ if (!apiKey) {
58
+ throw new Error(
59
+ "`tokenvault resolve` did not return an apiKey. Use a tokenVault build that supports `tokenvault resolve --with-secret` (see tokenVault README)."
60
+ );
61
+ }
62
+ const out = {
63
+ apiKey,
64
+ modelId,
65
+ providerId,
66
+ baseURL: apiBaseUrl,
67
+ connectionId,
68
+ credentialId
69
+ };
70
+ provider.validateResolution(out, ctx);
71
+ return out;
72
+ }
73
+
74
+ // src/bootstrap.ts
75
+ function promptLine(question) {
76
+ const rl = readline.createInterface({
77
+ input: process.stdin,
78
+ output: process.stderr
79
+ });
80
+ return new Promise((resolve) => {
81
+ rl.question(question, (answer) => {
82
+ rl.close();
83
+ resolve(answer.trim());
84
+ });
85
+ });
86
+ }
87
+ async function addCredentialInteractive(ctx, runner) {
88
+ const { provider, ids, logger } = ctx;
89
+ const listR = await runner.runJson(["list"]);
90
+ const payload = listR.code === 0 ? parseVaultListPayload(listR.stdout) : null;
91
+ const picks = payload ? provider.listCredentialCopyPicks(payload, ids.profileId) : [];
92
+ if (picks.length === 0) {
93
+ logger.notice(
94
+ `Adding API key to tokenVault for provider "${provider.tokenvaultProviderId}" (hidden input). Follow the tokenVault prompts if any appear.
95
+ `
96
+ );
97
+ } else {
98
+ console.error("");
99
+ logger.notice(
100
+ `API key for tokenVault credential "${ids.credentialId}" (${provider.tokenvaultProviderId}):`
101
+ );
102
+ logger.notice(
103
+ " 1) Enter a new API key (hidden input via tokenvault)"
104
+ );
105
+ logger.notice(
106
+ " 2) Copy from another profile \u2192 connection \u2192 credential (reuse a stored key)"
107
+ );
108
+ console.error("");
109
+ const raw = await promptLine("Choose 1 or 2 [1]: ");
110
+ const mode = raw === "" ? "1" : raw;
111
+ if (mode === "2") {
112
+ console.error("");
113
+ for (let i = 0; i < picks.length; i++) {
114
+ const x = picks[i];
115
+ logger.notice(
116
+ ` ${i + 1}) profile "${x.profileId}" \u2192 connection "${x.connectionId}" \u2192 credential "${x.credentialId}"`
117
+ );
118
+ }
119
+ console.error("");
120
+ const numRaw = await promptLine(
121
+ `Enter 1\u2013${picks.length} (or blank to enter a new key instead): `
122
+ );
123
+ if (numRaw !== "") {
124
+ const n = Number.parseInt(numRaw, 10);
125
+ if (Number.isFinite(n) && n >= 1 && n <= picks.length) {
126
+ const credId = picks[n - 1].credentialId;
127
+ const copyR = await runner.runJson([
128
+ "credential",
129
+ "copy",
130
+ credId,
131
+ ids.credentialId
132
+ ]);
133
+ if (copyR.code === 0) {
134
+ console.error("");
135
+ return;
136
+ }
137
+ throw new Error(
138
+ copyR.stderr || copyR.stdout || `tokenvault credential copy failed (exit ${copyR.code})`
139
+ );
140
+ }
141
+ }
142
+ logger.notice("\nUsing new API key entry.\n");
143
+ }
144
+ logger.notice("Follow the tokenVault prompts (hidden API key).\n");
145
+ }
146
+ const code = await runner.runInherit([
147
+ "credential",
148
+ "add",
149
+ provider.tokenvaultProviderId,
150
+ ids.credentialId
151
+ ]);
152
+ if (code !== 0) {
153
+ throw new Error(`tokenvault credential add failed (exit ${code})`);
154
+ }
155
+ }
156
+ async function profileExists(runner, profileId) {
157
+ const r = await runner.runJson(["list"]);
158
+ if (r.code !== 0) return false;
159
+ let payload;
160
+ try {
161
+ payload = JSON.parse(r.stdout);
162
+ } catch {
163
+ return false;
164
+ }
165
+ return Boolean(payload.profiles?.some((p) => p.id === profileId));
166
+ }
167
+ async function credentialExists(runner, credentialId) {
168
+ const r = await runner.runJson(["credential", "inspect", credentialId]);
169
+ return r.code === 0;
170
+ }
171
+ async function connectionExists(runner, connectionId) {
172
+ const r = await runner.runJson(["connection", "inspect", connectionId]);
173
+ return r.code === 0;
174
+ }
175
+ async function tryResolve(runner, provider, profileId, capability) {
176
+ const r = await runner.runJson([
177
+ "resolve",
178
+ profileId,
179
+ "--capability",
180
+ capability,
181
+ "--with-secret"
182
+ ]);
183
+ if (r.code !== 0) return null;
184
+ return parseResolveStdout(r.stdout, provider, { profileId, capability });
185
+ }
186
+ async function bootstrapVaultProfile(ctx, runner) {
187
+ const { provider, ids, bootstrapCapability, defaultModelId, logger, appLabel } = ctx;
188
+ if (!ctx.allowInteractive) {
189
+ throw new Error(
190
+ `tokenVault profile "${ids.profileId}" is not usable in this environment. Configure it interactively on a TTY, or run the tokenvault commands from the tokenVault README for profile "${ids.profileId}".`
191
+ );
192
+ }
193
+ console.error("");
194
+ logger.notice(
195
+ `${appLabel}: tokenVault profile "${ids.profileId}" is missing or incomplete. Setting up credential "${ids.credentialId}" and wiring the profile.`
196
+ );
197
+ console.error("");
198
+ if (!await profileExists(runner, ids.profileId)) {
199
+ const r = await runner.runJson(["profile", "create", ids.profileId]);
200
+ if (r.code !== 0) {
201
+ throw new Error(
202
+ r.stderr || r.stdout || `tokenvault profile create failed (exit ${r.code})`
203
+ );
204
+ }
205
+ }
206
+ if (!await credentialExists(runner, ids.credentialId)) {
207
+ await addCredentialInteractive(ctx, runner);
208
+ }
209
+ if (!await connectionExists(runner, ids.connectionId)) {
210
+ const r = await runner.runJson([
211
+ "connection",
212
+ "add",
213
+ provider.tokenvaultProviderId,
214
+ ids.connectionId,
215
+ "--credential",
216
+ ids.credentialId
217
+ ]);
218
+ if (r.code !== 0) {
219
+ throw new Error(
220
+ r.stderr || r.stdout || `tokenvault connection add failed (exit ${r.code})`
221
+ );
222
+ }
223
+ }
224
+ {
225
+ const r = await runner.runJson([
226
+ "profile",
227
+ "attach",
228
+ ids.profileId,
229
+ ids.connectionId
230
+ ]);
231
+ if (r.code !== 0) {
232
+ throw new Error(
233
+ r.stderr || r.stdout || `tokenvault profile attach failed (exit ${r.code})`
234
+ );
235
+ }
236
+ }
237
+ if (provider.refreshModelsAfterBootstrap) {
238
+ logger.notice("Refreshing model cache in tokenVault\u2026\n");
239
+ const code = await runner.runInherit([
240
+ "connection",
241
+ "refresh-models",
242
+ ids.connectionId
243
+ ]);
244
+ if (code !== 0) {
245
+ throw new Error(
246
+ `tokenvault connection refresh-models failed (exit ${code})`
247
+ );
248
+ }
249
+ }
250
+ {
251
+ const r = await runner.runJson([
252
+ "profile",
253
+ "select",
254
+ ids.profileId,
255
+ bootstrapCapability,
256
+ ids.connectionId,
257
+ defaultModelId
258
+ ]);
259
+ if (r.code !== 0) {
260
+ throw new Error(
261
+ r.stderr || r.stdout || `tokenvault profile select failed (exit ${r.code}). Try: tokenvault connection refresh-models ${ids.connectionId}`
262
+ );
263
+ }
264
+ }
265
+ console.error("");
266
+ logger.success(
267
+ `${appLabel}: tokenVault profile "${ids.profileId}" is ready.
268
+ `
269
+ );
270
+ }
271
+ function interactiveSetupAllowed(allowInteractiveBootstrap) {
272
+ if (allowInteractiveBootstrap === false) return false;
273
+ if (allowInteractiveBootstrap === true) return true;
274
+ return Boolean(process.stdin.isTTY) && !isInCi;
275
+ }
276
+ async function ensureBootstrapCapability(runner, ctx) {
277
+ const { provider, ids, bootstrapCapability } = ctx;
278
+ let cfg = await tryResolve(
279
+ runner,
280
+ provider,
281
+ ids.profileId,
282
+ bootstrapCapability
283
+ );
284
+ if (!cfg && await connectionExists(runner, ids.connectionId) && provider.refreshModelsAfterBootstrap) {
285
+ const code = await runner.runInherit([
286
+ "connection",
287
+ "refresh-models",
288
+ ids.connectionId
289
+ ]);
290
+ if (code === 0) {
291
+ cfg = await tryResolve(
292
+ runner,
293
+ provider,
294
+ ids.profileId,
295
+ bootstrapCapability
296
+ );
297
+ }
298
+ }
299
+ if (!cfg) {
300
+ await bootstrapVaultProfile(ctx, runner);
301
+ cfg = await tryResolve(
302
+ runner,
303
+ provider,
304
+ ids.profileId,
305
+ bootstrapCapability
306
+ );
307
+ }
308
+ if (!cfg) {
309
+ throw new Error(
310
+ `Could not resolve tokenVault profile "${ids.profileId}" for capability "${bootstrapCapability}" after setup. See: tokenvault resolve ${ids.profileId} --capability ${bootstrapCapability} --json`
311
+ );
312
+ }
313
+ return cfg;
314
+ }
315
+ async function resolveWithSecret(runner, provider, profileId, capability) {
316
+ const r = await runner.runJson([
317
+ "resolve",
318
+ profileId,
319
+ "--capability",
320
+ capability,
321
+ "--with-secret"
322
+ ]);
323
+ if (r.code !== 0) {
324
+ throw new Error(
325
+ r.stderr || r.stdout || `tokenvault resolve failed (exit ${r.code}) for profile "${profileId}" capability "${capability}"`
326
+ );
327
+ }
328
+ return parseResolveStdout(r.stdout, provider, { profileId, capability });
329
+ }
330
+ async function listVaultSnapshot(runner) {
331
+ const r = await runner.runJson(["list"]);
332
+ if (r.code !== 0) {
333
+ throw new Error(
334
+ r.stderr || r.stdout || `tokenvault list failed (exit ${r.code})`
335
+ );
336
+ }
337
+ const payload = parseVaultListPayload(r.stdout);
338
+ if (!payload) {
339
+ throw new Error("Could not parse JSON from `tokenvault list`.");
340
+ }
341
+ return {
342
+ providers: payload.providers,
343
+ credentials: payload.credentials ?? [],
344
+ connections: payload.connections ?? [],
345
+ profiles: payload.profiles ?? []
346
+ };
347
+ }
348
+ async function selectCapabilityModel(runner, params) {
349
+ const r = await runner.runJson([
350
+ "profile",
351
+ "select",
352
+ params.profileId,
353
+ params.capability,
354
+ params.connectionId,
355
+ params.modelId
356
+ ]);
357
+ if (r.code !== 0) {
358
+ throw new Error(
359
+ r.stderr || r.stdout || `tokenvault profile select failed (exit ${r.code})`
360
+ );
361
+ }
362
+ }
363
+
364
+ // src/executable.ts
365
+ import fs from "fs";
366
+ import path from "path";
367
+ function resolveTokenvaultExecutable(explicit) {
368
+ const trimmed = explicit?.trim();
369
+ if (trimmed) return trimmed;
370
+ const fromEnv = process.env.TOKENVAULT_BIN?.trim();
371
+ if (fromEnv) return fromEnv;
372
+ const found = whichOnPath("tokenvault");
373
+ if (!found) {
374
+ throw new Error(
375
+ "tokenVault is not available: `tokenvault` was not found on PATH. Install tokenVault and link the CLI, or set TOKENVAULT_BIN to the tokenvault executable."
376
+ );
377
+ }
378
+ return found;
379
+ }
380
+ function whichOnPath(cmd) {
381
+ const isWin = process.platform === "win32";
382
+ const paths = process.env.PATH?.split(path.delimiter) ?? [];
383
+ const exts = isWin ? process.env.PATHEXT?.split(path.delimiter) ?? [".EXE", ".CMD", ".BAT", ""] : [""];
384
+ for (const dir of paths) {
385
+ for (const ext of exts) {
386
+ const candidate = path.join(dir, cmd + ext);
387
+ try {
388
+ const st = fs.statSync(candidate);
389
+ if (!st.isFile()) continue;
390
+ if (!isWin) {
391
+ try {
392
+ fs.accessSync(candidate, fs.constants.X_OK);
393
+ } catch {
394
+ continue;
395
+ }
396
+ }
397
+ return candidate;
398
+ } catch {
399
+ }
400
+ }
401
+ }
402
+ return null;
403
+ }
404
+
405
+ // src/logger.ts
406
+ function stderrColorEnabled() {
407
+ if (process.env.NO_COLOR) return false;
408
+ if (process.env.TERM === "dumb") return false;
409
+ return Boolean(process.stderr.isTTY);
410
+ }
411
+ var ANSI_YELLOW = "\x1B[33m";
412
+ var ANSI_GREEN = "\x1B[32m";
413
+ var ANSI_RESET = "\x1B[0m";
414
+ function createDefaultLogger() {
415
+ return {
416
+ notice(message) {
417
+ if (stderrColorEnabled())
418
+ console.error(`${ANSI_YELLOW}${message}${ANSI_RESET}`);
419
+ else console.error(message);
420
+ },
421
+ success(message) {
422
+ if (stderrColorEnabled())
423
+ console.error(`${ANSI_GREEN}${message}${ANSI_RESET}`);
424
+ else console.error(message);
425
+ }
426
+ };
427
+ }
428
+
429
+ // src/runner.ts
430
+ import { spawn } from "child_process";
431
+
432
+ // src/env.ts
433
+ function vaultProcessEnv() {
434
+ const env = { ...process.env };
435
+ if (env.TOKENVAULT_SECURE_STORE?.trim()) return env;
436
+ switch (process.platform) {
437
+ case "darwin":
438
+ env.TOKENVAULT_SECURE_STORE = "macos-keychain";
439
+ break;
440
+ case "win32":
441
+ env.TOKENVAULT_SECURE_STORE = "windows";
442
+ break;
443
+ case "linux":
444
+ env.TOKENVAULT_SECURE_STORE = "linux-secret-service";
445
+ break;
446
+ default:
447
+ break;
448
+ }
449
+ return env;
450
+ }
451
+
452
+ // src/runner.ts
453
+ function createVaultCliRunner(options) {
454
+ const envFactory = options.env ?? vaultProcessEnv;
455
+ function executable() {
456
+ return resolveTokenvaultExecutable(options.executablePath);
457
+ }
458
+ return {
459
+ async runJson(args) {
460
+ const exe = executable();
461
+ const env = envFactory();
462
+ const stdinMode = process.stdin.isTTY ? "inherit" : "ignore";
463
+ return await spawnCapture([exe, "--json", ...args], env, stdinMode);
464
+ },
465
+ async runInherit(args) {
466
+ const exe = executable();
467
+ const env = envFactory();
468
+ return await spawnInheritAll([exe, ...args], env);
469
+ }
470
+ };
471
+ }
472
+ function spawnCapture(argv, env, stdinMode) {
473
+ const [executablePath, ...args] = argv;
474
+ return new Promise((resolve, reject) => {
475
+ const child = spawn(executablePath, args, {
476
+ env,
477
+ stdio: [stdinMode, "pipe", "pipe"]
478
+ });
479
+ let stdout = "";
480
+ let stderr = "";
481
+ child.stdout?.setEncoding("utf8");
482
+ child.stderr?.setEncoding("utf8");
483
+ child.stdout?.on("data", (c) => {
484
+ stdout += c;
485
+ });
486
+ child.stderr?.on("data", (c) => {
487
+ stderr += c;
488
+ });
489
+ child.on("error", reject);
490
+ child.on("close", (code) => {
491
+ resolve({
492
+ code: code ?? 1,
493
+ stdout: stdout.trimEnd(),
494
+ stderr: stderr.trimEnd()
495
+ });
496
+ });
497
+ });
498
+ }
499
+ function spawnInheritAll(argv, env) {
500
+ const [executablePath, ...args] = argv;
501
+ return new Promise((resolve, reject) => {
502
+ const child = spawn(executablePath, args, { env, stdio: "inherit" });
503
+ child.on("error", reject);
504
+ child.on("close", (code) => resolve(code ?? 1));
505
+ });
506
+ }
507
+
508
+ // src/facade.ts
509
+ function idsFromNamespace(ns, provider) {
510
+ const artifact = `${ns}-${provider.tokenvaultProviderId}`;
511
+ return { profileId: ns, connectionId: artifact, credentialId: artifact };
512
+ }
513
+ function resolveBootstrapIds(options) {
514
+ if ("namespace" in options) {
515
+ return idsFromNamespace(options.namespace, options.provider);
516
+ }
517
+ return {
518
+ profileId: options.profileId,
519
+ connectionId: options.connectionId,
520
+ credentialId: options.credentialId
521
+ };
522
+ }
523
+ function createTokenVault(options) {
524
+ const provider = options.provider;
525
+ const bootstrapCapability = options.bootstrapCapability ?? CAPABILITY.chat;
526
+ const defaultModelRaw = options.defaultModelByCapability[bootstrapCapability]?.trim();
527
+ if (!defaultModelRaw) {
528
+ throw new Error(
529
+ `createTokenVault: defaultModelByCapability must include a default model for bootstrap capability "${bootstrapCapability}"`
530
+ );
531
+ }
532
+ const defaultModelId = defaultModelRaw;
533
+ if (!options.runner) {
534
+ resolveTokenvaultExecutable(options.executablePath);
535
+ }
536
+ const runner = options.runner ?? createVaultCliRunner({ executablePath: options.executablePath });
537
+ const bootstrapIds = resolveBootstrapIds(options);
538
+ let resolveProfileId = bootstrapIds.profileId;
539
+ const logger = options.logger ?? createDefaultLogger();
540
+ const allowInteractive = interactiveSetupAllowed(
541
+ options.allowInteractiveBootstrap
542
+ );
543
+ function buildContext(ids) {
544
+ return {
545
+ provider,
546
+ ids,
547
+ bootstrapCapability,
548
+ defaultModelId,
549
+ appLabel: options.appLabel,
550
+ logger,
551
+ allowInteractive
552
+ };
553
+ }
554
+ return {
555
+ async ensure(namespaceOverride) {
556
+ const trimmed = namespaceOverride?.trim();
557
+ const ids = trimmed ? idsFromNamespace(trimmed, provider) : bootstrapIds;
558
+ return await ensureBootstrapCapability(
559
+ runner,
560
+ buildContext(ids)
561
+ );
562
+ },
563
+ async listProfiles() {
564
+ return await listVaultSnapshot(runner);
565
+ },
566
+ useProfile(profileId) {
567
+ resolveProfileId = profileId;
568
+ },
569
+ get activeProfileId() {
570
+ return resolveProfileId;
571
+ },
572
+ async key(capability) {
573
+ const cap = typeof capability === "string" ? assertCapability(capability) : capability;
574
+ return await resolveWithSecret(
575
+ runner,
576
+ provider,
577
+ resolveProfileId,
578
+ cap
579
+ );
580
+ },
581
+ async setCapabilityModel(capability, connectionId, modelId) {
582
+ const cap = typeof capability === "string" ? assertCapability(capability) : capability;
583
+ await selectCapabilityModel(runner, {
584
+ profileId: resolveProfileId,
585
+ capability: cap,
586
+ connectionId,
587
+ modelId
588
+ });
589
+ }
590
+ };
591
+ }
592
+
593
+ // src/provider.ts
594
+ function openAiCopyPicks(payload, excludeProfileId) {
595
+ const profiles = payload.profiles ?? [];
596
+ const connections = payload.connections ?? [];
597
+ const byConnId = new Map(connections.map((c) => [c.id, c]));
598
+ const seenCred = /* @__PURE__ */ new Set();
599
+ const out = [];
600
+ for (const p of profiles) {
601
+ if (p.id === excludeProfileId) continue;
602
+ for (const connId of p.attachedConnectionIds ?? []) {
603
+ const c = byConnId.get(connId);
604
+ if (!c || c.providerId !== "openai") continue;
605
+ if (seenCred.has(c.credentialId)) continue;
606
+ seenCred.add(c.credentialId);
607
+ out.push({
608
+ profileId: p.id,
609
+ connectionId: c.id,
610
+ credentialId: c.credentialId
611
+ });
612
+ }
613
+ }
614
+ return out;
615
+ }
616
+ var openAiProvider = {
617
+ tokenvaultProviderId: "openai",
618
+ refreshModelsAfterBootstrap: true,
619
+ listCredentialCopyPicks: openAiCopyPicks,
620
+ validateResolution(resolution, ctx) {
621
+ if (resolution.providerId !== "openai") {
622
+ throw new Error(
623
+ `tokenVault profile "${ctx.profileId}" must select an OpenAI connection for capability "${ctx.capability}" (got provider "${resolution.providerId}").`
624
+ );
625
+ }
626
+ if (!resolution.modelId) {
627
+ throw new Error(
628
+ `tokenVault profile "${ctx.profileId}" has no model selected for capability "${ctx.capability}". Run: tokenvault profile select ${ctx.profileId} ${ctx.capability} <connection> <model>`
629
+ );
630
+ }
631
+ }
632
+ };
633
+ var builtInProviders = {
634
+ openai: openAiProvider
635
+ };
636
+ export {
637
+ CAPABILITY,
638
+ assertCapability,
639
+ builtInProviders,
640
+ createTokenVault,
641
+ createVaultCliRunner,
642
+ isCapability,
643
+ parseResolveStdout,
644
+ parseVaultListPayload,
645
+ resolveTokenvaultExecutable,
646
+ vaultProcessEnv
647
+ };
648
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/capability.ts","../src/bootstrap.ts","../src/parse.ts","../src/executable.ts","../src/logger.ts","../src/runner.ts","../src/env.ts","../src/facade.ts","../src/provider.ts"],"sourcesContent":["/** Aligned with tokenVault `src/domain/capability.ts` — keep in sync when adding capabilities. */\nexport const CAPABILITY = {\n chat: \"chat\",\n reasoning: \"reasoning\",\n embeddings: \"embeddings\",\n image: \"image\",\n audio: \"audio\",\n vision: \"vision\",\n tools: \"tools\",\n} as const;\n\nexport type Capability = (typeof CAPABILITY)[keyof typeof CAPABILITY];\n\nconst CAP_VALUES: readonly string[] = Object.values(CAPABILITY);\n\nexport function isCapability(s: string): s is Capability {\n return CAP_VALUES.includes(s);\n}\n\nexport function assertCapability(s: string): Capability {\n if (!isCapability(s)) {\n throw new Error(\n `Unknown capability \"${s}\". Expected one of: ${CAP_VALUES.join(\", \")}`,\n );\n }\n return s;\n}\n","import * as readline from \"node:readline\";\nimport isInCi from \"is-in-ci\";\nimport type { Capability } from \"./capability.ts\";\nimport { parseResolveStdout, parseVaultListPayload } from \"./parse.ts\";\nimport type { TokenVaultBootstrapProvider } from \"./provider.ts\";\nimport type { VaultCliRunner } from \"./runner.ts\";\nimport type {\n ListPayload,\n Logger,\n VaultListResult,\n VaultResolution,\n} from \"./types.ts\";\n\nexport type BootstrapIds = {\n profileId: string;\n connectionId: string;\n credentialId: string;\n};\n\nexport type BootstrapContext = {\n provider: TokenVaultBootstrapProvider;\n ids: BootstrapIds;\n bootstrapCapability: Capability;\n defaultModelId: string;\n appLabel: string;\n logger: Logger;\n allowInteractive: boolean;\n};\n\nfunction promptLine(question: string): Promise<string> {\n const rl = readline.createInterface({\n input: process.stdin,\n output: process.stderr,\n });\n return new Promise((resolve) => {\n rl.question(question, (answer) => {\n rl.close();\n resolve(answer.trim());\n });\n });\n}\n\nasync function addCredentialInteractive(\n ctx: BootstrapContext,\n runner: VaultCliRunner,\n): Promise<void> {\n const { provider, ids, logger } = ctx;\n const listR = await runner.runJson([\"list\"]);\n const payload =\n listR.code === 0 ? parseVaultListPayload(listR.stdout) : null;\n const picks = payload\n ? provider.listCredentialCopyPicks(payload, ids.profileId)\n : [];\n\n if (picks.length === 0) {\n logger.notice(\n `Adding API key to tokenVault for provider \"${provider.tokenvaultProviderId}\" (hidden input). Follow the tokenVault prompts if any appear.\\n`,\n );\n } else {\n console.error(\"\");\n logger.notice(\n `API key for tokenVault credential \"${ids.credentialId}\" (${provider.tokenvaultProviderId}):`,\n );\n logger.notice(\n \" 1) Enter a new API key (hidden input via tokenvault)\",\n );\n logger.notice(\n \" 2) Copy from another profile → connection → credential (reuse a stored key)\",\n );\n console.error(\"\");\n const raw = await promptLine(\"Choose 1 or 2 [1]: \");\n const mode = raw === \"\" ? \"1\" : raw;\n\n if (mode === \"2\") {\n console.error(\"\");\n for (let i = 0; i < picks.length; i++) {\n const x = picks[i]!;\n logger.notice(\n ` ${i + 1}) profile \"${x.profileId}\" → connection \"${x.connectionId}\" → credential \"${x.credentialId}\"`,\n );\n }\n console.error(\"\");\n const numRaw = await promptLine(\n `Enter 1–${picks.length} (or blank to enter a new key instead): `,\n );\n if (numRaw !== \"\") {\n const n = Number.parseInt(numRaw, 10);\n if (Number.isFinite(n) && n >= 1 && n <= picks.length) {\n const credId = picks[n - 1]!.credentialId;\n const copyR = await runner.runJson([\n \"credential\",\n \"copy\",\n credId,\n ids.credentialId,\n ]);\n if (copyR.code === 0) {\n console.error(\"\");\n return;\n }\n throw new Error(\n copyR.stderr ||\n copyR.stdout ||\n `tokenvault credential copy failed (exit ${copyR.code})`,\n );\n }\n }\n logger.notice(\"\\nUsing new API key entry.\\n\");\n }\n\n logger.notice(\"Follow the tokenVault prompts (hidden API key).\\n\");\n }\n\n const code = await runner.runInherit([\n \"credential\",\n \"add\",\n provider.tokenvaultProviderId,\n ids.credentialId,\n ]);\n if (code !== 0) {\n throw new Error(`tokenvault credential add failed (exit ${code})`);\n }\n}\n\nasync function profileExists(\n runner: VaultCliRunner,\n profileId: string,\n): Promise<boolean> {\n const r = await runner.runJson([\"list\"]);\n if (r.code !== 0) return false;\n let payload: ListPayload;\n try {\n payload = JSON.parse(r.stdout) as ListPayload;\n } catch {\n return false;\n }\n return Boolean(payload.profiles?.some((p) => p.id === profileId));\n}\n\nasync function credentialExists(\n runner: VaultCliRunner,\n credentialId: string,\n): Promise<boolean> {\n const r = await runner.runJson([\"credential\", \"inspect\", credentialId]);\n return r.code === 0;\n}\n\nasync function connectionExists(\n runner: VaultCliRunner,\n connectionId: string,\n): Promise<boolean> {\n const r = await runner.runJson([\"connection\", \"inspect\", connectionId]);\n return r.code === 0;\n}\n\nasync function tryResolve(\n runner: VaultCliRunner,\n provider: TokenVaultBootstrapProvider,\n profileId: string,\n capability: Capability,\n): Promise<VaultResolution | null> {\n const r = await runner.runJson([\n \"resolve\",\n profileId,\n \"--capability\",\n capability,\n \"--with-secret\",\n ]);\n if (r.code !== 0) return null;\n return parseResolveStdout(r.stdout, provider, { profileId, capability });\n}\n\nasync function bootstrapVaultProfile(\n ctx: BootstrapContext,\n runner: VaultCliRunner,\n): Promise<void> {\n const { provider, ids, bootstrapCapability, defaultModelId, logger, appLabel } =\n ctx;\n\n if (!ctx.allowInteractive) {\n throw new Error(\n `tokenVault profile \"${ids.profileId}\" is not usable in this environment. Configure it interactively on a TTY, or run the tokenvault commands from the tokenVault README for profile \"${ids.profileId}\".`,\n );\n }\n\n console.error(\"\");\n logger.notice(\n `${appLabel}: tokenVault profile \"${ids.profileId}\" is missing or incomplete. Setting up credential \"${ids.credentialId}\" and wiring the profile.`,\n );\n console.error(\"\");\n\n if (!(await profileExists(runner, ids.profileId))) {\n const r = await runner.runJson([\"profile\", \"create\", ids.profileId]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr || r.stdout || `tokenvault profile create failed (exit ${r.code})`,\n );\n }\n }\n\n if (!(await credentialExists(runner, ids.credentialId))) {\n await addCredentialInteractive(ctx, runner);\n }\n\n if (!(await connectionExists(runner, ids.connectionId))) {\n const r = await runner.runJson([\n \"connection\",\n \"add\",\n provider.tokenvaultProviderId,\n ids.connectionId,\n \"--credential\",\n ids.credentialId,\n ]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr ||\n r.stdout ||\n `tokenvault connection add failed (exit ${r.code})`,\n );\n }\n }\n\n {\n const r = await runner.runJson([\n \"profile\",\n \"attach\",\n ids.profileId,\n ids.connectionId,\n ]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr ||\n r.stdout ||\n `tokenvault profile attach failed (exit ${r.code})`,\n );\n }\n }\n\n if (provider.refreshModelsAfterBootstrap) {\n logger.notice(\"Refreshing model cache in tokenVault…\\n\");\n const code = await runner.runInherit([\n \"connection\",\n \"refresh-models\",\n ids.connectionId,\n ]);\n if (code !== 0) {\n throw new Error(\n `tokenvault connection refresh-models failed (exit ${code})`,\n );\n }\n }\n\n {\n const r = await runner.runJson([\n \"profile\",\n \"select\",\n ids.profileId,\n bootstrapCapability,\n ids.connectionId,\n defaultModelId,\n ]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr ||\n r.stdout ||\n `tokenvault profile select failed (exit ${r.code}). Try: tokenvault connection refresh-models ${ids.connectionId}`,\n );\n }\n }\n\n console.error(\"\");\n logger.success(\n `${appLabel}: tokenVault profile \"${ids.profileId}\" is ready.\\n`,\n );\n}\n\nexport function interactiveSetupAllowed(\n allowInteractiveBootstrap?: boolean,\n): boolean {\n if (allowInteractiveBootstrap === false) return false;\n if (allowInteractiveBootstrap === true) return true;\n return Boolean(process.stdin.isTTY) && !isInCi;\n}\n\nexport async function ensureBootstrapCapability(\n runner: VaultCliRunner,\n ctx: BootstrapContext,\n): Promise<VaultResolution> {\n const { provider, ids, bootstrapCapability } = ctx;\n\n let cfg = await tryResolve(\n runner,\n provider,\n ids.profileId,\n bootstrapCapability,\n );\n if (\n !cfg &&\n (await connectionExists(runner, ids.connectionId)) &&\n provider.refreshModelsAfterBootstrap\n ) {\n const code = await runner.runInherit([\n \"connection\",\n \"refresh-models\",\n ids.connectionId,\n ]);\n if (code === 0) {\n cfg = await tryResolve(\n runner,\n provider,\n ids.profileId,\n bootstrapCapability,\n );\n }\n }\n\n if (!cfg) {\n await bootstrapVaultProfile(ctx, runner);\n cfg = await tryResolve(\n runner,\n provider,\n ids.profileId,\n bootstrapCapability,\n );\n }\n\n if (!cfg) {\n throw new Error(\n `Could not resolve tokenVault profile \"${ids.profileId}\" for capability \"${bootstrapCapability}\" after setup. See: tokenvault resolve ${ids.profileId} --capability ${bootstrapCapability} --json`,\n );\n }\n\n return cfg;\n}\n\nexport async function resolveWithSecret(\n runner: VaultCliRunner,\n provider: TokenVaultBootstrapProvider,\n profileId: string,\n capability: Capability,\n): Promise<VaultResolution> {\n const r = await runner.runJson([\n \"resolve\",\n profileId,\n \"--capability\",\n capability,\n \"--with-secret\",\n ]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr ||\n r.stdout ||\n `tokenvault resolve failed (exit ${r.code}) for profile \"${profileId}\" capability \"${capability}\"`,\n );\n }\n return parseResolveStdout(r.stdout, provider, { profileId, capability });\n}\n\nexport async function listVaultSnapshot(\n runner: VaultCliRunner,\n): Promise<VaultListResult> {\n const r = await runner.runJson([\"list\"]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr || r.stdout || `tokenvault list failed (exit ${r.code})`,\n );\n }\n const payload = parseVaultListPayload(r.stdout);\n if (!payload) {\n throw new Error(\"Could not parse JSON from `tokenvault list`.\");\n }\n return {\n providers: payload.providers,\n credentials: payload.credentials ?? [],\n connections: payload.connections ?? [],\n profiles: payload.profiles ?? [],\n };\n}\n\nexport async function selectCapabilityModel(\n runner: VaultCliRunner,\n params: {\n profileId: string;\n capability: Capability;\n connectionId: string;\n modelId: string;\n },\n): Promise<void> {\n const r = await runner.runJson([\n \"profile\",\n \"select\",\n params.profileId,\n params.capability,\n params.connectionId,\n params.modelId,\n ]);\n if (r.code !== 0) {\n throw new Error(\n r.stderr ||\n r.stdout ||\n `tokenvault profile select failed (exit ${r.code})`,\n );\n }\n}\n","import type { TokenVaultBootstrapProvider } from \"./provider.ts\";\nimport type { ListPayload, VaultResolution, ValidationContext } from \"./types.ts\";\n\nexport function parseVaultListPayload(stdout: string): ListPayload | null {\n try {\n return JSON.parse(stdout) as ListPayload;\n } catch {\n return null;\n }\n}\n\nexport function parseResolveStdout(\n stdout: string,\n provider: TokenVaultBootstrapProvider,\n ctx: ValidationContext,\n): VaultResolution {\n let data: unknown;\n try {\n data = JSON.parse(stdout);\n } catch {\n throw new Error(\n \"Could not parse JSON from `tokenvault resolve` (unexpected output).\",\n );\n }\n const resolution = (data as { resolution?: Record<string, unknown> })\n .resolution;\n if (!resolution || typeof resolution !== \"object\") {\n throw new Error(\n \"`tokenvault resolve` JSON did not include a resolution object.\",\n );\n }\n const apiKey =\n typeof resolution.apiKey === \"string\" ? resolution.apiKey.trim() : \"\";\n const modelId =\n typeof resolution.modelId === \"string\" ? resolution.modelId.trim() : \"\";\n const providerId =\n typeof resolution.providerId === \"string\"\n ? resolution.providerId.trim()\n : \"\";\n const apiBaseUrl =\n typeof resolution.apiBaseUrl === \"string\" && resolution.apiBaseUrl.trim()\n ? resolution.apiBaseUrl.trim()\n : undefined;\n const connectionId =\n typeof resolution.connectionId === \"string\"\n ? resolution.connectionId.trim()\n : undefined;\n const credentialId =\n typeof resolution.credentialId === \"string\"\n ? resolution.credentialId.trim()\n : undefined;\n\n if (!apiKey) {\n throw new Error(\n \"`tokenvault resolve` did not return an apiKey. Use a tokenVault build that supports `tokenvault resolve --with-secret` (see tokenVault README).\",\n );\n }\n\n const out: VaultResolution = {\n apiKey,\n modelId,\n providerId,\n baseURL: apiBaseUrl,\n connectionId,\n credentialId,\n };\n provider.validateResolution(out, ctx);\n return out;\n}\n","import fs from \"node:fs\";\nimport path from \"node:path\";\n\n/**\n * Resolve `tokenvault` on PATH (Windows respects PATHEXT).\n * @throws if not found and no explicit path\n */\nexport function resolveTokenvaultExecutable(explicit?: string): string {\n const trimmed = explicit?.trim();\n if (trimmed) return trimmed;\n const fromEnv = process.env.TOKENVAULT_BIN?.trim();\n if (fromEnv) return fromEnv;\n const found = whichOnPath(\"tokenvault\");\n if (!found) {\n throw new Error(\n \"tokenVault is not available: `tokenvault` was not found on PATH. Install tokenVault and link the CLI, or set TOKENVAULT_BIN to the tokenvault executable.\",\n );\n }\n return found;\n}\n\nfunction whichOnPath(cmd: string): string | null {\n const isWin = process.platform === \"win32\";\n const paths = process.env.PATH?.split(path.delimiter) ?? [];\n const exts = isWin\n ? process.env.PATHEXT?.split(path.delimiter) ?? [\".EXE\", \".CMD\", \".BAT\", \"\"]\n : [\"\"];\n\n for (const dir of paths) {\n for (const ext of exts) {\n const candidate = path.join(dir, cmd + ext);\n try {\n const st = fs.statSync(candidate);\n if (!st.isFile()) continue;\n if (!isWin) {\n try {\n fs.accessSync(candidate, fs.constants.X_OK);\n } catch {\n continue;\n }\n }\n return candidate;\n } catch {\n /* try next */\n }\n }\n }\n return null;\n}\n","import type { Logger } from \"./types.ts\";\n\nfunction stderrColorEnabled(): boolean {\n if (process.env.NO_COLOR) return false;\n if (process.env.TERM === \"dumb\") return false;\n return Boolean(process.stderr.isTTY);\n}\n\nconst ANSI_YELLOW = \"\\x1b[33m\";\nconst ANSI_GREEN = \"\\x1b[32m\";\nconst ANSI_RESET = \"\\x1b[0m\";\n\nexport function createDefaultLogger(): Logger {\n return {\n notice(message: string): void {\n if (stderrColorEnabled())\n console.error(`${ANSI_YELLOW}${message}${ANSI_RESET}`);\n else console.error(message);\n },\n success(message: string): void {\n if (stderrColorEnabled())\n console.error(`${ANSI_GREEN}${message}${ANSI_RESET}`);\n else console.error(message);\n },\n };\n}\n","import { spawn } from \"node:child_process\";\nimport { vaultProcessEnv } from \"./env.ts\";\nimport { resolveTokenvaultExecutable } from \"./executable.ts\";\n\nexport type RunJsonResult = { code: number; stdout: string; stderr: string };\n\nexport type VaultCliRunner = {\n runJson: (args: string[]) => Promise<RunJsonResult>;\n runInherit: (args: string[]) => Promise<number>;\n};\n\nexport function createVaultCliRunner(options: {\n executablePath?: string;\n env?: () => NodeJS.ProcessEnv;\n}): VaultCliRunner {\n const envFactory = options.env ?? vaultProcessEnv;\n\n function executable(): string {\n return resolveTokenvaultExecutable(options.executablePath);\n }\n\n return {\n async runJson(args: string[]): Promise<RunJsonResult> {\n const exe = executable();\n const env = envFactory();\n const stdinMode = process.stdin.isTTY ? \"inherit\" : \"ignore\";\n return await spawnCapture([exe, \"--json\", ...args], env, stdinMode);\n },\n async runInherit(args: string[]): Promise<number> {\n const exe = executable();\n const env = envFactory();\n return await spawnInheritAll([exe, ...args], env);\n },\n };\n}\n\nfunction spawnCapture(\n argv: string[],\n env: NodeJS.ProcessEnv,\n stdinMode: \"inherit\" | \"ignore\",\n): Promise<RunJsonResult> {\n const [executablePath, ...args] = argv;\n return new Promise((resolve, reject) => {\n const child = spawn(executablePath!, args, {\n env,\n stdio: [stdinMode, \"pipe\", \"pipe\"],\n });\n let stdout = \"\";\n let stderr = \"\";\n child.stdout?.setEncoding(\"utf8\");\n child.stderr?.setEncoding(\"utf8\");\n child.stdout?.on(\"data\", (c: string) => {\n stdout += c;\n });\n child.stderr?.on(\"data\", (c: string) => {\n stderr += c;\n });\n child.on(\"error\", reject);\n child.on(\"close\", (code) => {\n resolve({\n code: code ?? 1,\n stdout: stdout.trimEnd(),\n stderr: stderr.trimEnd(),\n });\n });\n });\n}\n\nfunction spawnInheritAll(\n argv: string[],\n env: NodeJS.ProcessEnv,\n): Promise<number> {\n const [executablePath, ...args] = argv;\n return new Promise((resolve, reject) => {\n const child = spawn(executablePath!, args, { env, stdio: \"inherit\" });\n child.on(\"error\", reject);\n child.on(\"close\", (code) => resolve(code ?? 1));\n });\n}\n","/**\n * Prefer the OS secure store (Keychain / Secret Service / DPAPI) so tokenVault does not create a\n * passphrase-backed vault. Ignored if the user already has `vault/passphrase-envelope.json` or\n * sets TOKENVAULT_SECURE_STORE themselves.\n */\nexport function vaultProcessEnv(): NodeJS.ProcessEnv {\n const env: NodeJS.ProcessEnv = { ...process.env };\n if (env.TOKENVAULT_SECURE_STORE?.trim()) return env;\n switch (process.platform) {\n case \"darwin\":\n env.TOKENVAULT_SECURE_STORE = \"macos-keychain\";\n break;\n case \"win32\":\n env.TOKENVAULT_SECURE_STORE = \"windows\";\n break;\n case \"linux\":\n env.TOKENVAULT_SECURE_STORE = \"linux-secret-service\";\n break;\n default:\n break;\n }\n return env;\n}\n","import {\n assertCapability,\n CAPABILITY,\n type Capability,\n} from \"./capability.ts\";\nimport {\n ensureBootstrapCapability,\n interactiveSetupAllowed,\n listVaultSnapshot,\n resolveWithSecret,\n selectCapabilityModel,\n type BootstrapContext,\n type BootstrapIds,\n} from \"./bootstrap.ts\";\nimport { resolveTokenvaultExecutable } from \"./executable.ts\";\nimport { createDefaultLogger } from \"./logger.ts\";\nimport type { TokenVaultBootstrapProvider } from \"./provider.ts\";\nimport {\n createVaultCliRunner,\n type VaultCliRunner,\n} from \"./runner.ts\";\nimport type { Logger, VaultListResult, VaultResolution } from \"./types.ts\";\n\nexport type CreateTokenVaultOptions = {\n provider: TokenVaultBootstrapProvider;\n appLabel: string;\n /** Default model per capability; must include entry for `bootstrapCapability` */\n defaultModelByCapability: Partial<Record<Capability, string>>;\n /** Capability wired by `ensure()` (default: chat) */\n bootstrapCapability?: Capability;\n executablePath?: string;\n allowInteractiveBootstrap?: boolean;\n logger?: Logger;\n /** @internal Inject for tests */\n runner?: VaultCliRunner;\n} & (\n | { namespace: string }\n | {\n profileId: string;\n connectionId: string;\n credentialId: string;\n }\n);\n\nexport type TokenVault = {\n /** Bootstrap `bootstrapCapability` for the given profile triple; optional one-off namespace convention. */\n ensure: (namespaceOverride?: string) => Promise<VaultResolution>;\n listProfiles: () => Promise<VaultListResult>;\n /** Profile used by `key()` and `setCapabilityModel` (default: bootstrap profile). */\n useProfile: (profileId: string) => void;\n get activeProfileId(): string;\n key: (capability: Capability | string) => Promise<VaultResolution>;\n setCapabilityModel: (\n capability: Capability | string,\n connectionId: string,\n modelId: string,\n ) => Promise<void>;\n};\n\nfunction idsFromNamespace(\n ns: string,\n provider: TokenVaultBootstrapProvider,\n): BootstrapIds {\n const artifact = `${ns}-${provider.tokenvaultProviderId}`;\n return { profileId: ns, connectionId: artifact, credentialId: artifact };\n}\n\nfunction resolveBootstrapIds(\n options: CreateTokenVaultOptions,\n): BootstrapIds {\n if (\"namespace\" in options) {\n return idsFromNamespace(options.namespace, options.provider);\n }\n return {\n profileId: options.profileId,\n connectionId: options.connectionId,\n credentialId: options.credentialId,\n };\n}\n\nexport function createTokenVault(\n options: CreateTokenVaultOptions,\n): TokenVault {\n const provider = options.provider;\n const bootstrapCapability =\n options.bootstrapCapability ?? CAPABILITY.chat;\n const defaultModelRaw =\n options.defaultModelByCapability[bootstrapCapability]?.trim();\n if (!defaultModelRaw) {\n throw new Error(\n `createTokenVault: defaultModelByCapability must include a default model for bootstrap capability \"${bootstrapCapability}\"`,\n );\n }\n const defaultModelId: string = defaultModelRaw;\n\n if (!options.runner) {\n resolveTokenvaultExecutable(options.executablePath);\n }\n\n const runner =\n options.runner ??\n createVaultCliRunner({ executablePath: options.executablePath });\n\n const bootstrapIds = resolveBootstrapIds(options);\n let resolveProfileId = bootstrapIds.profileId;\n\n const logger = options.logger ?? createDefaultLogger();\n const allowInteractive = interactiveSetupAllowed(\n options.allowInteractiveBootstrap,\n );\n\n function buildContext(ids: BootstrapIds): BootstrapContext {\n return {\n provider,\n ids,\n bootstrapCapability,\n defaultModelId,\n appLabel: options.appLabel,\n logger,\n allowInteractive,\n };\n }\n\n return {\n async ensure(namespaceOverride?: string): Promise<VaultResolution> {\n const trimmed = namespaceOverride?.trim();\n const ids = trimmed\n ? idsFromNamespace(trimmed, provider)\n : bootstrapIds;\n return await ensureBootstrapCapability(\n runner,\n buildContext(ids),\n );\n },\n\n async listProfiles(): Promise<VaultListResult> {\n return await listVaultSnapshot(runner);\n },\n\n useProfile(profileId: string): void {\n resolveProfileId = profileId;\n },\n\n get activeProfileId(): string {\n return resolveProfileId;\n },\n\n async key(capability: Capability | string): Promise<VaultResolution> {\n const cap = typeof capability === \"string\" ? assertCapability(capability) : capability;\n return await resolveWithSecret(\n runner,\n provider,\n resolveProfileId,\n cap,\n );\n },\n\n async setCapabilityModel(\n capability: Capability | string,\n connectionId: string,\n modelId: string,\n ): Promise<void> {\n const cap =\n typeof capability === \"string\" ? assertCapability(capability) : capability;\n await selectCapabilityModel(runner, {\n profileId: resolveProfileId,\n capability: cap,\n connectionId,\n modelId,\n });\n },\n };\n}\n","import type {\n CredentialCopyPick,\n ListPayload,\n VaultResolution,\n ValidationContext,\n} from \"./types.ts\";\n\nexport type TokenVaultBootstrapProvider = {\n /** tokenVault adapter id (e.g. `openai`) */\n readonly tokenvaultProviderId: string;\n /** After parse, enforce provider / model rules */\n validateResolution(\n resolution: VaultResolution,\n ctx: ValidationContext,\n ): void;\n /** Connections on other profiles eligible for credential copy during bootstrap */\n listCredentialCopyPicks(\n payload: ListPayload,\n excludeProfileId: string,\n ): CredentialCopyPick[];\n /** Run `connection refresh-models` after wiring (model-capable providers) */\n readonly refreshModelsAfterBootstrap: boolean;\n};\n\nfunction openAiCopyPicks(\n payload: ListPayload,\n excludeProfileId: string,\n): CredentialCopyPick[] {\n const profiles = payload.profiles ?? [];\n const connections = payload.connections ?? [];\n const byConnId = new Map(connections.map((c) => [c.id, c]));\n const seenCred = new Set<string>();\n const out: CredentialCopyPick[] = [];\n for (const p of profiles) {\n if (p.id === excludeProfileId) continue;\n for (const connId of p.attachedConnectionIds ?? []) {\n const c = byConnId.get(connId);\n if (!c || c.providerId !== \"openai\") continue;\n if (seenCred.has(c.credentialId)) continue;\n seenCred.add(c.credentialId);\n out.push({\n profileId: p.id,\n connectionId: c.id,\n credentialId: c.credentialId,\n });\n }\n }\n return out;\n}\n\nconst openAiProvider: TokenVaultBootstrapProvider = {\n tokenvaultProviderId: \"openai\",\n refreshModelsAfterBootstrap: true,\n listCredentialCopyPicks: openAiCopyPicks,\n validateResolution(resolution: VaultResolution, ctx: ValidationContext): void {\n if (resolution.providerId !== \"openai\") {\n throw new Error(\n `tokenVault profile \"${ctx.profileId}\" must select an OpenAI connection for capability \"${ctx.capability}\" (got provider \"${resolution.providerId}\").`,\n );\n }\n if (!resolution.modelId) {\n throw new Error(\n `tokenVault profile \"${ctx.profileId}\" has no model selected for capability \"${ctx.capability}\". Run: tokenvault profile select ${ctx.profileId} ${ctx.capability} <connection> <model>`,\n );\n }\n },\n};\n\nexport const builtInProviders = {\n openai: openAiProvider,\n} as const;\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,40 @@
1
+ {
2
+ "name": "@partrocks/tokenvault",
3
+ "version": "0.1.2",
4
+ "description": "Facade for tokenvault CLI: bootstrap profiles, resolve secrets per capability, list profiles",
5
+ "type": "module",
6
+ "main": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "default": "./dist/index.js"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist",
17
+ "README.md"
18
+ ],
19
+ "publishConfig": {
20
+ "access": "public"
21
+ },
22
+ "scripts": {
23
+ "build": "tsup",
24
+ "prepublishOnly": "bun run build",
25
+ "typecheck": "tsc --noEmit",
26
+ "test": "bun test"
27
+ },
28
+ "engines": {
29
+ "node": ">=20"
30
+ },
31
+ "dependencies": {
32
+ "is-in-ci": "^2.0.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^22.10.0",
36
+ "tsup": "^8.5.1",
37
+ "typescript": "^5.7.0"
38
+ },
39
+ "license": "MIT"
40
+ }