@vouchagents/cli 0.1.0

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.
@@ -0,0 +1,4 @@
1
+
2
+ > @vouchagents/cli@0.1.0 build /Users/momentumadmin/Desktop/Personal Projects/agent-signup/packages/cli
3
+ > tsc
4
+
package/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,59 @@
1
+ #!/usr/bin/env node
2
+ import { initCommand } from "./commands/init.js";
3
+ import { statusCommand } from "./commands/status.js";
4
+ import { exportCommand } from "./commands/export.js";
5
+ const args = process.argv.slice(2);
6
+ const command = args[0];
7
+ // Parse --vault flag
8
+ const vaultIdx = args.indexOf("--vault");
9
+ const vaultPath = vaultIdx !== -1 ? args[vaultIdx + 1] : undefined;
10
+ switch (command) {
11
+ case "init":
12
+ await initCommand(vaultPath);
13
+ break;
14
+ case "status":
15
+ await statusCommand(vaultPath);
16
+ break;
17
+ case "export": {
18
+ const output = args[1];
19
+ if (!output || output.startsWith("--")) {
20
+ console.log("\n Usage: vouch export <output-path>\n");
21
+ process.exit(1);
22
+ }
23
+ await exportCommand(output, vaultPath);
24
+ break;
25
+ }
26
+ case "help":
27
+ case "--help":
28
+ case "-h":
29
+ case undefined:
30
+ printHelp();
31
+ break;
32
+ default:
33
+ console.log(`\n Unknown command: ${command}`);
34
+ printHelp();
35
+ process.exit(1);
36
+ }
37
+ function printHelp() {
38
+ console.log(`
39
+ \x1b[1mvouch\x1b[0m - Manage your Vouch identity vault
40
+
41
+ \x1b[1mUsage:\x1b[0m
42
+ vouch <command> [options]
43
+
44
+ \x1b[1mCommands:\x1b[0m
45
+ init Create a new encrypted vault
46
+ status Show vault contents and recent signups
47
+ export Export vault to a file (still encrypted)
48
+ help Show this help
49
+
50
+ \x1b[1mOptions:\x1b[0m
51
+ --vault <path> Custom vault path (default: ~/.vouch/vault.json)
52
+
53
+ \x1b[1mExamples:\x1b[0m
54
+ vouch init
55
+ vouch status
56
+ vouch export ~/backup-vault.json
57
+ `);
58
+ }
59
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAErD,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;AACnC,MAAM,OAAO,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;AAExB,qBAAqB;AACrB,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;AACzC,MAAM,SAAS,GAAG,QAAQ,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,QAAQ,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;AAEnE,QAAQ,OAAO,EAAE,CAAC;IAChB,KAAK,MAAM;QACT,MAAM,WAAW,CAAC,SAAS,CAAC,CAAC;QAC7B,MAAM;IAER,KAAK,QAAQ;QACX,MAAM,aAAa,CAAC,SAAS,CAAC,CAAC;QAC/B,MAAM;IAER,KAAK,QAAQ,CAAC,CAAC,CAAC;QACd,MAAM,MAAM,GAAG,IAAI,CAAC,CAAC,CAAC,CAAC;QACvB,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,yCAAyC,CAAC,CAAC;YACvD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QACD,MAAM,aAAa,CAAC,MAAM,EAAE,SAAS,CAAC,CAAC;QACvC,MAAM;IACR,CAAC;IAED,KAAK,MAAM,CAAC;IACZ,KAAK,QAAQ,CAAC;IACd,KAAK,IAAI,CAAC;IACV,KAAK,SAAS;QACZ,SAAS,EAAE,CAAC;QACZ,MAAM;IAER;QACE,OAAO,CAAC,GAAG,CAAC,wBAAwB,OAAO,EAAE,CAAC,CAAC;QAC/C,SAAS,EAAE,CAAC;QACZ,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AACpB,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,CAAC,GAAG,CAAC;;;;;;;;;;;;;;;;;;;CAmBb,CAAC,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function exportCommand(outputPath: string, vaultPath?: string): Promise<void>;
2
+ //# sourceMappingURL=export.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.d.ts","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAIA,wBAAsB,aAAa,CAAC,UAAU,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,iBA+BzE"}
@@ -0,0 +1,32 @@
1
+ import { Vault, FileStorage, defaultVaultPath } from "@vouchagents/client";
2
+ import { writeFile } from "node:fs/promises";
3
+ import { askSecret, close } from "../prompt.js";
4
+ export async function exportCommand(outputPath, vaultPath) {
5
+ const path = vaultPath ?? defaultVaultPath();
6
+ const storage = new FileStorage(path);
7
+ if (!(await storage.exists())) {
8
+ console.log(`\n No vault found at ${path}\n`);
9
+ close();
10
+ return;
11
+ }
12
+ const password = await askSecret(" Vault password: ");
13
+ close();
14
+ try {
15
+ // Verify the password works by opening
16
+ await Vault.open({ passphrase: password, storage });
17
+ // Export the raw encrypted file
18
+ const data = await storage.read();
19
+ if (!data) {
20
+ console.log("\n Failed to read vault.\n");
21
+ process.exit(1);
22
+ }
23
+ await writeFile(outputPath, data, "utf-8");
24
+ console.log(`\n \x1b[32mVault exported to ${outputPath}\x1b[0m`);
25
+ console.log(" This file is encrypted. You need your password to use it.\n");
26
+ }
27
+ catch {
28
+ console.log("\n Wrong password.\n");
29
+ process.exit(1);
30
+ }
31
+ }
32
+ //# sourceMappingURL=export.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"export.js","sourceRoot":"","sources":["../../src/commands/export.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,MAAM,kBAAkB,CAAC;AAC7C,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAEhD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,UAAkB,EAAE,SAAkB;IACxE,MAAM,IAAI,GAAG,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAEtC,IAAI,CAAC,CAAC,MAAM,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,CAAC;QAC9B,OAAO,CAAC,GAAG,CAAC,yBAAyB,IAAI,IAAI,CAAC,CAAC;QAC/C,KAAK,EAAE,CAAC;QACR,OAAO;IACT,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,oBAAoB,CAAC,CAAC;IACvD,KAAK,EAAE,CAAC;IAER,IAAI,CAAC;QACH,uCAAuC;QACvC,MAAM,KAAK,CAAC,IAAI,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QAEpD,gCAAgC;QAChC,MAAM,IAAI,GAAG,MAAM,OAAO,CAAC,IAAI,EAAE,CAAC;QAClC,IAAI,CAAC,IAAI,EAAE,CAAC;YACV,OAAO,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC;YAC3C,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC;QAED,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,EAAE,OAAO,CAAC,CAAC;QAC3C,OAAO,CAAC,GAAG,CAAC,iCAAiC,UAAU,SAAS,CAAC,CAAC;QAClE,OAAO,CAAC,GAAG,CAAC,+DAA+D,CAAC,CAAC;IAC/E,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;QACrC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;AACH,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function initCommand(vaultPath?: string): Promise<void>;
2
+ //# sourceMappingURL=init.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.d.ts","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAGA,wBAAsB,WAAW,CAAC,SAAS,CAAC,EAAE,MAAM,iBAuDnD"}
@@ -0,0 +1,50 @@
1
+ import { Vault, FileStorage, defaultVaultPath } from "@vouchagents/client";
2
+ import { ask, askSecret, close } from "../prompt.js";
3
+ export async function initCommand(vaultPath) {
4
+ const path = vaultPath ?? defaultVaultPath();
5
+ const storage = new FileStorage(path);
6
+ // Check if vault already exists
7
+ if (await storage.exists()) {
8
+ console.log(`\n A vault already exists at ${path}`);
9
+ console.log(" Run `vouch status` to see what's stored.");
10
+ console.log(" Run `vouch init --force` to overwrite.\n");
11
+ close();
12
+ return;
13
+ }
14
+ console.log("\n Setting up Vouch...\n");
15
+ const name = await ask(" What name should we use? ");
16
+ if (!name) {
17
+ console.log(" Name is required.");
18
+ close();
19
+ process.exit(1);
20
+ }
21
+ const email = await ask(" Email? ");
22
+ if (!email) {
23
+ console.log(" Email is required.");
24
+ close();
25
+ process.exit(1);
26
+ }
27
+ const password = await askSecret(" Set a password to protect your vault: ");
28
+ if (!password || password.length < 6) {
29
+ console.log("\n Password must be at least 6 characters.");
30
+ close();
31
+ process.exit(1);
32
+ }
33
+ console.log("\n Creating vault...");
34
+ try {
35
+ const vault = await Vault.create({ passphrase: password, storage });
36
+ await vault.setField("name", name);
37
+ await vault.setField("email", email);
38
+ const identity = vault.getIdentity();
39
+ console.log(`\n \x1b[32mVault created at ${path}\x1b[0m`);
40
+ console.log(` \x1b[32mEd25519 signing key generated\x1b[0m`);
41
+ console.log(`\n Key ID: ${identity.keyId}`);
42
+ console.log(" Your details are encrypted. Run `vouch status` to check.\n");
43
+ }
44
+ catch (err) {
45
+ console.error(`\n Failed to create vault: ${err instanceof Error ? err.message : err}\n`);
46
+ process.exit(1);
47
+ }
48
+ close();
49
+ }
50
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAE,WAAW,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC3E,OAAO,EAAE,GAAG,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,cAAc,CAAC;AAErD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,SAAkB;IAClD,MAAM,IAAI,GAAG,SAAS,IAAI,gBAAgB,EAAE,CAAC;IAC7C,MAAM,OAAO,GAAG,IAAI,WAAW,CAAC,IAAI,CAAC,CAAC;IAEtC,gCAAgC;IAChC,IAAI,MAAM,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC3B,OAAO,CAAC,GAAG,CAAC,iCAAiC,IAAI,EAAE,CAAC,CAAC;QACrD,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC1D,OAAO,CAAC,GAAG,CAAC,4CAA4C,CAAC,CAAC;QAC1D,KAAK,EAAE,CAAC;QACR,OAAO;IACT,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,2BAA2B,CAAC,CAAC;IAEzC,MAAM,IAAI,GAAG,MAAM,GAAG,CAAC,6BAA6B,CAAC,CAAC;IACtD,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;QACnC,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,WAAW,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACpC,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,MAAM,QAAQ,GAAG,MAAM,SAAS,CAAC,0CAA0C,CAAC,CAAC;IAC7E,IAAI,CAAC,QAAQ,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrC,OAAO,CAAC,GAAG,CAAC,6CAA6C,CAAC,CAAC;QAC3D,KAAK,EAAE,CAAC;QACR,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,OAAO,CAAC,GAAG,CAAC,uBAAuB,CAAC,CAAC;IAErC,IAAI,CAAC;QACH,MAAM,KAAK,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;QACpE,MAAM,KAAK,CAAC,QAAQ,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;QACnC,MAAM,KAAK,CAAC,QAAQ,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QAErC,MAAM,QAAQ,GAAG,KAAK,CAAC,WAAW,EAAE,CAAC;QAErC,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,SAAS,CAAC,CAAC;QAC3D,OAAO,CAAC,GAAG,CAAC,gDAAgD,CAAC,CAAC;QAC9D,OAAO,CAAC,GAAG,CAAC,eAAe,QAAQ,CAAC,KAAK,EAAE,CAAC,CAAC;QAC7C,OAAO,CAAC,GAAG,CAAC,8DAA8D,CAAC,CAAC;IAC9E,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,CAAC,KAAK,CAAC,+BAA+B,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;QAC3F,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAClB,CAAC;IAED,KAAK,EAAE,CAAC;AACV,CAAC"}
@@ -0,0 +1,2 @@
1
+ export declare function statusCommand(vaultPath?: string): Promise<void>;
2
+ //# sourceMappingURL=status.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"AAGA,wBAAsB,aAAa,CAAC,SAAS,CAAC,EAAE,MAAM,iBAmDrD"}
@@ -0,0 +1,55 @@
1
+ import { Vault, FileStorage, defaultVaultPath } from "@vouchagents/client";
2
+ import { askSecret, close } from "../prompt.js";
3
+ export async function statusCommand(vaultPath) {
4
+ const path = vaultPath ?? defaultVaultPath();
5
+ const storage = new FileStorage(path);
6
+ if (!(await storage.exists())) {
7
+ console.log(`\n No vault found at ${path}`);
8
+ console.log(" Run `vouch init` to create one.\n");
9
+ close();
10
+ return;
11
+ }
12
+ const password = await askSecret(" Vault password: ");
13
+ close();
14
+ try {
15
+ const vault = await Vault.open({ passphrase: password, storage });
16
+ const fields = await vault.listFields();
17
+ const identity = vault.getIdentity();
18
+ const history = await vault.getHistory({ limit: 5 });
19
+ console.log("\n \x1b[1mVouch Vault\x1b[0m");
20
+ console.log(` Location: ${path}`);
21
+ console.log(` Key ID: ${identity.keyId}\n`);
22
+ console.log(" \x1b[1mStored fields:\x1b[0m");
23
+ for (const field of fields) {
24
+ const val = await vault.getField(field);
25
+ const masked = val && field === "email"
26
+ ? maskEmail(val.unsafeUnwrap())
27
+ : val
28
+ ? val.unsafeUnwrap().slice(0, 2) + "***"
29
+ : "(empty)";
30
+ console.log(` ${field}: ${masked}`);
31
+ }
32
+ if (history.length > 0) {
33
+ console.log(`\n \x1b[1mRecent signups:\x1b[0m`);
34
+ for (const entry of history) {
35
+ const date = new Date(entry.timestamp).toLocaleDateString();
36
+ console.log(` ${date} ${entry.site} ${entry.status}`);
37
+ }
38
+ }
39
+ else {
40
+ console.log("\n No signups yet.");
41
+ }
42
+ console.log();
43
+ }
44
+ catch {
45
+ console.log("\n Wrong password.\n");
46
+ process.exit(1);
47
+ }
48
+ }
49
+ function maskEmail(email) {
50
+ const [local, domain] = email.split("@");
51
+ if (!local || !domain)
52
+ return "***";
53
+ return local.slice(0, 2) + "***@" + domain;
54
+ }
55
+ //# sourceMappingURL=status.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"status.js","sourceRoot":"","sources":["../../src/commands/status.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,4 @@
1
+ export declare function ask(question: string): Promise<string>;
2
+ export declare function askSecret(question: string): Promise<string>;
3
+ export declare function close(): void;
4
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAOA,wBAAgB,GAAG,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAIrD;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CA+B3D;AAED,wBAAgB,KAAK,SAEpB"}
package/dist/prompt.js ADDED
@@ -0,0 +1,50 @@
1
+ import * as readline from "node:readline";
2
+ const rl = readline.createInterface({
3
+ input: process.stdin,
4
+ output: process.stderr, // prompts to stderr so stdout stays clean
5
+ });
6
+ export function ask(question) {
7
+ return new Promise((resolve) => {
8
+ rl.question(question, (answer) => resolve(answer.trim()));
9
+ });
10
+ }
11
+ export function askSecret(question) {
12
+ return new Promise((resolve) => {
13
+ process.stderr.write(question);
14
+ const stdin = process.stdin;
15
+ const wasRaw = stdin.isRaw;
16
+ if (stdin.isTTY)
17
+ stdin.setRawMode(true);
18
+ let input = "";
19
+ const onData = (chunk) => {
20
+ const char = chunk.toString();
21
+ if (char === "\n" || char === "\r") {
22
+ if (stdin.isTTY)
23
+ stdin.setRawMode(wasRaw ?? false);
24
+ stdin.removeListener("data", onData);
25
+ process.stderr.write("\n");
26
+ resolve(input);
27
+ }
28
+ else if (char === "\u007f" || char === "\b") {
29
+ // backspace
30
+ if (input.length > 0) {
31
+ input = input.slice(0, -1);
32
+ process.stderr.write("\b \b");
33
+ }
34
+ }
35
+ else if (char === "\u0003") {
36
+ // ctrl+c
37
+ process.exit(1);
38
+ }
39
+ else {
40
+ input += char;
41
+ process.stderr.write("*");
42
+ }
43
+ };
44
+ stdin.on("data", onData);
45
+ });
46
+ }
47
+ export function close() {
48
+ rl.close();
49
+ }
50
+ //# sourceMappingURL=prompt.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.js","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,QAAQ,MAAM,eAAe,CAAC;AAE1C,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC;IAClC,KAAK,EAAE,OAAO,CAAC,KAAK;IACpB,MAAM,EAAE,OAAO,CAAC,MAAM,EAAE,0CAA0C;CACnE,CAAC,CAAC;AAEH,MAAM,UAAU,GAAG,CAAC,QAAgB;IAClC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,EAAE,CAAC,QAAQ,CAAC,QAAQ,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;IAC5D,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS,CAAC,QAAgB;IACxC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,QAAQ,CAAC,CAAC;QAC/B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC5B,MAAM,MAAM,GAAG,KAAK,CAAC,KAAK,CAAC;QAC3B,IAAI,KAAK,CAAC,KAAK;YAAE,KAAK,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC;QAExC,IAAI,KAAK,GAAG,EAAE,CAAC;QACf,MAAM,MAAM,GAAG,CAAC,KAAa,EAAE,EAAE;YAC/B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC;YAC9B,IAAI,IAAI,KAAK,IAAI,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBACnC,IAAI,KAAK,CAAC,KAAK;oBAAE,KAAK,CAAC,UAAU,CAAC,MAAM,IAAI,KAAK,CAAC,CAAC;gBACnD,KAAK,CAAC,cAAc,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;gBACrC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;gBAC3B,OAAO,CAAC,KAAK,CAAC,CAAC;YACjB,CAAC;iBAAM,IAAI,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI,EAAE,CAAC;gBAC9C,YAAY;gBACZ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;oBACrB,KAAK,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;oBAC3B,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;gBAChC,CAAC;YACH,CAAC;iBAAM,IAAI,IAAI,KAAK,QAAQ,EAAE,CAAC;gBAC7B,SAAS;gBACT,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;YAClB,CAAC;iBAAM,CAAC;gBACN,KAAK,IAAI,IAAI,CAAC;gBACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;YAC5B,CAAC;QACH,CAAC,CAAC;QACF,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAC3B,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,KAAK;IACnB,EAAE,CAAC,KAAK,EAAE,CAAC;AACb,CAAC"}
package/package.json ADDED
@@ -0,0 +1,21 @@
1
+ {
2
+ "name": "@vouchagents/cli",
3
+ "version": "0.1.0",
4
+ "type": "module",
5
+ "bin": {
6
+ "vouch": "./dist/bin.js"
7
+ },
8
+ "scripts": {
9
+ "build": "tsc",
10
+ "typecheck": "tsc --noEmit",
11
+ "clean": "rm -rf dist"
12
+ },
13
+ "dependencies": {
14
+ "@vouchagents/protocol": "0.1.0",
15
+ "@vouchagents/client": "0.1.0"
16
+ },
17
+ "devDependencies": {
18
+ "typescript": "^5.7.0",
19
+ "@types/node": "^25.5.0"
20
+ }
21
+ }
package/src/bin.ts ADDED
@@ -0,0 +1,67 @@
1
+ #!/usr/bin/env node
2
+
3
+ import { initCommand } from "./commands/init.js";
4
+ import { statusCommand } from "./commands/status.js";
5
+ import { exportCommand } from "./commands/export.js";
6
+
7
+ const args = process.argv.slice(2);
8
+ const command = args[0];
9
+
10
+ // Parse --vault flag
11
+ const vaultIdx = args.indexOf("--vault");
12
+ const vaultPath = vaultIdx !== -1 ? args[vaultIdx + 1] : undefined;
13
+
14
+ switch (command) {
15
+ case "init":
16
+ await initCommand(vaultPath);
17
+ break;
18
+
19
+ case "status":
20
+ await statusCommand(vaultPath);
21
+ break;
22
+
23
+ case "export": {
24
+ const output = args[1];
25
+ if (!output || output.startsWith("--")) {
26
+ console.log("\n Usage: vouch export <output-path>\n");
27
+ process.exit(1);
28
+ }
29
+ await exportCommand(output, vaultPath);
30
+ break;
31
+ }
32
+
33
+ case "help":
34
+ case "--help":
35
+ case "-h":
36
+ case undefined:
37
+ printHelp();
38
+ break;
39
+
40
+ default:
41
+ console.log(`\n Unknown command: ${command}`);
42
+ printHelp();
43
+ process.exit(1);
44
+ }
45
+
46
+ function printHelp() {
47
+ console.log(`
48
+ \x1b[1mvouch\x1b[0m - Manage your Vouch identity vault
49
+
50
+ \x1b[1mUsage:\x1b[0m
51
+ vouch <command> [options]
52
+
53
+ \x1b[1mCommands:\x1b[0m
54
+ init Create a new encrypted vault
55
+ status Show vault contents and recent signups
56
+ export Export vault to a file (still encrypted)
57
+ help Show this help
58
+
59
+ \x1b[1mOptions:\x1b[0m
60
+ --vault <path> Custom vault path (default: ~/.vouch/vault.json)
61
+
62
+ \x1b[1mExamples:\x1b[0m
63
+ vouch init
64
+ vouch status
65
+ vouch export ~/backup-vault.json
66
+ `);
67
+ }
@@ -0,0 +1,36 @@
1
+ import { Vault, FileStorage, defaultVaultPath } from "@vouchagents/client";
2
+ import { writeFile } from "node:fs/promises";
3
+ import { askSecret, close } from "../prompt.js";
4
+
5
+ export async function exportCommand(outputPath: string, vaultPath?: string) {
6
+ const path = vaultPath ?? defaultVaultPath();
7
+ const storage = new FileStorage(path);
8
+
9
+ if (!(await storage.exists())) {
10
+ console.log(`\n No vault found at ${path}\n`);
11
+ close();
12
+ return;
13
+ }
14
+
15
+ const password = await askSecret(" Vault password: ");
16
+ close();
17
+
18
+ try {
19
+ // Verify the password works by opening
20
+ await Vault.open({ passphrase: password, storage });
21
+
22
+ // Export the raw encrypted file
23
+ const data = await storage.read();
24
+ if (!data) {
25
+ console.log("\n Failed to read vault.\n");
26
+ process.exit(1);
27
+ }
28
+
29
+ await writeFile(outputPath, data, "utf-8");
30
+ console.log(`\n \x1b[32mVault exported to ${outputPath}\x1b[0m`);
31
+ console.log(" This file is encrypted. You need your password to use it.\n");
32
+ } catch {
33
+ console.log("\n Wrong password.\n");
34
+ process.exit(1);
35
+ }
36
+ }
@@ -0,0 +1,59 @@
1
+ import { Vault, FileStorage, defaultVaultPath } from "@vouchagents/client";
2
+ import { ask, askSecret, close } from "../prompt.js";
3
+
4
+ export async function initCommand(vaultPath?: string) {
5
+ const path = vaultPath ?? defaultVaultPath();
6
+ const storage = new FileStorage(path);
7
+
8
+ // Check if vault already exists
9
+ if (await storage.exists()) {
10
+ console.log(`\n A vault already exists at ${path}`);
11
+ console.log(" Run `vouch status` to see what's stored.");
12
+ console.log(" Run `vouch init --force` to overwrite.\n");
13
+ close();
14
+ return;
15
+ }
16
+
17
+ console.log("\n Setting up Vouch...\n");
18
+
19
+ const name = await ask(" What name should we use? ");
20
+ if (!name) {
21
+ console.log(" Name is required.");
22
+ close();
23
+ process.exit(1);
24
+ }
25
+
26
+ const email = await ask(" Email? ");
27
+ if (!email) {
28
+ console.log(" Email is required.");
29
+ close();
30
+ process.exit(1);
31
+ }
32
+
33
+ const password = await askSecret(" Set a password to protect your vault: ");
34
+ if (!password || password.length < 6) {
35
+ console.log("\n Password must be at least 6 characters.");
36
+ close();
37
+ process.exit(1);
38
+ }
39
+
40
+ console.log("\n Creating vault...");
41
+
42
+ try {
43
+ const vault = await Vault.create({ passphrase: password, storage });
44
+ await vault.setField("name", name);
45
+ await vault.setField("email", email);
46
+
47
+ const identity = vault.getIdentity();
48
+
49
+ console.log(`\n \x1b[32mVault created at ${path}\x1b[0m`);
50
+ console.log(` \x1b[32mEd25519 signing key generated\x1b[0m`);
51
+ console.log(`\n Key ID: ${identity.keyId}`);
52
+ console.log(" Your details are encrypted. Run `vouch status` to check.\n");
53
+ } catch (err) {
54
+ console.error(`\n Failed to create vault: ${err instanceof Error ? err.message : err}\n`);
55
+ process.exit(1);
56
+ }
57
+
58
+ close();
59
+ }
@@ -0,0 +1,61 @@
1
+ import { Vault, FileStorage, defaultVaultPath } from "@vouchagents/client";
2
+ import { askSecret, close } from "../prompt.js";
3
+
4
+ export async function statusCommand(vaultPath?: string) {
5
+ const path = vaultPath ?? defaultVaultPath();
6
+ const storage = new FileStorage(path);
7
+
8
+ if (!(await storage.exists())) {
9
+ console.log(`\n No vault found at ${path}`);
10
+ console.log(" Run `vouch init` to create one.\n");
11
+ close();
12
+ return;
13
+ }
14
+
15
+ const password = await askSecret(" Vault password: ");
16
+ close();
17
+
18
+ try {
19
+ const vault = await Vault.open({ passphrase: password, storage });
20
+ const fields = await vault.listFields();
21
+ const identity = vault.getIdentity();
22
+ const history = await vault.getHistory({ limit: 5 });
23
+
24
+ console.log("\n \x1b[1mVouch Vault\x1b[0m");
25
+ console.log(` Location: ${path}`);
26
+ console.log(` Key ID: ${identity.keyId}\n`);
27
+
28
+ console.log(" \x1b[1mStored fields:\x1b[0m");
29
+ for (const field of fields) {
30
+ const val = await vault.getField(field);
31
+ const masked =
32
+ val && field === "email"
33
+ ? maskEmail(val.unsafeUnwrap())
34
+ : val
35
+ ? val.unsafeUnwrap().slice(0, 2) + "***"
36
+ : "(empty)";
37
+ console.log(` ${field}: ${masked}`);
38
+ }
39
+
40
+ if (history.length > 0) {
41
+ console.log(`\n \x1b[1mRecent signups:\x1b[0m`);
42
+ for (const entry of history) {
43
+ const date = new Date(entry.timestamp).toLocaleDateString();
44
+ console.log(` ${date} ${entry.site} ${entry.status}`);
45
+ }
46
+ } else {
47
+ console.log("\n No signups yet.");
48
+ }
49
+
50
+ console.log();
51
+ } catch {
52
+ console.log("\n Wrong password.\n");
53
+ process.exit(1);
54
+ }
55
+ }
56
+
57
+ function maskEmail(email: string): string {
58
+ const [local, domain] = email.split("@");
59
+ if (!local || !domain) return "***";
60
+ return local.slice(0, 2) + "***@" + domain;
61
+ }
package/src/prompt.ts ADDED
@@ -0,0 +1,49 @@
1
+ import * as readline from "node:readline";
2
+
3
+ const rl = readline.createInterface({
4
+ input: process.stdin,
5
+ output: process.stderr, // prompts to stderr so stdout stays clean
6
+ });
7
+
8
+ export function ask(question: string): Promise<string> {
9
+ return new Promise((resolve) => {
10
+ rl.question(question, (answer) => resolve(answer.trim()));
11
+ });
12
+ }
13
+
14
+ export function askSecret(question: string): Promise<string> {
15
+ return new Promise((resolve) => {
16
+ process.stderr.write(question);
17
+ const stdin = process.stdin;
18
+ const wasRaw = stdin.isRaw;
19
+ if (stdin.isTTY) stdin.setRawMode(true);
20
+
21
+ let input = "";
22
+ const onData = (chunk: Buffer) => {
23
+ const char = chunk.toString();
24
+ if (char === "\n" || char === "\r") {
25
+ if (stdin.isTTY) stdin.setRawMode(wasRaw ?? false);
26
+ stdin.removeListener("data", onData);
27
+ process.stderr.write("\n");
28
+ resolve(input);
29
+ } else if (char === "\u007f" || char === "\b") {
30
+ // backspace
31
+ if (input.length > 0) {
32
+ input = input.slice(0, -1);
33
+ process.stderr.write("\b \b");
34
+ }
35
+ } else if (char === "\u0003") {
36
+ // ctrl+c
37
+ process.exit(1);
38
+ } else {
39
+ input += char;
40
+ process.stderr.write("*");
41
+ }
42
+ };
43
+ stdin.on("data", onData);
44
+ });
45
+ }
46
+
47
+ export function close() {
48
+ rl.close();
49
+ }
package/tsconfig.json ADDED
@@ -0,0 +1,9 @@
1
+ {
2
+ "extends": "../../tsconfig.json",
3
+ "compilerOptions": {
4
+ "outDir": "dist",
5
+ "rootDir": "src",
6
+ "lib": ["ES2022", "DOM"]
7
+ },
8
+ "include": ["src"]
9
+ }