@passwd/passwd-agent-cli 1.3.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.
- package/dist/commands/envs.d.ts +3 -0
- package/dist/commands/envs.js +24 -0
- package/dist/commands/envs.js.map +1 -0
- package/dist/commands/exec.d.ts +3 -0
- package/dist/commands/exec.js +60 -0
- package/dist/commands/exec.js.map +1 -0
- package/dist/commands/get.d.ts +3 -0
- package/dist/commands/get.js +8 -0
- package/dist/commands/get.js.map +1 -0
- package/dist/commands/list.d.ts +7 -0
- package/dist/commands/list.js +20 -0
- package/dist/commands/list.js.map +1 -0
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.js +20 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/resolve.d.ts +10 -0
- package/dist/commands/resolve.js +81 -0
- package/dist/commands/resolve.js.map +1 -0
- package/dist/commands/totp.d.ts +3 -0
- package/dist/commands/totp.js +26 -0
- package/dist/commands/totp.js.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +12 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +80 -0
- package/dist/index.js.map +1 -0
- package/dist/util/envs.d.ts +7 -0
- package/dist/util/envs.js +49 -0
- package/dist/util/envs.js.map +1 -0
- package/dist/util/format.d.ts +4 -0
- package/dist/util/format.js +15 -0
- package/dist/util/format.js.map +1 -0
- package/package.json +36 -0
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { getTokenDir } from "@passwd/passwd-lib";
|
|
2
|
+
import { scanTokenFiles } from "../util/envs.js";
|
|
3
|
+
export async function envsCommand(opts) {
|
|
4
|
+
const envs = await scanTokenFiles(getTokenDir());
|
|
5
|
+
if (envs.length === 0) {
|
|
6
|
+
console.log("No known environments. Log in with PASSWD_ORIGIN set first.");
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const currentOrigin = process.env.PASSWD_ORIGIN?.replace(/\/+$/, "");
|
|
10
|
+
if (opts.json) {
|
|
11
|
+
const out = envs.map((e) => ({
|
|
12
|
+
origin: e.origin,
|
|
13
|
+
current: e.origin === currentOrigin,
|
|
14
|
+
savedAt: e.savedAt,
|
|
15
|
+
}));
|
|
16
|
+
console.log(JSON.stringify(out, null, 2));
|
|
17
|
+
return;
|
|
18
|
+
}
|
|
19
|
+
for (const env of envs) {
|
|
20
|
+
const marker = env.origin === currentOrigin ? " *" : "";
|
|
21
|
+
console.log(`${env.origin}${marker}`);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=envs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envs.js","sourceRoot":"","sources":["../../src/commands/envs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAEjD,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAAwB;IACxD,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,WAAW,EAAE,CAAC,CAAC;IAEjD,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,6DAA6D,CAAC,CAAC;QAC3E,OAAO;IACT,CAAC;IAED,MAAM,aAAa,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAErE,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,MAAM,GAAG,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;YAC3B,MAAM,EAAE,CAAC,CAAC,MAAM;YAChB,OAAO,EAAE,CAAC,CAAC,MAAM,KAAK,aAAa;YACnC,OAAO,EAAE,CAAC,CAAC,OAAO;SACnB,CAAC,CAAC,CAAC;QACJ,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1C,OAAO;IACT,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,MAAM,GAAG,GAAG,CAAC,MAAM,KAAK,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC,CAAC;IACxC,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { spawn } from "node:child_process";
|
|
2
|
+
import { getSecret } from "@passwd/passwd-lib";
|
|
3
|
+
export async function execCommand(args, opts) {
|
|
4
|
+
if (!args.length) {
|
|
5
|
+
console.error("Usage: passwd-agent exec --inject VAR=SECRET_ID:FIELD -- command [args...]");
|
|
6
|
+
process.exitCode = 1;
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
const injections = opts.inject ?? [];
|
|
10
|
+
const env = { ...process.env };
|
|
11
|
+
// Scrub passwd credentials so the child only gets the specific fields requested
|
|
12
|
+
delete env.PASSWD_ACCESS_TOKEN;
|
|
13
|
+
delete env.PASSWD_API_URL;
|
|
14
|
+
delete env.PASSWD_CLIENT_ID;
|
|
15
|
+
// Parse and fetch all injections in parallel
|
|
16
|
+
const tasks = injections.map(async (spec) => {
|
|
17
|
+
const eqIdx = spec.indexOf("=");
|
|
18
|
+
if (eqIdx === -1) {
|
|
19
|
+
throw new Error(`Invalid --inject format: '${spec}'. Expected VAR=SECRET_ID:FIELD`);
|
|
20
|
+
}
|
|
21
|
+
const varName = spec.slice(0, eqIdx);
|
|
22
|
+
const rest = spec.slice(eqIdx + 1);
|
|
23
|
+
const colonIdx = rest.indexOf(":");
|
|
24
|
+
if (colonIdx === -1) {
|
|
25
|
+
throw new Error(`Invalid --inject format: '${spec}'. Expected VAR=SECRET_ID:FIELD`);
|
|
26
|
+
}
|
|
27
|
+
const secretId = rest.slice(0, colonIdx);
|
|
28
|
+
const field = rest.slice(colonIdx + 1);
|
|
29
|
+
const secret = await getSecret(secretId);
|
|
30
|
+
const value = secret[field];
|
|
31
|
+
if (value === undefined) {
|
|
32
|
+
throw new Error(`Field '${field}' not found in secret '${secretId}'`);
|
|
33
|
+
}
|
|
34
|
+
return { varName, value: String(value) };
|
|
35
|
+
});
|
|
36
|
+
const resolved = await Promise.all(tasks);
|
|
37
|
+
for (const { varName, value } of resolved) {
|
|
38
|
+
env[varName] = value;
|
|
39
|
+
}
|
|
40
|
+
const secretValues = resolved.map((r) => r.value).filter((v) => v.length > 0);
|
|
41
|
+
const [cmd, ...cmdArgs] = args;
|
|
42
|
+
// Always mask — no --no-masking flag exists in the agent CLI
|
|
43
|
+
const child = spawn(cmd, cmdArgs, {
|
|
44
|
+
env,
|
|
45
|
+
stdio: ["inherit", "pipe", "pipe"],
|
|
46
|
+
});
|
|
47
|
+
const mask = (chunk) => {
|
|
48
|
+
let str = chunk.toString();
|
|
49
|
+
for (const v of secretValues) {
|
|
50
|
+
str = str.replaceAll(v, "<concealed by passwd>");
|
|
51
|
+
}
|
|
52
|
+
return Buffer.from(str);
|
|
53
|
+
};
|
|
54
|
+
child.stdout?.on("data", (chunk) => process.stdout.write(mask(chunk)));
|
|
55
|
+
child.stderr?.on("data", (chunk) => process.stderr.write(mask(chunk)));
|
|
56
|
+
child.on("close", (code) => {
|
|
57
|
+
process.exitCode = code ?? 1;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=exec.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"exec.js","sourceRoot":"","sources":["../../src/commands/exec.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { getSecret, redactSecret } from "@passwd/passwd-lib";
|
|
2
|
+
import { formatJson } from "../util/format.js";
|
|
3
|
+
export async function getCommand(id, opts) {
|
|
4
|
+
const secret = await getSecret(id);
|
|
5
|
+
// Always redacted — no --field flag exists in the agent CLI
|
|
6
|
+
console.log(formatJson(redactSecret(secret)));
|
|
7
|
+
}
|
|
8
|
+
//# sourceMappingURL=get.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"get.js","sourceRoot":"","sources":["../../src/commands/get.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAC7D,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,EAAU,EACV,IAAwB;IAExB,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,EAAE,CAAC,CAAC;IACnC,4DAA4D;IAC5D,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,YAAY,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC;AAChD,CAAC"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { listSecrets } from "@passwd/passwd-lib";
|
|
2
|
+
import { formatJson, formatSecretRow } from "../util/format.js";
|
|
3
|
+
export async function listCommand(opts) {
|
|
4
|
+
const result = await listSecrets({
|
|
5
|
+
query: opts.query,
|
|
6
|
+
secretType: opts.type,
|
|
7
|
+
limit: opts.limit !== undefined ? Number(opts.limit) : undefined,
|
|
8
|
+
offset: opts.offset !== undefined ? Number(opts.offset) : undefined,
|
|
9
|
+
});
|
|
10
|
+
if (opts.json) {
|
|
11
|
+
console.log(formatJson(result));
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
console.log(`Total: ${result.totalCount}`);
|
|
15
|
+
for (const s of result.secrets) {
|
|
16
|
+
console.log(formatSecretRow(s));
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=list.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"list.js","sourceRoot":"","sources":["../../src/commands/list.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AAEhE,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,IAMjC;IACC,MAAM,MAAM,GAAG,MAAM,WAAW,CAAC;QAC/B,KAAK,EAAE,IAAI,CAAC,KAAK;QACjB,UAAU,EAAE,IAAI,CAAC,IAAI;QACrB,KAAK,EAAE,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS;QAChE,MAAM,EAAE,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,SAAS;KACpE,CAAC,CAAC;IAEH,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC;IAClC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,UAAU,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QAC3C,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;YAC/B,OAAO,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function loginCommand(): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { createInterface } from "node:readline/promises";
|
|
2
|
+
import { stdin, stdout } from "node:process";
|
|
3
|
+
import { buildOAuthUrl, extractCodeFromRedirectUrl, exchangeCode } from "@passwd/passwd-lib";
|
|
4
|
+
export async function loginCommand() {
|
|
5
|
+
const oauthUrl = await buildOAuthUrl();
|
|
6
|
+
console.log("Open this URL in your browser to authenticate:\n");
|
|
7
|
+
console.log(oauthUrl);
|
|
8
|
+
console.log();
|
|
9
|
+
const rl = createInterface({ input: stdin, output: stdout });
|
|
10
|
+
try {
|
|
11
|
+
const redirectUrl = await rl.question("Paste the redirect URL here: ");
|
|
12
|
+
const code = extractCodeFromRedirectUrl(redirectUrl.trim());
|
|
13
|
+
await exchangeCode(code);
|
|
14
|
+
console.log("Authenticated successfully. Token saved to ~/.passwd/");
|
|
15
|
+
}
|
|
16
|
+
finally {
|
|
17
|
+
rl.close();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AACzD,OAAO,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,cAAc,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,0BAA0B,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAE7F,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,MAAM,QAAQ,GAAG,MAAM,aAAa,EAAE,CAAC;IAEvC,OAAO,CAAC,GAAG,CAAC,kDAAkD,CAAC,CAAC;IAChE,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;IACtB,OAAO,CAAC,GAAG,EAAE,CAAC;IAEd,MAAM,EAAE,GAAG,eAAe,CAAC,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC;IAC7D,IAAI,CAAC;QACH,MAAM,WAAW,GAAG,MAAM,EAAE,CAAC,QAAQ,CAAC,+BAA+B,CAAC,CAAC;QACvE,MAAM,IAAI,GAAG,0BAA0B,CAAC,WAAW,CAAC,IAAI,EAAE,CAAC,CAAC;QAC5D,MAAM,YAAY,CAAC,IAAI,CAAC,CAAC;QACzB,OAAO,CAAC,GAAG,CAAC,uDAAuD,CAAC,CAAC;IACvE,CAAC;YAAS,CAAC;QACT,EAAE,CAAC,KAAK,EAAE,CAAC;IACb,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* OpenClaw exec secrets provider protocol.
|
|
3
|
+
*
|
|
4
|
+
* Reads a JSON request from stdin:
|
|
5
|
+
* { "protocolVersion": 1, "provider": "passwd", "ids": ["secretId:field", ...] }
|
|
6
|
+
*
|
|
7
|
+
* Writes a JSON response to stdout:
|
|
8
|
+
* { "protocolVersion": 1, "values": { "secretId:field": "value", ... }, "errors": { "id": "msg", ... } }
|
|
9
|
+
*/
|
|
10
|
+
export declare function resolveCommand(): Promise<void>;
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { getSecret } from "@passwd/passwd-lib";
|
|
2
|
+
/**
|
|
3
|
+
* OpenClaw exec secrets provider protocol.
|
|
4
|
+
*
|
|
5
|
+
* Reads a JSON request from stdin:
|
|
6
|
+
* { "protocolVersion": 1, "provider": "passwd", "ids": ["secretId:field", ...] }
|
|
7
|
+
*
|
|
8
|
+
* Writes a JSON response to stdout:
|
|
9
|
+
* { "protocolVersion": 1, "values": { "secretId:field": "value", ... }, "errors": { "id": "msg", ... } }
|
|
10
|
+
*/
|
|
11
|
+
export async function resolveCommand() {
|
|
12
|
+
const input = await readStdin();
|
|
13
|
+
let request;
|
|
14
|
+
try {
|
|
15
|
+
request = JSON.parse(input);
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
writeResponse({}, { _parse: "Invalid JSON on stdin" });
|
|
19
|
+
return;
|
|
20
|
+
}
|
|
21
|
+
const ids = request.ids ?? [];
|
|
22
|
+
if (!Array.isArray(ids) || ids.length === 0) {
|
|
23
|
+
writeResponse({}, {});
|
|
24
|
+
return;
|
|
25
|
+
}
|
|
26
|
+
// Deduplicate secret IDs to minimize API calls
|
|
27
|
+
const secretIds = [...new Set(ids.map((id) => id.split(":")[0]))];
|
|
28
|
+
const secrets = new Map();
|
|
29
|
+
const fetchErrors = new Map();
|
|
30
|
+
const results = await Promise.allSettled(secretIds.map(async (sid) => {
|
|
31
|
+
const secret = await getSecret(sid);
|
|
32
|
+
return { sid, secret };
|
|
33
|
+
}));
|
|
34
|
+
for (const result of results) {
|
|
35
|
+
if (result.status === "fulfilled") {
|
|
36
|
+
secrets.set(result.value.sid, result.value.secret);
|
|
37
|
+
}
|
|
38
|
+
else {
|
|
39
|
+
const sid = secretIds[results.indexOf(result)];
|
|
40
|
+
fetchErrors.set(sid, String(result.reason));
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const values = {};
|
|
44
|
+
const errors = {};
|
|
45
|
+
for (const id of ids) {
|
|
46
|
+
const [secretId, field = "password"] = id.split(":");
|
|
47
|
+
const fetchError = fetchErrors.get(secretId);
|
|
48
|
+
if (fetchError) {
|
|
49
|
+
errors[id] = fetchError;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
const secret = secrets.get(secretId);
|
|
53
|
+
if (!secret) {
|
|
54
|
+
errors[id] = "Secret not found";
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const value = secret[field];
|
|
58
|
+
if (value === undefined || value === null) {
|
|
59
|
+
errors[id] = `Field '${field}' not found`;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
values[id] = String(value);
|
|
63
|
+
}
|
|
64
|
+
writeResponse(values, errors);
|
|
65
|
+
}
|
|
66
|
+
function writeResponse(values, errors) {
|
|
67
|
+
const response = { protocolVersion: 1, values };
|
|
68
|
+
if (Object.keys(errors).length > 0) {
|
|
69
|
+
response.errors = errors;
|
|
70
|
+
}
|
|
71
|
+
process.stdout.write(JSON.stringify(response) + "\n");
|
|
72
|
+
}
|
|
73
|
+
function readStdin() {
|
|
74
|
+
return new Promise((resolve, reject) => {
|
|
75
|
+
const chunks = [];
|
|
76
|
+
process.stdin.on("data", (chunk) => chunks.push(chunk));
|
|
77
|
+
process.stdin.on("end", () => resolve(Buffer.concat(chunks).toString("utf-8")));
|
|
78
|
+
process.stdin.on("error", reject);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=resolve.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve.js","sourceRoot":"","sources":["../../src/commands/resolve.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,cAAc;IAClC,MAAM,KAAK,GAAG,MAAM,SAAS,EAAE,CAAC;IAEhC,IAAI,OAAqD,CAAC;IAC1D,IAAI,CAAC;QACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC;IAC9B,CAAC;IAAC,MAAM,CAAC;QACP,aAAa,CAAC,EAAE,EAAE,EAAE,MAAM,EAAE,uBAAuB,EAAE,CAAC,CAAC;QACvD,OAAO;IACT,CAAC;IAED,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,EAAE,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC5C,aAAa,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtB,OAAO;IACT,CAAC;IAED,+CAA+C;IAC/C,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;IAClE,MAAM,OAAO,GAAG,IAAI,GAAG,EAAmC,CAAC;IAC3D,MAAM,WAAW,GAAG,IAAI,GAAG,EAAkB,CAAC;IAE9C,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,UAAU,CACtC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,GAAG,EAAE,EAAE;QAC1B,MAAM,MAAM,GAAG,MAAM,SAAS,CAAC,GAAG,CAAC,CAAC;QACpC,OAAO,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC;IACzB,CAAC,CAAC,CACH,CAAC;IAEF,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,IAAI,MAAM,CAAC,MAAM,KAAK,WAAW,EAAE,CAAC;YAClC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,MAA4C,CAAC,CAAC;QAC3F,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,GAAG,SAAS,CAAC,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC;YAC/C,WAAW,CAAC,GAAG,CAAC,GAAG,EAAE,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9C,CAAC;IACH,CAAC;IAED,MAAM,MAAM,GAA2B,EAAE,CAAC;IAC1C,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,EAAE,IAAI,GAAG,EAAE,CAAC;QACrB,MAAM,CAAC,QAAQ,EAAE,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACrD,MAAM,UAAU,GAAG,WAAW,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QAC7C,IAAI,UAAU,EAAE,CAAC;YACf,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,CAAC;YACxB,SAAS;QACX,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACrC,IAAI,CAAC,MAAM,EAAE,CAAC;YACZ,MAAM,CAAC,EAAE,CAAC,GAAG,kBAAkB,CAAC;YAChC,SAAS;QACX,CAAC;QACD,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;QAC5B,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,MAAM,CAAC,EAAE,CAAC,GAAG,UAAU,KAAK,aAAa,CAAC;YAC1C,SAAS;QACX,CAAC;QACD,MAAM,CAAC,EAAE,CAAC,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC;IAC7B,CAAC;IAED,aAAa,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,SAAS,aAAa,CAAC,MAA8B,EAAE,MAA8B;IACnF,MAAM,QAAQ,GAA4B,EAAE,eAAe,EAAE,CAAC,EAAE,MAAM,EAAE,CAAC;IACzE,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnC,QAAQ,CAAC,MAAM,GAAG,MAAM,CAAC;IAC3B,CAAC;IACD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,GAAG,IAAI,CAAC,CAAC;AACxD,CAAC;AAED,SAAS,SAAS;IAChB,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,MAAM,MAAM,GAAa,EAAE,CAAC;QAC5B,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC;QACxD,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC;QAChF,OAAO,CAAC,KAAK,CAAC,EAAE,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACpC,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { getTotpCode } from "@passwd/passwd-lib";
|
|
2
|
+
import { formatJson } from "../util/format.js";
|
|
3
|
+
export async function totpCommand(id, opts) {
|
|
4
|
+
const codes = await getTotpCode(id);
|
|
5
|
+
if (opts.json) {
|
|
6
|
+
console.log(formatJson(codes));
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
// Find the currently valid code
|
|
10
|
+
const now = Math.floor(Date.now() / 1000);
|
|
11
|
+
const current = codes.find((c) => now >= c.validityStart && now < c.validityEnd);
|
|
12
|
+
if (current) {
|
|
13
|
+
const remaining = current.validityEnd - now;
|
|
14
|
+
console.log(`${current.code} (${remaining}s remaining)`);
|
|
15
|
+
}
|
|
16
|
+
else if (codes.length > 0) {
|
|
17
|
+
// Fallback: show the first code
|
|
18
|
+
console.log(codes[0].code);
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
console.error("No TOTP codes returned");
|
|
22
|
+
process.exitCode = 1;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=totp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"totp.js","sourceRoot":"","sources":["../../src/commands/totp.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACjD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,WAAW,CAC/B,EAAU,EACV,IAAwB;IAExB,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,EAAE,CAAC,CAAC;IACpC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,CAAC;IACjC,CAAC;SAAM,CAAC;QACN,gCAAgC;QAChC,MAAM,GAAG,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,CAAC;QAC1C,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,IAAI,CAAC,CAAC,aAAa,IAAI,GAAG,GAAG,CAAC,CAAC,WAAW,CAAC,CAAC;QACjF,IAAI,OAAO,EAAE,CAAC;YACZ,MAAM,SAAS,GAAG,OAAO,CAAC,WAAW,GAAG,GAAG,CAAC;YAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,IAAI,KAAK,SAAS,cAAc,CAAC,CAAC;QAC3D,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,gCAAgC;YAChC,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;QAC7B,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,KAAK,CAAC,wBAAwB,CAAC,CAAC;YACxC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { getCurrentUser } from "@passwd/passwd-lib";
|
|
2
|
+
import { formatJson } from "../util/format.js";
|
|
3
|
+
export async function whoamiCommand(opts) {
|
|
4
|
+
const user = await getCurrentUser();
|
|
5
|
+
if (opts.json) {
|
|
6
|
+
console.log(formatJson(user));
|
|
7
|
+
}
|
|
8
|
+
else {
|
|
9
|
+
console.log(`${user.name} <${user.email}>`);
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
//# sourceMappingURL=whoami.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"whoami.js","sourceRoot":"","sources":["../../src/commands/whoami.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AACpD,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AAE/C,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,IAAwB;IAC1D,MAAM,IAAI,GAAG,MAAM,cAAc,EAAE,CAAC;IACpC,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;QACd,OAAO,CAAC,GAAG,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,KAAK,GAAG,CAAC,CAAC;IAC9C,CAAC;AACH,CAAC"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { loginCommand } from "./commands/login.js";
|
|
4
|
+
import { whoamiCommand } from "./commands/whoami.js";
|
|
5
|
+
import { listCommand } from "./commands/list.js";
|
|
6
|
+
import { getCommand } from "./commands/get.js";
|
|
7
|
+
import { totpCommand } from "./commands/totp.js";
|
|
8
|
+
import { execCommand } from "./commands/exec.js";
|
|
9
|
+
import { envsCommand } from "./commands/envs.js";
|
|
10
|
+
import { resolveCommand } from "./commands/resolve.js";
|
|
11
|
+
import { formatError } from "./util/format.js";
|
|
12
|
+
import { resolveEnv } from "./util/envs.js";
|
|
13
|
+
import { resetDiscoveryCache, getTokenDir } from "@passwd/passwd-lib";
|
|
14
|
+
const program = new Command();
|
|
15
|
+
program
|
|
16
|
+
.name("passwd-agent")
|
|
17
|
+
.description("Agent-safe CLI for passwd.team — no command exposes raw credential values")
|
|
18
|
+
.version("1.3.0")
|
|
19
|
+
.enablePositionalOptions()
|
|
20
|
+
.option("--env <name>", "Target a specific environment (substring match against known origins)");
|
|
21
|
+
program.hook("preAction", async (thisCommand) => {
|
|
22
|
+
const envName = thisCommand.opts().env;
|
|
23
|
+
if (envName) {
|
|
24
|
+
const origin = await resolveEnv(envName, getTokenDir());
|
|
25
|
+
process.env.PASSWD_ORIGIN = origin;
|
|
26
|
+
resetDiscoveryCache();
|
|
27
|
+
}
|
|
28
|
+
});
|
|
29
|
+
program
|
|
30
|
+
.command("login")
|
|
31
|
+
.description("Authenticate with Google OAuth")
|
|
32
|
+
.action(() => loginCommand().catch(die));
|
|
33
|
+
program
|
|
34
|
+
.command("whoami")
|
|
35
|
+
.description("Show current user")
|
|
36
|
+
.option("--json", "Output as JSON")
|
|
37
|
+
.action((opts) => whoamiCommand(opts).catch(die));
|
|
38
|
+
program
|
|
39
|
+
.command("list")
|
|
40
|
+
.description("List secrets")
|
|
41
|
+
.option("-q, --query <text>", "Search by name, username, or URL")
|
|
42
|
+
.option("-t, --type <type>", "Filter by secret type")
|
|
43
|
+
.option("-l, --limit <n>", "Maximum results")
|
|
44
|
+
.option("-o, --offset <n>", "Skip first N results")
|
|
45
|
+
.option("--json", "Output as JSON")
|
|
46
|
+
.action((opts) => listCommand(opts).catch(die));
|
|
47
|
+
program
|
|
48
|
+
.command("get <id>")
|
|
49
|
+
.description("Get a secret (credentials always redacted)")
|
|
50
|
+
.option("--json", "Output as JSON")
|
|
51
|
+
.action((id, opts) => getCommand(id, opts).catch(die));
|
|
52
|
+
program
|
|
53
|
+
.command("totp <id>")
|
|
54
|
+
.description("Get current TOTP code")
|
|
55
|
+
.option("--json", "Output as JSON (includes remaining seconds)")
|
|
56
|
+
.action((id, opts) => totpCommand(id, opts).catch(die));
|
|
57
|
+
program
|
|
58
|
+
.command("exec")
|
|
59
|
+
.description("Run a command with secrets injected as environment variables")
|
|
60
|
+
.option("--inject <mapping...>", "VAR=SECRET_ID:FIELD (repeatable)")
|
|
61
|
+
.argument("[args...]", "Command to execute (after --)")
|
|
62
|
+
.passThroughOptions()
|
|
63
|
+
.action((args, opts) => {
|
|
64
|
+
execCommand(args, opts).catch(die);
|
|
65
|
+
});
|
|
66
|
+
program
|
|
67
|
+
.command("envs")
|
|
68
|
+
.description("List known environments")
|
|
69
|
+
.option("--json", "Output as JSON")
|
|
70
|
+
.action((opts) => envsCommand(opts).catch(die));
|
|
71
|
+
program
|
|
72
|
+
.command("resolve", { hidden: true })
|
|
73
|
+
.description("Resolve secrets for exec secrets provider (reads JSON from stdin)")
|
|
74
|
+
.action(() => resolveCommand().catch(die));
|
|
75
|
+
function die(err) {
|
|
76
|
+
console.error(`Error: ${formatError(err)}`);
|
|
77
|
+
process.exitCode = 1;
|
|
78
|
+
}
|
|
79
|
+
program.parse();
|
|
80
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { readdir, readFile } from "node:fs/promises";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
export async function scanTokenFiles(tokenDir) {
|
|
4
|
+
let files;
|
|
5
|
+
try {
|
|
6
|
+
files = await readdir(tokenDir);
|
|
7
|
+
}
|
|
8
|
+
catch {
|
|
9
|
+
return [];
|
|
10
|
+
}
|
|
11
|
+
const results = [];
|
|
12
|
+
for (const file of files) {
|
|
13
|
+
if (!file.startsWith("tokens-") || !file.endsWith(".json"))
|
|
14
|
+
continue;
|
|
15
|
+
try {
|
|
16
|
+
const content = await readFile(join(tokenDir, file), "utf-8");
|
|
17
|
+
const tokens = JSON.parse(content);
|
|
18
|
+
if (tokens.origin) {
|
|
19
|
+
results.push({
|
|
20
|
+
origin: tokens.origin,
|
|
21
|
+
file,
|
|
22
|
+
savedAt: tokens.saved_at,
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
catch {
|
|
27
|
+
// skip unreadable/corrupt files
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return results;
|
|
31
|
+
}
|
|
32
|
+
export async function resolveEnv(name, tokenDir) {
|
|
33
|
+
const envs = await scanTokenFiles(tokenDir);
|
|
34
|
+
if (envs.length === 0) {
|
|
35
|
+
throw new Error("No known environments. Log in with PASSWD_ORIGIN set first.");
|
|
36
|
+
}
|
|
37
|
+
const lower = name.toLowerCase();
|
|
38
|
+
const matches = envs.filter((e) => e.origin.toLowerCase().includes(lower));
|
|
39
|
+
if (matches.length === 0) {
|
|
40
|
+
const known = envs.map((e) => ` ${e.origin}`).join("\n");
|
|
41
|
+
throw new Error(`No environment matching "${name}". Known environments:\n${known}`);
|
|
42
|
+
}
|
|
43
|
+
if (matches.length > 1) {
|
|
44
|
+
const list = matches.map((e) => ` ${e.origin}`).join("\n");
|
|
45
|
+
throw new Error(`Ambiguous match for "${name}". Matching environments:\n${list}\nBe more specific.`);
|
|
46
|
+
}
|
|
47
|
+
return matches[0].origin;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=envs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"envs.js","sourceRoot":"","sources":["../../src/util/envs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AASjC,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,QAAgB;IACnD,IAAI,KAAe,CAAC;IACpB,IAAI,CAAC;QACH,KAAK,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAc,EAAE,CAAC;IAC9B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,CAAC;YAAE,SAAS;QACrE,IAAI,CAAC;YACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,IAAI,CAAC,QAAQ,EAAE,IAAI,CAAC,EAAE,OAAO,CAAC,CAAC;YAC9D,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAe,CAAC;YACjD,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;gBAClB,OAAO,CAAC,IAAI,CAAC;oBACX,MAAM,EAAE,MAAM,CAAC,MAAM;oBACrB,IAAI;oBACJ,OAAO,EAAE,MAAM,CAAC,QAAQ;iBACzB,CAAC,CAAC;YACL,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,gCAAgC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,UAAU,CAC9B,IAAY,EACZ,QAAgB;IAEhB,MAAM,IAAI,GAAG,MAAM,cAAc,CAAC,QAAQ,CAAC,CAAC;IAC5C,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,MAAM,IAAI,KAAK,CACb,6DAA6D,CAC9D,CAAC;IACJ,CAAC;IAED,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC;IACjC,MAAM,OAAO,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,CAAC;IAE3E,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACzB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1D,MAAM,IAAI,KAAK,CACb,4BAA4B,IAAI,2BAA2B,KAAK,EAAE,CACnE,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC5D,MAAM,IAAI,KAAK,CACb,wBAAwB,IAAI,8BAA8B,IAAI,qBAAqB,CACpF,CAAC;IACJ,CAAC;IACD,OAAO,OAAO,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC;AAC3B,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export function formatError(error) {
|
|
2
|
+
return error instanceof Error ? error.message : String(error);
|
|
3
|
+
}
|
|
4
|
+
export function formatJson(data) {
|
|
5
|
+
return JSON.stringify(data, null, 2);
|
|
6
|
+
}
|
|
7
|
+
export function formatSecretRow(s) {
|
|
8
|
+
const parts = [s.id, s.type, s.name];
|
|
9
|
+
if (s.username)
|
|
10
|
+
parts.push(s.username);
|
|
11
|
+
if (s.web)
|
|
12
|
+
parts.push(s.web);
|
|
13
|
+
return parts.join("\t");
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=format.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format.js","sourceRoot":"","sources":["../../src/util/format.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,WAAW,CAAC,KAAc;IACxC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,UAAU,CAAC,IAAa;IACtC,OAAO,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC;AACvC,CAAC;AAED,MAAM,UAAU,eAAe,CAAC,CAAiB;IAC/C,MAAM,KAAK,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC;IACrC,IAAI,CAAC,CAAC,QAAQ;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,CAAC;IACvC,IAAI,CAAC,CAAC,GAAG;QAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC;IAC7B,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@passwd/passwd-agent-cli",
|
|
3
|
+
"version": "1.3.0",
|
|
4
|
+
"description": "Agent-safe CLI for passwd.team — no command exposes raw credential values",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"bin": {
|
|
8
|
+
"passwd-agent": "dist/index.js"
|
|
9
|
+
},
|
|
10
|
+
"files": [
|
|
11
|
+
"dist"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc -b"
|
|
15
|
+
},
|
|
16
|
+
"keywords": [
|
|
17
|
+
"passwd",
|
|
18
|
+
"password-manager",
|
|
19
|
+
"cli",
|
|
20
|
+
"agent",
|
|
21
|
+
"passwd-team"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"dependencies": {
|
|
25
|
+
"@passwd/passwd-lib": "1.3.0",
|
|
26
|
+
"commander": "^13.1.0"
|
|
27
|
+
},
|
|
28
|
+
"repository": {
|
|
29
|
+
"type": "git",
|
|
30
|
+
"url": "https://github.com/pepuscz/passwd.git",
|
|
31
|
+
"directory": "packages/passwd-agent-cli"
|
|
32
|
+
},
|
|
33
|
+
"publishConfig": {
|
|
34
|
+
"access": "public"
|
|
35
|
+
}
|
|
36
|
+
}
|