workos 0.15.2 → 0.16.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/README.md +37 -11
- package/dist/bin.js +1439 -1257
- package/dist/bin.js.map +1 -1
- package/dist/cli.config.d.ts +1 -0
- package/dist/cli.config.js +1 -0
- package/dist/cli.config.js.map +1 -1
- package/dist/commands/api/index.js +7 -2
- package/dist/commands/api/index.js.map +1 -1
- package/dist/commands/api/interactive.js +9 -3
- package/dist/commands/api/interactive.js.map +1 -1
- package/dist/commands/debug.d.ts +2 -1
- package/dist/commands/debug.js +43 -3
- package/dist/commands/debug.js.map +1 -1
- package/dist/commands/dev.js +5 -4
- package/dist/commands/dev.js.map +1 -1
- package/dist/commands/doctor.js +13 -4
- package/dist/commands/doctor.js.map +1 -1
- package/dist/commands/emulate.js +2 -2
- package/dist/commands/emulate.js.map +1 -1
- package/dist/commands/env.js +5 -4
- package/dist/commands/env.js.map +1 -1
- package/dist/commands/install-skill.js +4 -3
- package/dist/commands/install-skill.js.map +1 -1
- package/dist/commands/install.js +2 -2
- package/dist/commands/install.js.map +1 -1
- package/dist/commands/login.js +3 -3
- package/dist/commands/login.js.map +1 -1
- package/dist/commands/migrations.d.ts +1 -1
- package/dist/commands/migrations.js +4 -1
- package/dist/commands/migrations.js.map +1 -1
- package/dist/commands/telemetry.d.ts +3 -0
- package/dist/commands/telemetry.js +88 -0
- package/dist/commands/telemetry.js.map +1 -0
- package/dist/commands/uninstall-skill.js +3 -2
- package/dist/commands/uninstall-skill.js.map +1 -1
- package/dist/commands/vault-run.d.ts +13 -0
- package/dist/commands/vault-run.js +194 -0
- package/dist/commands/vault-run.js.map +1 -0
- package/dist/commands/vault.d.ts +3 -2
- package/dist/commands/vault.js +41 -8
- package/dist/commands/vault.js.map +1 -1
- package/dist/lib/api-error-handler.d.ts +15 -3
- package/dist/lib/api-error-handler.js +52 -34
- package/dist/lib/api-error-handler.js.map +1 -1
- package/dist/lib/command-aliases.d.ts +8 -0
- package/dist/lib/command-aliases.js +12 -0
- package/dist/lib/command-aliases.js.map +1 -0
- package/dist/lib/constants.d.ts +0 -1
- package/dist/lib/constants.js +0 -1
- package/dist/lib/constants.js.map +1 -1
- package/dist/lib/device-id.d.ts +25 -0
- package/dist/lib/device-id.js +102 -0
- package/dist/lib/device-id.js.map +1 -0
- package/dist/lib/preferences.d.ts +101 -0
- package/dist/lib/preferences.js +198 -0
- package/dist/lib/preferences.js.map +1 -0
- package/dist/lib/run-with-core.js +15 -15
- package/dist/lib/run-with-core.js.map +1 -1
- package/dist/lib/settings.d.ts +6 -0
- package/dist/lib/settings.js +7 -0
- package/dist/lib/settings.js.map +1 -1
- package/dist/lib/telemetry-notice.d.ts +25 -0
- package/dist/lib/telemetry-notice.js +56 -0
- package/dist/lib/telemetry-notice.js.map +1 -0
- package/dist/test/force-insecure-storage.d.ts +1 -0
- package/dist/test/force-insecure-storage.js +9 -0
- package/dist/test/force-insecure-storage.js.map +1 -0
- package/dist/test/setup.d.ts +1 -0
- package/dist/test/setup.js +38 -0
- package/dist/test/setup.js.map +1 -0
- package/dist/utils/analytics.d.ts +41 -0
- package/dist/utils/analytics.js +199 -12
- package/dist/utils/analytics.js.map +1 -1
- package/dist/utils/box.d.ts +29 -1
- package/dist/utils/box.js +92 -4
- package/dist/utils/box.js.map +1 -1
- package/dist/utils/cli-exit.d.ts +15 -0
- package/dist/utils/cli-exit.js +11 -0
- package/dist/utils/cli-exit.js.map +1 -0
- package/dist/utils/cli-symbols.d.ts +1 -1
- package/dist/utils/command-telemetry.d.ts +17 -0
- package/dist/utils/command-telemetry.js +67 -0
- package/dist/utils/command-telemetry.js.map +1 -0
- package/dist/utils/crash-reporter.d.ts +13 -0
- package/dist/utils/crash-reporter.js +91 -0
- package/dist/utils/crash-reporter.js.map +1 -0
- package/dist/utils/debug.d.ts +1 -0
- package/dist/utils/debug.js +4 -1
- package/dist/utils/debug.js.map +1 -1
- package/dist/utils/exit-codes.d.ts +5 -0
- package/dist/utils/exit-codes.js +30 -1
- package/dist/utils/exit-codes.js.map +1 -1
- package/dist/utils/help-json.d.ts +6 -0
- package/dist/utils/help-json.js +87 -10
- package/dist/utils/help-json.js.map +1 -1
- package/dist/utils/output.d.ts +7 -2
- package/dist/utils/output.js +9 -2
- package/dist/utils/output.js.map +1 -1
- package/dist/utils/telemetry-client.d.ts +30 -2
- package/dist/utils/telemetry-client.js +122 -12
- package/dist/utils/telemetry-client.js.map +1 -1
- package/dist/utils/telemetry-store-forward.d.ts +11 -0
- package/dist/utils/telemetry-store-forward.js +94 -0
- package/dist/utils/telemetry-store-forward.js.map +1 -0
- package/dist/utils/telemetry-types.d.ts +58 -9
- package/dist/utils/telemetry-types.js.map +1 -1
- package/package.json +1 -1
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { COMMAND_ALIASES } from '../lib/command-aliases.js';
|
|
2
|
+
import { getTopLevelCommandNames } from './help-json.js';
|
|
3
|
+
let knownTopLevelCommands = null;
|
|
4
|
+
/** Canonical top-level command heads (registry + alias targets), memoized. */
|
|
5
|
+
function topLevelCommands() {
|
|
6
|
+
if (!knownTopLevelCommands) {
|
|
7
|
+
const names = new Set(getTopLevelCommandNames());
|
|
8
|
+
// Alias targets resolve to a canonical head (e.g. claim -> env.claim -> env).
|
|
9
|
+
for (const target of Object.values(COMMAND_ALIASES)) {
|
|
10
|
+
names.add(target.split('.')[0]);
|
|
11
|
+
}
|
|
12
|
+
knownTopLevelCommands = names;
|
|
13
|
+
}
|
|
14
|
+
return knownTopLevelCommands;
|
|
15
|
+
}
|
|
16
|
+
export const SKIP_TELEMETRY_COMMANDS = new Set(['install', 'dashboard', 'root', 'telemetry']);
|
|
17
|
+
export function resolveCanonicalName(parts) {
|
|
18
|
+
if (parts.length === 0)
|
|
19
|
+
return 'root';
|
|
20
|
+
const resolved = [...parts];
|
|
21
|
+
resolved[0] = COMMAND_ALIASES[resolved[0]] ?? resolved[0];
|
|
22
|
+
return resolved.join('.');
|
|
23
|
+
}
|
|
24
|
+
/**
|
|
25
|
+
* Resolve the command name from raw argv for paths where yargs validation
|
|
26
|
+
* fails before middleware runs (e.g. a missing required argument).
|
|
27
|
+
*
|
|
28
|
+
* Returns the first token that resolves to a KNOWN top-level command. Tokens
|
|
29
|
+
* are matched against the command registry rather than trusting position, so
|
|
30
|
+
* an option value preceding the command (e.g. `--api-key sk_live_… org` or
|
|
31
|
+
* `--mode ci org`) can never be recorded as the command name — that would leak
|
|
32
|
+
* secrets/values into telemetry and explode cardinality. Anything that isn't a
|
|
33
|
+
* known command (typos, stray values, `--help`) returns 'root', which is
|
|
34
|
+
* skipped. Only the top-level command is recorded; later positionals can be
|
|
35
|
+
* user values (org names, emails, IDs), so they are never included.
|
|
36
|
+
*/
|
|
37
|
+
export function resolveCommandNameFromRawArgs(rawArgs) {
|
|
38
|
+
const known = topLevelCommands();
|
|
39
|
+
for (const token of rawArgs) {
|
|
40
|
+
if (token.startsWith('-'))
|
|
41
|
+
continue;
|
|
42
|
+
const canonical = resolveCanonicalName([token]);
|
|
43
|
+
if (known.has(canonical.split('.')[0]))
|
|
44
|
+
return canonical;
|
|
45
|
+
}
|
|
46
|
+
return 'root';
|
|
47
|
+
}
|
|
48
|
+
export function extractUserFlags(rawArgs) {
|
|
49
|
+
const passedFlags = rawArgs
|
|
50
|
+
.filter((arg) => {
|
|
51
|
+
// `--` is the positional separator, not a flag.
|
|
52
|
+
if (arg === '--')
|
|
53
|
+
return false;
|
|
54
|
+
// Long flags: --name or --name=value (must start with a letter, so
|
|
55
|
+
// negative numbers like -1 / --1 are not mistaken for flags).
|
|
56
|
+
if (/^--[A-Za-z][\w-]*(=.*)?$/.test(arg))
|
|
57
|
+
return true;
|
|
58
|
+
// Short flags: a single letter, e.g. -v.
|
|
59
|
+
if (/^-[A-Za-z]$/.test(arg))
|
|
60
|
+
return true;
|
|
61
|
+
return false;
|
|
62
|
+
})
|
|
63
|
+
.map((arg) => arg.replace(/^-+/, '').split('=')[0])
|
|
64
|
+
.filter(Boolean);
|
|
65
|
+
return [...new Set(passedFlags)];
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=command-telemetry.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"command-telemetry.js","sourceRoot":"","sources":["../../src/utils/command-telemetry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,gBAAgB,CAAC;AAEzD,IAAI,qBAAqB,GAAuB,IAAI,CAAC;AAErD,8EAA8E;AAC9E,SAAS,gBAAgB;IACvB,IAAI,CAAC,qBAAqB,EAAE,CAAC;QAC3B,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,uBAAuB,EAAE,CAAC,CAAC;QACjD,8EAA8E;QAC9E,KAAK,MAAM,MAAM,IAAI,MAAM,CAAC,MAAM,CAAC,eAAe,CAAC,EAAE,CAAC;YACpD,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAClC,CAAC;QACD,qBAAqB,GAAG,KAAK,CAAC;IAChC,CAAC;IACD,OAAO,qBAAqB,CAAC;AAC/B,CAAC;AAED,MAAM,CAAC,MAAM,uBAAuB,GAAG,IAAI,GAAG,CAAC,CAAC,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAC;AAE9F,MAAM,UAAU,oBAAoB,CAAC,KAAe;IAClD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,MAAM,CAAC;IACtC,MAAM,QAAQ,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IAC5B,QAAQ,CAAC,CAAC,CAAC,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,CAAC,CAAC,CAAC;IAC1D,OAAO,QAAQ,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AAC5B,CAAC;AAED;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,6BAA6B,CAAC,OAAiB;IAC7D,MAAM,KAAK,GAAG,gBAAgB,EAAE,CAAC;IACjC,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,IAAI,KAAK,CAAC,UAAU,CAAC,GAAG,CAAC;YAAE,SAAS;QACpC,MAAM,SAAS,GAAG,oBAAoB,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;QAChD,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;YAAE,OAAO,SAAS,CAAC;IAC3D,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,OAAiB;IAChD,MAAM,WAAW,GAAG,OAAO;SACxB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE;QACd,gDAAgD;QAChD,IAAI,GAAG,KAAK,IAAI;YAAE,OAAO,KAAK,CAAC;QAC/B,mEAAmE;QACnE,8DAA8D;QAC9D,IAAI,0BAA0B,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACtD,yCAAyC;QACzC,IAAI,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QACzC,OAAO,KAAK,CAAC;IACf,CAAC,CAAC;SACD,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;SAClD,MAAM,CAAC,OAAO,CAAC,CAAC;IACnB,OAAO,CAAC,GAAG,IAAI,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC;AACnC,CAAC","sourcesContent":["import { COMMAND_ALIASES } from '../lib/command-aliases.js';\nimport { getTopLevelCommandNames } from './help-json.js';\n\nlet knownTopLevelCommands: Set<string> | null = null;\n\n/** Canonical top-level command heads (registry + alias targets), memoized. */\nfunction topLevelCommands(): Set<string> {\n if (!knownTopLevelCommands) {\n const names = new Set(getTopLevelCommandNames());\n // Alias targets resolve to a canonical head (e.g. claim -> env.claim -> env).\n for (const target of Object.values(COMMAND_ALIASES)) {\n names.add(target.split('.')[0]);\n }\n knownTopLevelCommands = names;\n }\n return knownTopLevelCommands;\n}\n\nexport const SKIP_TELEMETRY_COMMANDS = new Set(['install', 'dashboard', 'root', 'telemetry']);\n\nexport function resolveCanonicalName(parts: string[]): string {\n if (parts.length === 0) return 'root';\n const resolved = [...parts];\n resolved[0] = COMMAND_ALIASES[resolved[0]] ?? resolved[0];\n return resolved.join('.');\n}\n\n/**\n * Resolve the command name from raw argv for paths where yargs validation\n * fails before middleware runs (e.g. a missing required argument).\n *\n * Returns the first token that resolves to a KNOWN top-level command. Tokens\n * are matched against the command registry rather than trusting position, so\n * an option value preceding the command (e.g. `--api-key sk_live_… org` or\n * `--mode ci org`) can never be recorded as the command name — that would leak\n * secrets/values into telemetry and explode cardinality. Anything that isn't a\n * known command (typos, stray values, `--help`) returns 'root', which is\n * skipped. Only the top-level command is recorded; later positionals can be\n * user values (org names, emails, IDs), so they are never included.\n */\nexport function resolveCommandNameFromRawArgs(rawArgs: string[]): string {\n const known = topLevelCommands();\n for (const token of rawArgs) {\n if (token.startsWith('-')) continue;\n const canonical = resolveCanonicalName([token]);\n if (known.has(canonical.split('.')[0])) return canonical;\n }\n return 'root';\n}\n\nexport function extractUserFlags(rawArgs: string[]): string[] {\n const passedFlags = rawArgs\n .filter((arg) => {\n // `--` is the positional separator, not a flag.\n if (arg === '--') return false;\n // Long flags: --name or --name=value (must start with a letter, so\n // negative numbers like -1 / --1 are not mistaken for flags).\n if (/^--[A-Za-z][\\w-]*(=.*)?$/.test(arg)) return true;\n // Short flags: a single letter, e.g. -v.\n if (/^-[A-Za-z]$/.test(arg)) return true;\n return false;\n })\n .map((arg) => arg.replace(/^-+/, '').split('=')[0])\n .filter(Boolean);\n return [...new Set(passedFlags)];\n}\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/** Sanitize stack trace for telemetry: homedir, absolute-path collapse, secrets, truncation. */
|
|
2
|
+
export declare function sanitizeStack(stack: string | undefined): string;
|
|
3
|
+
/** Sanitize an error message for telemetry (homedir, secrets, truncation). */
|
|
4
|
+
export declare function sanitizeMessage(msg: string | undefined): string;
|
|
5
|
+
/**
|
|
6
|
+
* Register global handlers for uncaughtException and unhandledRejection
|
|
7
|
+
* that capture crash details before the process exits.
|
|
8
|
+
*
|
|
9
|
+
* Handlers are SYNCHRONOUS. Node does NOT await async uncaughtException handlers.
|
|
10
|
+
* We queue the event synchronously; store-forward's process.on('exit') handler
|
|
11
|
+
* persists it to disk. The next CLI invocation recovers and sends.
|
|
12
|
+
*/
|
|
13
|
+
export declare function installCrashReporter(): void;
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import { analytics } from './analytics.js';
|
|
2
|
+
import { CliExit } from './cli-exit.js';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
// Hard ceiling the telemetry API enforces on every attribute value
|
|
5
|
+
// (z.string().max(4096) in llm-gateway/types/telemetry-event.ts). The final
|
|
6
|
+
// sanitized string — truncation marker included — MUST stay within this, or
|
|
7
|
+
// the whole crash event fails Zod validation server-side and is silently
|
|
8
|
+
// dropped. Reserve room for the marker so a truncated stack lands at exactly
|
|
9
|
+
// MAX_STACK_LENGTH rather than overshooting it.
|
|
10
|
+
const MAX_STACK_LENGTH = 4096;
|
|
11
|
+
const STACK_TRUNCATION_MARKER = '\n...[truncated]';
|
|
12
|
+
const MAX_MESSAGE_LENGTH = 1024;
|
|
13
|
+
const HOME = homedir();
|
|
14
|
+
let isCrashing = false;
|
|
15
|
+
/**
|
|
16
|
+
* Redact known credential patterns (Bearer tokens, sk_test_/sk_live_ keys,
|
|
17
|
+
* raw JWTs). Shared by sanitizeStack and sanitizeMessage because Node echoes
|
|
18
|
+
* `.message` into the leading `Error.stack` line, so secrets in messages also
|
|
19
|
+
* surface in stacks.
|
|
20
|
+
*/
|
|
21
|
+
function redactSecrets(s) {
|
|
22
|
+
return s
|
|
23
|
+
.replace(/Bearer\s+[A-Za-z0-9._-]+/g, 'Bearer <redacted>')
|
|
24
|
+
.replace(/\bsk_(test|live)_[A-Za-z0-9]+/g, 'sk_<redacted>')
|
|
25
|
+
.replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, '<jwt-redacted>');
|
|
26
|
+
}
|
|
27
|
+
/** Sanitize stack trace for telemetry: homedir, absolute-path collapse, secrets, truncation. */
|
|
28
|
+
export function sanitizeStack(stack) {
|
|
29
|
+
if (!stack)
|
|
30
|
+
return '';
|
|
31
|
+
let sanitized = stack.replaceAll(HOME, '~');
|
|
32
|
+
// Collapse absolute paths to their leaf segment. POSIX and Windows separately —
|
|
33
|
+
// Windows paths (C:\...\node_modules\) bypass the POSIX regex and would
|
|
34
|
+
// otherwise leak full local filesystem paths into telemetry.
|
|
35
|
+
sanitized = sanitized
|
|
36
|
+
.replace(/\/[^\s:]+\/(node_modules|dist|src)\//g, '$1/')
|
|
37
|
+
.replace(/[A-Za-z]:\\[^\s:]+\\(node_modules|dist|src)\\/g, '$1\\');
|
|
38
|
+
sanitized = redactSecrets(sanitized);
|
|
39
|
+
return sanitized.length > MAX_STACK_LENGTH
|
|
40
|
+
? sanitized.slice(0, MAX_STACK_LENGTH - STACK_TRUNCATION_MARKER.length) + STACK_TRUNCATION_MARKER
|
|
41
|
+
: sanitized;
|
|
42
|
+
}
|
|
43
|
+
/** Sanitize an error message for telemetry (homedir, secrets, truncation). */
|
|
44
|
+
export function sanitizeMessage(msg) {
|
|
45
|
+
if (!msg)
|
|
46
|
+
return '';
|
|
47
|
+
const sanitized = redactSecrets(msg.replaceAll(HOME, '~'));
|
|
48
|
+
return sanitized.length > MAX_MESSAGE_LENGTH ? sanitized.slice(0, MAX_MESSAGE_LENGTH) + '...[truncated]' : sanitized;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Register global handlers for uncaughtException and unhandledRejection
|
|
52
|
+
* that capture crash details before the process exits.
|
|
53
|
+
*
|
|
54
|
+
* Handlers are SYNCHRONOUS. Node does NOT await async uncaughtException handlers.
|
|
55
|
+
* We queue the event synchronously; store-forward's process.on('exit') handler
|
|
56
|
+
* persists it to disk. The next CLI invocation recovers and sends.
|
|
57
|
+
*/
|
|
58
|
+
export function installCrashReporter() {
|
|
59
|
+
process.on('uncaughtException', (error) => {
|
|
60
|
+
// A CliExit that reaches here escaped the normal lifecycle (e.g. thrown
|
|
61
|
+
// from a fire-and-forget async event listener like `child.on('error')` in
|
|
62
|
+
// dev.ts). It is an intentional exit, NOT a crash — record no crash event,
|
|
63
|
+
// just honor the requested code.
|
|
64
|
+
if (error instanceof CliExit) {
|
|
65
|
+
process.exit(error.exitCode);
|
|
66
|
+
}
|
|
67
|
+
reportCrashSync(error);
|
|
68
|
+
process.exit(1);
|
|
69
|
+
});
|
|
70
|
+
process.on('unhandledRejection', (reason) => {
|
|
71
|
+
if (reason instanceof CliExit) {
|
|
72
|
+
process.exit(reason.exitCode);
|
|
73
|
+
}
|
|
74
|
+
const error = reason instanceof Error ? reason : new Error(String(reason));
|
|
75
|
+
reportCrashSync(error);
|
|
76
|
+
process.exit(1);
|
|
77
|
+
});
|
|
78
|
+
}
|
|
79
|
+
function reportCrashSync(error) {
|
|
80
|
+
if (isCrashing)
|
|
81
|
+
return;
|
|
82
|
+
isCrashing = true;
|
|
83
|
+
try {
|
|
84
|
+
// captureUnhandledCrash sanitizes both message and stack at the analytics boundary.
|
|
85
|
+
analytics.captureUnhandledCrash(error);
|
|
86
|
+
}
|
|
87
|
+
catch {
|
|
88
|
+
// Telemetry must never prevent exit
|
|
89
|
+
}
|
|
90
|
+
}
|
|
91
|
+
//# sourceMappingURL=crash-reporter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"crash-reporter.js","sourceRoot":"","sources":["../../src/utils/crash-reporter.ts"],"names":[],"mappings":"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","sourcesContent":["import { analytics } from './analytics.js';\nimport { CliExit } from './cli-exit.js';\nimport { homedir } from 'node:os';\n\n// Hard ceiling the telemetry API enforces on every attribute value\n// (z.string().max(4096) in llm-gateway/types/telemetry-event.ts). The final\n// sanitized string — truncation marker included — MUST stay within this, or\n// the whole crash event fails Zod validation server-side and is silently\n// dropped. Reserve room for the marker so a truncated stack lands at exactly\n// MAX_STACK_LENGTH rather than overshooting it.\nconst MAX_STACK_LENGTH = 4096;\nconst STACK_TRUNCATION_MARKER = '\\n...[truncated]';\nconst MAX_MESSAGE_LENGTH = 1024;\nconst HOME = homedir();\nlet isCrashing = false;\n\n/**\n * Redact known credential patterns (Bearer tokens, sk_test_/sk_live_ keys,\n * raw JWTs). Shared by sanitizeStack and sanitizeMessage because Node echoes\n * `.message` into the leading `Error.stack` line, so secrets in messages also\n * surface in stacks.\n */\nfunction redactSecrets(s: string): string {\n return s\n .replace(/Bearer\\s+[A-Za-z0-9._-]+/g, 'Bearer <redacted>')\n .replace(/\\bsk_(test|live)_[A-Za-z0-9]+/g, 'sk_<redacted>')\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, '<jwt-redacted>');\n}\n\n/** Sanitize stack trace for telemetry: homedir, absolute-path collapse, secrets, truncation. */\nexport function sanitizeStack(stack: string | undefined): string {\n if (!stack) return '';\n let sanitized = stack.replaceAll(HOME, '~');\n // Collapse absolute paths to their leaf segment. POSIX and Windows separately —\n // Windows paths (C:\\...\\node_modules\\) bypass the POSIX regex and would\n // otherwise leak full local filesystem paths into telemetry.\n sanitized = sanitized\n .replace(/\\/[^\\s:]+\\/(node_modules|dist|src)\\//g, '$1/')\n .replace(/[A-Za-z]:\\\\[^\\s:]+\\\\(node_modules|dist|src)\\\\/g, '$1\\\\');\n sanitized = redactSecrets(sanitized);\n return sanitized.length > MAX_STACK_LENGTH\n ? sanitized.slice(0, MAX_STACK_LENGTH - STACK_TRUNCATION_MARKER.length) + STACK_TRUNCATION_MARKER\n : sanitized;\n}\n\n/** Sanitize an error message for telemetry (homedir, secrets, truncation). */\nexport function sanitizeMessage(msg: string | undefined): string {\n if (!msg) return '';\n const sanitized = redactSecrets(msg.replaceAll(HOME, '~'));\n return sanitized.length > MAX_MESSAGE_LENGTH ? sanitized.slice(0, MAX_MESSAGE_LENGTH) + '...[truncated]' : sanitized;\n}\n\n/**\n * Register global handlers for uncaughtException and unhandledRejection\n * that capture crash details before the process exits.\n *\n * Handlers are SYNCHRONOUS. Node does NOT await async uncaughtException handlers.\n * We queue the event synchronously; store-forward's process.on('exit') handler\n * persists it to disk. The next CLI invocation recovers and sends.\n */\nexport function installCrashReporter(): void {\n process.on('uncaughtException', (error) => {\n // A CliExit that reaches here escaped the normal lifecycle (e.g. thrown\n // from a fire-and-forget async event listener like `child.on('error')` in\n // dev.ts). It is an intentional exit, NOT a crash — record no crash event,\n // just honor the requested code.\n if (error instanceof CliExit) {\n process.exit(error.exitCode);\n }\n reportCrashSync(error);\n process.exit(1);\n });\n\n process.on('unhandledRejection', (reason) => {\n if (reason instanceof CliExit) {\n process.exit(reason.exitCode);\n }\n const error = reason instanceof Error ? reason : new Error(String(reason));\n reportCrashSync(error);\n process.exit(1);\n });\n}\n\nfunction reportCrashSync(error: Error): void {\n if (isCrashing) return;\n isCrashing = true;\n try {\n // captureUnhandledCrash sanitizes both message and stack at the analytics boundary.\n analytics.captureUnhandledCrash(error);\n } catch {\n // Telemetry must never prevent exit\n }\n}\n"]}
|
package/dist/utils/debug.d.ts
CHANGED
|
@@ -5,4 +5,5 @@ export declare function logWarn(...args: unknown[]): void;
|
|
|
5
5
|
export declare function logVisibleWarn(...args: unknown[]): void;
|
|
6
6
|
export declare function logError(...args: unknown[]): void;
|
|
7
7
|
export declare function debug(...args: unknown[]): void;
|
|
8
|
+
export declare function isDebugEnabled(): boolean;
|
|
8
9
|
export declare function enableDebugLogs(): void;
|
package/dist/utils/debug.js
CHANGED
|
@@ -91,11 +91,14 @@ export function logError(...args) {
|
|
|
91
91
|
writeLog('ERROR', '❌', args);
|
|
92
92
|
}
|
|
93
93
|
export function debug(...args) {
|
|
94
|
-
if (!
|
|
94
|
+
if (!isDebugEnabled())
|
|
95
95
|
return;
|
|
96
96
|
const msg = args.map((a) => prepareMessage(a)).join(' ');
|
|
97
97
|
clack.log.info(chalk.dim(msg));
|
|
98
98
|
}
|
|
99
|
+
export function isDebugEnabled() {
|
|
100
|
+
return debugEnabled && !isJsonMode();
|
|
101
|
+
}
|
|
99
102
|
export function enableDebugLogs() {
|
|
100
103
|
debugEnabled = true;
|
|
101
104
|
}
|
package/dist/utils/debug.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"debug.js","sourceRoot":"","sources":["../../src/utils/debug.ts"],"names":[],"mappings":"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","sourcesContent":["import { appendFileSync, existsSync, mkdirSync, readdirSync, unlinkSync } from 'fs';\nimport { join } from 'path';\nimport { homedir } from 'os';\nimport chalk from 'chalk';\nimport { prepareMessage } from './logging.js';\nimport { redactCredentials } from './redact.js';\nimport clack from './clack.js';\nimport { isJsonMode } from './output.js';\n\nlet debugEnabled = false;\nlet sessionLogPath: string | null = null;\n\nconst LOG_DIR = join(homedir(), '.workos', 'logs');\nconst MAX_LOG_FILES = 10;\n\nfunction ensureLogDir(): string {\n if (!existsSync(LOG_DIR)) {\n mkdirSync(LOG_DIR, { recursive: true });\n }\n return LOG_DIR;\n}\n\nfunction getSafeTimestamp(): string {\n return new Date().toISOString().replace(/:/g, '-');\n}\n\nfunction rotateLogFiles(): void {\n try {\n const dir = ensureLogDir();\n const files = readdirSync(dir)\n .filter((f) => f.startsWith('workos-') && f.endsWith('.log'))\n .sort();\n\n const toDelete = files.slice(0, Math.max(0, files.length - MAX_LOG_FILES + 1));\n for (const file of toDelete) {\n try {\n unlinkSync(join(dir, file));\n } catch {\n // Ignore deletion failures\n }\n }\n } catch {\n // Ignore rotation failures\n }\n}\n\nexport function initLogFile(): void {\n try {\n rotateLogFiles();\n const dir = ensureLogDir();\n const timestamp = getSafeTimestamp();\n sessionLogPath = join(dir, `workos-${timestamp}.log`);\n\n const header = `${'='.repeat(60)}\\nWorkOS AuthKit Installer Run: ${new Date().toISOString()}\\n${'='.repeat(60)}\\n`;\n appendFileSync(sessionLogPath, header);\n } catch {\n sessionLogPath = null;\n }\n}\n\nexport function getLogFilePath(): string | null {\n return sessionLogPath;\n}\n\nfunction writeLog(level: 'INFO' | 'WARN' | 'ERROR', emoji: string, args: unknown[]): string {\n const redactedArgs = args.map((a) => (typeof a === 'object' && a !== null ? redactCredentials(a) : a));\n const msg = redactedArgs.map((a) => prepareMessage(a)).join(' ');\n\n // Write to console if debug enabled\n if (debugEnabled && !isJsonMode()) {\n const color = level === 'ERROR' ? chalk.red : level === 'WARN' ? chalk.yellow : chalk.dim;\n clack.log.info(color(`${emoji} ${msg}`));\n }\n\n // Write to log file\n if (sessionLogPath) {\n try {\n const timestamp = new Date().toISOString();\n appendFileSync(sessionLogPath, `[${timestamp}] ${emoji} ${level}: ${msg}\\n`);\n } catch {\n // Ignore write failures\n }\n }\n\n return msg;\n}\n\nexport function logInfo(...args: unknown[]): void {\n writeLog('INFO', 'ℹ️ ', args);\n}\n\nexport function logWarn(...args: unknown[]): void {\n writeLog('WARN', '⚠️ ', args);\n}\n\nexport function logVisibleWarn(...args: unknown[]): void {\n const msg = writeLog('WARN', '⚠️ ', args);\n if (!debugEnabled && !isJsonMode()) {\n console.error(chalk.yellow(`⚠️ ${msg}`));\n }\n}\n\nexport function logError(...args: unknown[]): void {\n writeLog('ERROR', '❌', args);\n}\n\nexport function debug(...args: unknown[]): void {\n if (!isDebugEnabled()) return;\n const msg = args.map((a) => prepareMessage(a)).join(' ');\n clack.log.info(chalk.dim(msg));\n}\n\nexport function isDebugEnabled(): boolean {\n return debugEnabled && !isJsonMode();\n}\n\nexport function enableDebugLogs(): void {\n debugEnabled = true;\n}\n"]}
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* 4 = Authentication required
|
|
8
8
|
*/
|
|
9
9
|
import { type StructuredError } from './output.js';
|
|
10
|
+
import type { TerminationReason } from './telemetry-types.js';
|
|
10
11
|
export declare const ExitCode: {
|
|
11
12
|
readonly SUCCESS: 0;
|
|
12
13
|
readonly GENERAL_ERROR: 1;
|
|
@@ -14,6 +15,10 @@ export declare const ExitCode: {
|
|
|
14
15
|
readonly AUTH_REQUIRED: 4;
|
|
15
16
|
};
|
|
16
17
|
export type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];
|
|
18
|
+
export declare function resolveErrorCode(code: string): {
|
|
19
|
+
reason: TerminationReason;
|
|
20
|
+
exit: ExitCodeValue;
|
|
21
|
+
};
|
|
17
22
|
/** Exit with a specific code, optionally writing a structured error first. */
|
|
18
23
|
export declare function exitWithCode(code: ExitCodeValue, error?: StructuredError): never;
|
|
19
24
|
/**
|
package/dist/utils/exit-codes.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* 2 = Cancelled (e.g., Ctrl+C, user cancelled prompt)
|
|
7
7
|
* 4 = Authentication required
|
|
8
8
|
*/
|
|
9
|
+
import { CliExit } from './cli-exit.js';
|
|
9
10
|
import { outputError } from './output.js';
|
|
10
11
|
import { formatWorkOSCommand } from './command-invocation.js';
|
|
11
12
|
import { authLoginRecovery } from './recovery-hints.js';
|
|
@@ -16,12 +17,40 @@ export const ExitCode = {
|
|
|
16
17
|
CANCELLED: 2,
|
|
17
18
|
AUTH_REQUIRED: 4,
|
|
18
19
|
};
|
|
20
|
+
const ERROR_CODE_MAP = {
|
|
21
|
+
auth_required: { reason: 'auth_required', exit: ExitCode.AUTH_REQUIRED },
|
|
22
|
+
// resolveApiKey() emits `no_api_key` when no key is configured; semantically
|
|
23
|
+
// an auth failure, so it must not fall through to `validation_error`.
|
|
24
|
+
no_api_key: { reason: 'auth_required', exit: ExitCode.AUTH_REQUIRED },
|
|
25
|
+
cancelled: { reason: 'cancelled', exit: ExitCode.CANCELLED },
|
|
26
|
+
};
|
|
27
|
+
export function resolveErrorCode(code) {
|
|
28
|
+
const mapped = ERROR_CODE_MAP[code];
|
|
29
|
+
if (mapped)
|
|
30
|
+
return mapped;
|
|
31
|
+
if (code.startsWith('http_')) {
|
|
32
|
+
return { reason: 'api_error', exit: ExitCode.GENERAL_ERROR };
|
|
33
|
+
}
|
|
34
|
+
return { reason: 'validation_error', exit: ExitCode.GENERAL_ERROR };
|
|
35
|
+
}
|
|
36
|
+
function reasonForExitCode(code) {
|
|
37
|
+
if (code === ExitCode.AUTH_REQUIRED)
|
|
38
|
+
return 'auth_required';
|
|
39
|
+
if (code === ExitCode.CANCELLED)
|
|
40
|
+
return 'cancelled';
|
|
41
|
+
if (code === ExitCode.SUCCESS)
|
|
42
|
+
return 'success';
|
|
43
|
+
return 'validation_error';
|
|
44
|
+
}
|
|
19
45
|
/** Exit with a specific code, optionally writing a structured error first. */
|
|
20
46
|
export function exitWithCode(code, error) {
|
|
21
47
|
if (error) {
|
|
22
48
|
outputError(error);
|
|
23
49
|
}
|
|
24
|
-
|
|
50
|
+
throw new CliExit(code, {
|
|
51
|
+
reason: reasonForExitCode(code),
|
|
52
|
+
errorCode: error?.code,
|
|
53
|
+
});
|
|
25
54
|
}
|
|
26
55
|
/**
|
|
27
56
|
* Convenience: exit with code 4 and auth-required error.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/utils/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,WAAW,EAAwB,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;
|
|
1
|
+
{"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/utils/exit-codes.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,eAAe,CAAC;AACxC,OAAO,EAAE,WAAW,EAAwB,MAAM,aAAa,CAAC;AAChE,OAAO,EAAE,mBAAmB,EAAE,MAAM,yBAAyB,CAAC;AAC9D,OAAO,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAG3D,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,OAAO,EAAE,CAAC;IACV,aAAa,EAAE,CAAC;IAChB,SAAS,EAAE,CAAC;IACZ,aAAa,EAAE,CAAC;CACR,CAAC;AAIX,MAAM,cAAc,GAAuE;IACzF,aAAa,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,EAAE;IACxE,6EAA6E;IAC7E,sEAAsE;IACtE,UAAU,EAAE,EAAE,MAAM,EAAE,eAAe,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,EAAE;IACrE,SAAS,EAAE,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC,SAAS,EAAE;CAC7D,CAAC;AAEF,MAAM,UAAU,gBAAgB,CAAC,IAAY;IAI3C,MAAM,MAAM,GAAG,cAAc,CAAC,IAAI,CAAC,CAAC;IACpC,IAAI,MAAM;QAAE,OAAO,MAAM,CAAC;IAC1B,IAAI,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7B,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,EAAE,CAAC;IAC/D,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,kBAAkB,EAAE,IAAI,EAAE,QAAQ,CAAC,aAAa,EAAE,CAAC;AACtE,CAAC;AAED,SAAS,iBAAiB,CAAC,IAAmB;IAC5C,IAAI,IAAI,KAAK,QAAQ,CAAC,aAAa;QAAE,OAAO,eAAe,CAAC;IAC5D,IAAI,IAAI,KAAK,QAAQ,CAAC,SAAS;QAAE,OAAO,WAAW,CAAC;IACpD,IAAI,IAAI,KAAK,QAAQ,CAAC,OAAO;QAAE,OAAO,SAAS,CAAC;IAChD,OAAO,kBAAkB,CAAC;AAC5B,CAAC;AAED,8EAA8E;AAC9E,MAAM,UAAU,YAAY,CAAC,IAAmB,EAAE,KAAuB;IACvE,IAAI,KAAK,EAAE,CAAC;QACV,WAAW,CAAC,KAAK,CAAC,CAAC;IACrB,CAAC;IACD,MAAM,IAAI,OAAO,CAAC,IAAI,EAAE;QACtB,MAAM,EAAE,iBAAiB,CAAC,IAAI,CAAC;QAC/B,SAAS,EAAE,KAAK,EAAE,IAAI;KACvB,CAAC,CAAC;AACL,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,oBAAoB,CAAC,OAAgB,EAAE,OAAoD;IACzG,MAAM,IAAI,GAAG,kBAAkB,EAAE,CAAC,IAAI,CAAC;IACvC,YAAY,CAAC,QAAQ,CAAC,aAAa,EAAE;QACnC,IAAI,EAAE,eAAe;QACrB,OAAO,EACL,OAAO;YACP,4BAA4B,mBAAmB,CAAC,YAAY,CAAC,uDAAuD;QACtH,QAAQ,EAAE,OAAO,EAAE,QAAQ,IAAI,iBAAiB,CAAC,EAAE,IAAI,EAAE,CAAC;KAC3D,CAAC,CAAC;AACL,CAAC","sourcesContent":["/**\n * Standardized exit codes following gh CLI convention.\n *\n * 0 = Success\n * 1 = General error\n * 2 = Cancelled (e.g., Ctrl+C, user cancelled prompt)\n * 4 = Authentication required\n */\n\nimport { CliExit } from './cli-exit.js';\nimport { outputError, type StructuredError } from './output.js';\nimport { formatWorkOSCommand } from './command-invocation.js';\nimport { authLoginRecovery } from './recovery-hints.js';\nimport { getInteractionMode } from './interaction-mode.js';\nimport type { TerminationReason } from './telemetry-types.js';\n\nexport const ExitCode = {\n SUCCESS: 0,\n GENERAL_ERROR: 1,\n CANCELLED: 2,\n AUTH_REQUIRED: 4,\n} as const;\n\nexport type ExitCodeValue = (typeof ExitCode)[keyof typeof ExitCode];\n\nconst ERROR_CODE_MAP: Record<string, { reason: TerminationReason; exit: ExitCodeValue }> = {\n auth_required: { reason: 'auth_required', exit: ExitCode.AUTH_REQUIRED },\n // resolveApiKey() emits `no_api_key` when no key is configured; semantically\n // an auth failure, so it must not fall through to `validation_error`.\n no_api_key: { reason: 'auth_required', exit: ExitCode.AUTH_REQUIRED },\n cancelled: { reason: 'cancelled', exit: ExitCode.CANCELLED },\n};\n\nexport function resolveErrorCode(code: string): {\n reason: TerminationReason;\n exit: ExitCodeValue;\n} {\n const mapped = ERROR_CODE_MAP[code];\n if (mapped) return mapped;\n if (code.startsWith('http_')) {\n return { reason: 'api_error', exit: ExitCode.GENERAL_ERROR };\n }\n return { reason: 'validation_error', exit: ExitCode.GENERAL_ERROR };\n}\n\nfunction reasonForExitCode(code: ExitCodeValue): TerminationReason {\n if (code === ExitCode.AUTH_REQUIRED) return 'auth_required';\n if (code === ExitCode.CANCELLED) return 'cancelled';\n if (code === ExitCode.SUCCESS) return 'success';\n return 'validation_error';\n}\n\n/** Exit with a specific code, optionally writing a structured error first. */\nexport function exitWithCode(code: ExitCodeValue, error?: StructuredError): never {\n if (error) {\n outputError(error);\n }\n throw new CliExit(code, {\n reason: reasonForExitCode(code),\n errorCode: error?.code,\n });\n}\n\n/**\n * Convenience: exit with code 4 and auth-required error.\n *\n * Recovery hints are inferred from interaction mode unless explicitly provided.\n */\nexport function exitWithAuthRequired(message?: string, options?: { recovery?: StructuredError['recovery'] }): never {\n const mode = getInteractionMode().mode;\n exitWithCode(ExitCode.AUTH_REQUIRED, {\n code: 'auth_required',\n message:\n message ??\n `Not authenticated. Run \\`${formatWorkOSCommand('auth login')}\\` in an interactive terminal, or set WORKOS_API_KEY.`,\n recovery: options?.recovery ?? authLoginRecovery({ mode }),\n });\n}\n"]}
|
|
@@ -49,4 +49,10 @@ export declare function extractHelpJsonCommand(argv: string[]): string | undefin
|
|
|
49
49
|
* @param subcommand - Optional command name to return a subtree for (e.g. "env").
|
|
50
50
|
* Returns full tree if omitted or if command not found.
|
|
51
51
|
*/
|
|
52
|
+
/**
|
|
53
|
+
* Top-level command names (first token of each registered command). Used by
|
|
54
|
+
* telemetry to recognise real commands without trusting arbitrary argv tokens
|
|
55
|
+
* (so option values / secrets are never recorded as a command name).
|
|
56
|
+
*/
|
|
57
|
+
export declare function getTopLevelCommandNames(): string[];
|
|
52
58
|
export declare function buildCommandTree(subcommand?: string): HelpOutput | CommandSchema;
|
package/dist/utils/help-json.js
CHANGED
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
* so we maintain a parallel typed registry.
|
|
7
7
|
*/
|
|
8
8
|
import { getVersion } from '../lib/settings.js';
|
|
9
|
+
import { COMMAND_ALIASES } from '../lib/command-aliases.js';
|
|
9
10
|
// ---------------------------------------------------------------------------
|
|
10
11
|
// Shared option fragments (mirrors bin.ts shared option objects)
|
|
11
12
|
// ---------------------------------------------------------------------------
|
|
@@ -68,6 +69,15 @@ const commands = [
|
|
|
68
69
|
description: 'Show current authentication status',
|
|
69
70
|
options: [insecureStorageOpt],
|
|
70
71
|
},
|
|
72
|
+
{
|
|
73
|
+
name: 'telemetry',
|
|
74
|
+
description: 'Manage telemetry collection (opt-out, opt-in, status)',
|
|
75
|
+
commands: [
|
|
76
|
+
{ name: 'opt-out', description: 'Disable telemetry collection (persists across runs)' },
|
|
77
|
+
{ name: 'opt-in', description: 'Re-enable telemetry collection' },
|
|
78
|
+
{ name: 'status', description: 'Show whether telemetry is enabled and why' },
|
|
79
|
+
],
|
|
80
|
+
},
|
|
71
81
|
{
|
|
72
82
|
name: 'skills',
|
|
73
83
|
description: 'Manage WorkOS skills for coding agents (Claude Code, Codex, Cursor, Goose)',
|
|
@@ -969,29 +979,61 @@ const commands = [
|
|
|
969
979
|
{ name: 'list', description: 'List vault objects', options: [...paginationOpts] },
|
|
970
980
|
{
|
|
971
981
|
name: 'get',
|
|
972
|
-
description: 'Get a vault object',
|
|
982
|
+
description: 'Get a vault object (metadata only; use --decrypt to include value)',
|
|
973
983
|
positionals: [{ name: 'id', type: 'string', description: 'Object ID', required: true }],
|
|
984
|
+
options: [
|
|
985
|
+
{
|
|
986
|
+
name: 'decrypt',
|
|
987
|
+
type: 'boolean',
|
|
988
|
+
description: 'Include the decrypted secret value',
|
|
989
|
+
required: false,
|
|
990
|
+
default: false,
|
|
991
|
+
hidden: false,
|
|
992
|
+
},
|
|
993
|
+
],
|
|
974
994
|
},
|
|
975
995
|
{
|
|
976
996
|
name: 'get-by-name',
|
|
977
|
-
description: 'Get a vault object by name',
|
|
997
|
+
description: 'Get a vault object by name (metadata only; use --decrypt to include value)',
|
|
978
998
|
positionals: [{ name: 'name', type: 'string', description: 'Object name', required: true }],
|
|
999
|
+
options: [
|
|
1000
|
+
{
|
|
1001
|
+
name: 'decrypt',
|
|
1002
|
+
type: 'boolean',
|
|
1003
|
+
description: 'Include the decrypted secret value',
|
|
1004
|
+
required: false,
|
|
1005
|
+
default: false,
|
|
1006
|
+
hidden: false,
|
|
1007
|
+
},
|
|
1008
|
+
],
|
|
979
1009
|
},
|
|
980
1010
|
{
|
|
981
1011
|
name: 'create',
|
|
982
|
-
description: 'Create a vault object',
|
|
1012
|
+
description: 'Create a vault object (reads value from stdin when --value is omitted or -)',
|
|
983
1013
|
options: [
|
|
984
1014
|
{ name: 'name', type: 'string', description: 'Object name', required: true, hidden: false },
|
|
985
|
-
{
|
|
986
|
-
|
|
1015
|
+
{
|
|
1016
|
+
name: 'value',
|
|
1017
|
+
type: 'string',
|
|
1018
|
+
description: 'Secret value (omit or use - to read from stdin)',
|
|
1019
|
+
required: false,
|
|
1020
|
+
hidden: false,
|
|
1021
|
+
},
|
|
1022
|
+
{ name: 'org', type: 'string', description: 'Organization ID (required)', required: true, hidden: false },
|
|
987
1023
|
],
|
|
988
1024
|
},
|
|
989
1025
|
{
|
|
990
1026
|
name: 'update',
|
|
991
|
-
description: 'Update a vault object',
|
|
1027
|
+
description: 'Update a vault object (reads value from stdin when --value is omitted or -)',
|
|
992
1028
|
positionals: [{ name: 'id', type: 'string', description: 'Object ID', required: true }],
|
|
993
1029
|
options: [
|
|
994
|
-
{
|
|
1030
|
+
{
|
|
1031
|
+
name: 'value',
|
|
1032
|
+
type: 'string',
|
|
1033
|
+
description: 'New value (omit or use - to read from stdin)',
|
|
1034
|
+
required: false,
|
|
1035
|
+
hidden: false,
|
|
1036
|
+
},
|
|
995
1037
|
{ name: 'version-check', type: 'string', description: 'Version check ID', required: false, hidden: false },
|
|
996
1038
|
],
|
|
997
1039
|
},
|
|
@@ -1010,6 +1052,34 @@ const commands = [
|
|
|
1010
1052
|
description: 'List vault object versions',
|
|
1011
1053
|
positionals: [{ name: 'id', type: 'string', description: 'Object ID', required: true }],
|
|
1012
1054
|
},
|
|
1055
|
+
{
|
|
1056
|
+
name: 'run',
|
|
1057
|
+
description: 'Run a command with Vault secrets injected as environment variables',
|
|
1058
|
+
options: [
|
|
1059
|
+
{
|
|
1060
|
+
name: 'secret',
|
|
1061
|
+
type: 'array',
|
|
1062
|
+
description: 'Map a vault object to an env var: ENV_VAR=vault-name (repeatable)',
|
|
1063
|
+
required: true,
|
|
1064
|
+
hidden: false,
|
|
1065
|
+
},
|
|
1066
|
+
{
|
|
1067
|
+
name: 'env',
|
|
1068
|
+
type: 'string',
|
|
1069
|
+
description: 'Environment name to read API key from (defaults to active)',
|
|
1070
|
+
required: false,
|
|
1071
|
+
hidden: false,
|
|
1072
|
+
},
|
|
1073
|
+
{
|
|
1074
|
+
name: 'dry-run',
|
|
1075
|
+
type: 'boolean',
|
|
1076
|
+
description: 'Print which secrets would be injected, no fetch',
|
|
1077
|
+
required: false,
|
|
1078
|
+
default: false,
|
|
1079
|
+
hidden: false,
|
|
1080
|
+
},
|
|
1081
|
+
],
|
|
1082
|
+
},
|
|
1013
1083
|
],
|
|
1014
1084
|
},
|
|
1015
1085
|
{
|
|
@@ -1301,10 +1371,9 @@ const globalOptions = [
|
|
|
1301
1371
|
// ---------------------------------------------------------------------------
|
|
1302
1372
|
// Public API
|
|
1303
1373
|
// ---------------------------------------------------------------------------
|
|
1304
|
-
const commandAliases = { org: 'organization' };
|
|
1305
1374
|
const helpJsonCommandNames = new Set([
|
|
1306
1375
|
...commands.map((command) => command.name.split(' ')[0]),
|
|
1307
|
-
...Object.keys(
|
|
1376
|
+
...Object.keys(COMMAND_ALIASES),
|
|
1308
1377
|
]);
|
|
1309
1378
|
/**
|
|
1310
1379
|
* Extract the requested command from raw argv before yargs parses --help.
|
|
@@ -1323,7 +1392,7 @@ export function extractHelpJsonCommand(argv) {
|
|
|
1323
1392
|
continue;
|
|
1324
1393
|
}
|
|
1325
1394
|
if (!arg.startsWith('-') && helpJsonCommandNames.has(arg)) {
|
|
1326
|
-
return
|
|
1395
|
+
return COMMAND_ALIASES[arg] ?? arg;
|
|
1327
1396
|
}
|
|
1328
1397
|
}
|
|
1329
1398
|
return undefined;
|
|
@@ -1334,6 +1403,14 @@ export function extractHelpJsonCommand(argv) {
|
|
|
1334
1403
|
* @param subcommand - Optional command name to return a subtree for (e.g. "env").
|
|
1335
1404
|
* Returns full tree if omitted or if command not found.
|
|
1336
1405
|
*/
|
|
1406
|
+
/**
|
|
1407
|
+
* Top-level command names (first token of each registered command). Used by
|
|
1408
|
+
* telemetry to recognise real commands without trusting arbitrary argv tokens
|
|
1409
|
+
* (so option values / secrets are never recorded as a command name).
|
|
1410
|
+
*/
|
|
1411
|
+
export function getTopLevelCommandNames() {
|
|
1412
|
+
return commands.map((c) => c.name.split(' ')[0]);
|
|
1413
|
+
}
|
|
1337
1414
|
export function buildCommandTree(subcommand) {
|
|
1338
1415
|
if (subcommand) {
|
|
1339
1416
|
const match = commands.find((c) => c.name === subcommand);
|