@certen.io/cli 0.3.0 → 0.4.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/CHANGELOG.md ADDED
@@ -0,0 +1,55 @@
1
+ # Changelog — @certen.io/cli
2
+
3
+ ## 0.4.0 — `--json` is a machine contract
4
+
5
+ Adds a stable, tested output contract for scripts and AI agents. **Human output is unchanged**: if
6
+ you do not pass `--json`, this release behaves exactly as 0.3.1 did, with one exception noted under
7
+ Breaking.
8
+
9
+ Before this, every failure exited `1` and explained itself in English on stderr. An automated caller
10
+ could not distinguish "you passed a malformed address" from "the gateway is down" without parsing
11
+ prose — and those want opposite responses. One is a bug to fix; the other is worth retrying. For a
12
+ CLI that authorizes cross-chain execution against real funds, guessing wrong is expensive in a way
13
+ that is not recoverable.
14
+
15
+ The full specification is [docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md), enforced by
16
+ `test/conformance.test.ts`, which runs the built binary as a subprocess and checks the real process's
17
+ stdout and exit code.
18
+
19
+ ### Added
20
+
21
+ - **Global `--json`**, accepted anywhere in the argument list — `certen --json tx status X` and
22
+ `certen tx status X --json` are identical. It is resolved before argument parsing, so it applies
23
+ even to failures that occur while resolving credentials.
24
+ - **One JSON envelope on stdout and nothing else.** `{"ok":true,"data":…}` or
25
+ `{"ok":false,"error":{"code","message","retryable","status?","requestId?"}}`. A command producing
26
+ several payloads emits an array in `data`; one producing none emits `"data":null`. stdout is never
27
+ empty and never carries two concatenated objects. All human-facing text moves to stderr.
28
+ - **Meaningful exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway
29
+ unreachable. `3` guarantees nothing was submitted, so a retry cannot double-execute.
30
+ - **`error.retryable`**, taken from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
31
+ hand an automated caller the identical retry decision.
32
+ - **`certen --help --json`** returns the entire command tree — every command, argument, flag and exit
33
+ code — in one call, instead of scraping help text once per subcommand.
34
+
35
+ ### Fixed
36
+
37
+ - **Usage errors on subcommands bypassed error handling entirely.** `exitOverride()` is not inherited
38
+ by commander subcommands, so a missing required flag (`certen identity create` with no `--name`)
39
+ called `process.exit(1)` inside commander: no envelope was emitted, stdout stayed empty, and a
40
+ usage error was indistinguishable from a failed request. It is now applied to every command in the
41
+ tree.
42
+
43
+ ### Breaking
44
+
45
+ - **"No API key configured" now exits `2` instead of `1`.** It is a usage error: nothing was sent,
46
+ and retrying cannot help. The same applies to a config file with unsafe permissions and to a
47
+ missing keyring backend. Scripts treating any non-zero exit as failure are unaffected; scripts
48
+ testing specifically for `-eq 1` need updating.
49
+
50
+ ### Note
51
+
52
+ `output: "json"` in `~/.certen/config.json` is **not** this contract. That setting predates the
53
+ envelope and makes commands print their raw payload — no `ok`, no `error`, no exit-code guarantees.
54
+ It is kept for backward compatibility. Automated callers should pass `--json` explicitly rather than
55
+ depend on a machine's local config, which they cannot see.
package/README.md CHANGED
@@ -1,132 +1,160 @@
1
- # `@certen.io/cli`
2
-
3
- The `certen` command line for the [CERTEN Gateway](https://gateway.kompendium.co/reference) —
4
- proof-gated cross-chain execution on Accumulate.
5
-
6
- ```bash
7
- npm install -g @certen.io/cli
8
- ```
9
-
10
- ## Five minutes, start to finish
11
-
12
- ```bash
13
- # 1. A key. Generated here, encrypted here, and it never leaves this machine.
14
- certen keys generate --name dev
15
-
16
- # 2. An API key from the portal at https://gateway.kompendium.co/portal
17
- certen auth login --api-key ck_live_...
18
-
19
- # 3. An identity that your key controls.
20
- certen identity create --name my-org --sign-with dev
21
-
22
- # 4. Watch it provision (~20s). Wait for status=active AND can_sign=true.
23
- certen identity get <id>
24
- ```
25
-
26
- That is the whole onboarding path. Step 3 is the one worth understanding: `--sign-with` derives
27
- the `public_key` and `public_key_hash` from your local key, so the ADI's key page is bound to a
28
- key only you hold.
29
-
30
- ## Your key never leaves this machine
31
-
32
- `certen keys generate` creates an Ed25519 key, encrypts it with a passphrase (scrypt + AES-256-GCM),
33
- and writes it to `~/.certen/keys/<name>.json` with `0600` permissions. The CLI sends **signatures**
34
- to the gateway. It never sends a private key, and there is no code path that could.
35
-
36
- ```bash
37
- certen keys generate --name dev # prompts for a passphrase (confirmed)
38
- certen keys generate --name ci --no-passphrase # unencrypted; file permissions only
39
- certen keys list # metadata only never decrypts
40
- certen keys show dev
41
- certen keys verify dev # proves the key decrypts and signs correctly
42
- certen keys sign --name dev --hash <hex> # print a signature, send nothing
43
- certen keys delete dev --yes
44
- certen keys path
45
- ```
46
-
47
- Set `CERTEN_KEY_PASSPHRASE` to skip the prompt in CI. When it is set and there is no TTY, the CLI
48
- uses it; when neither is available it fails with an explanation rather than hanging on a prompt
49
- nobody can see.
50
-
51
- **`certen keys sign` sends nothing anywhere.** It is the air-gapped path: generate on one machine,
52
- carry the hash to it, carry the signature back.
53
-
54
- ## Signing a transaction
55
-
56
- The one-step form opens the intent, signs the returned hash, and submits the signature:
57
-
58
- ```bash
59
- certen tx create --identity <uuid> --to-chain ethereum-sepolia \
60
- --to 0xRecipient --amount 1000000000000000 --sign-with dev
61
- ```
62
-
63
- Or drive the steps yourself — useful when the signer is an HSM, another machine, or your own
64
- policy engine:
65
-
66
- ```bash
67
- certen tx create --identity <uuid> ... # returns signing_data.hash_to_sign
68
- certen keys sign --name dev --hash <hash> # or your HSM
69
- certen tx sign <intent-id> --signature <sig> --public-key <pub>
70
- ```
71
-
72
- `--signature`/`--public-key` remain first-class. `--sign-with` is a convenience, not a replacement.
73
-
74
- ## Multi-party approvals
75
-
76
- ```bash
77
- certen pending list
78
- certen pending sign <id> --identity <adi> --vote approve
79
- certen pending submit <request-id> --sign-with dev --hash <hash>
80
- ```
81
-
82
- `--vote` takes `approve`, `reject`, or `abstain` — lowercase strings. Not `accept`, and not a
83
- number.
84
-
85
- ## Everything else
86
-
87
- ```bash
88
- certen identity get <id> | link-chain <id> --chain <chain>
89
- certen portfolio # balances across every identity and chain
90
- certen tx status <id> | list
91
- certen governance add-delegate | set-threshold
92
- certen admin api-keys list | create | rotate | revoke
93
- certen admin audit-log | usage
94
- ```
95
-
96
- Run `certen <group> --help` for the flags on any of them.
97
-
98
- ## Configuration
99
-
100
- | | |
101
- |---|---|
102
- | `CERTEN_API_KEY` | API key. Always wins, so CI never touches the keyring or config file. |
103
- | `CERTEN_API_URL` | Gateway base URL. Defaults to `https://gateway.kompendium.co`. |
104
- | `CERTEN_KEY_PASSPHRASE` | Passphrase for local signing keys. |
105
-
106
- `certen auth login` stores the API key in your OS keyring by default, or in
107
- `~/.certen/config.json` at `0600` with `--no-keyring`.
108
-
109
- ## Things that will bite you
110
-
111
- **Identity creation is asynchronous.** `identity create` returns `202` and provisioning continues.
112
- Poll until the status is terminal, and check `can_sign` — it derives from the on-chain key page, so
113
- it can read `true` while the status is still `creating`.
114
-
115
- **A proof cycle takes 60–110 seconds.** Real validator work, not a tunable delay. Do not wrap it in
116
- a 30-second timeout.
117
-
118
- **Sign the bytes, not the text.** If you are producing signatures outside this CLI: sign the raw
119
- bytes of the hash, do not hash it again, and do not sign the ASCII of the hex string. All three
120
- mistakes produce a well-formed 128-hex signature the gateway rejects. `certen keys sign` handles
121
- this for you.
122
-
123
- ## Documentation
124
-
125
- The [live API reference](https://gateway.kompendium.co/reference) is generated from the running
126
- gateway and is authoritative. Task-shaped guides live in
127
- [the SDK repo](https://github.com/certenIO/certen-sdk): onboarding an identity, external signing,
128
- proof-gating a contract call, M-of-N panels, and verifying a proof.
129
-
130
- ## License
131
-
132
- MIT
1
+ # `@certen.io/cli`
2
+
3
+ The `certen` command line for the [CERTEN Gateway](https://gateway.kompendium.co/reference) —
4
+ proof-gated cross-chain execution on Accumulate.
5
+
6
+ **Docs: <https://docs.kompendium.co>** · **Get an API key: <https://gateway.kompendium.co/portal>**
7
+
8
+ ```bash
9
+ npm install -g @certen.io/cli
10
+ ```
11
+
12
+ ## Five minutes, start to finish
13
+
14
+ ```bash
15
+ # 1. A key. Generated here, encrypted here, and it never leaves this machine.
16
+ certen keys generate --name dev
17
+
18
+ # 2. An API key from the portal at https://gateway.kompendium.co/portal
19
+ certen auth login --api-key ck_live_...
20
+
21
+ # 3. An identity that your key controls.
22
+ certen identity create --name my-org --sign-with dev
23
+
24
+ # 4. Watch it provision (~20s). Wait for status=active AND can_sign=true.
25
+ certen identity get <id>
26
+ ```
27
+
28
+ That is the whole onboarding path. Step 3 is the one worth understanding: `--sign-with` derives
29
+ the `public_key` and `public_key_hash` from your local key, so the ADI's key page is bound to a
30
+ key only you hold.
31
+
32
+ ## Your key never leaves this machine
33
+
34
+ `certen keys generate` creates an Ed25519 key, encrypts it with a passphrase (scrypt + AES-256-GCM),
35
+ and writes it to `~/.certen/keys/<name>.json` with `0600` permissions. The CLI sends **signatures**
36
+ to the gateway. It never sends a private key, and there is no code path that could.
37
+
38
+ ```bash
39
+ certen keys generate --name dev # prompts for a passphrase (confirmed)
40
+ certen keys generate --name ci --no-passphrase # unencrypted; file permissions only
41
+ certen keys list # metadata only never decrypts
42
+ certen keys show dev
43
+ certen keys verify dev # proves the key decrypts and signs correctly
44
+ certen keys sign --name dev --hash <hex> # print a signature, send nothing
45
+ certen keys delete dev --yes
46
+ certen keys path
47
+ ```
48
+
49
+ Set `CERTEN_KEY_PASSPHRASE` to skip the prompt in CI. When it is set and there is no TTY, the CLI
50
+ uses it; when neither is available it fails with an explanation rather than hanging on a prompt
51
+ nobody can see.
52
+
53
+ **`certen keys sign` sends nothing anywhere.** It is the air-gapped path: generate on one machine,
54
+ carry the hash to it, carry the signature back.
55
+
56
+ ## Signing a transaction
57
+
58
+ The one-step form opens the intent, signs the returned hash, and submits the signature:
59
+
60
+ ```bash
61
+ certen tx create --identity <uuid> --to-chain ethereum-sepolia \
62
+ --to 0xRecipient --amount 1000000000000000 --sign-with dev
63
+ ```
64
+
65
+ Or drive the steps yourself — useful when the signer is an HSM, another machine, or your own
66
+ policy engine:
67
+
68
+ ```bash
69
+ certen tx create --identity <uuid> ... # returns signing_data.hash_to_sign
70
+ certen keys sign --name dev --hash <hash> # or your HSM
71
+ certen tx sign <intent-id> --signature <sig> --public-key <pub>
72
+ ```
73
+
74
+ `--signature`/`--public-key` remain first-class. `--sign-with` is a convenience, not a replacement.
75
+
76
+ ## Multi-party approvals
77
+
78
+ ```bash
79
+ certen pending list
80
+ certen pending sign <id> --identity <adi> --vote approve
81
+ certen pending submit <request-id> --sign-with dev --hash <hash>
82
+ ```
83
+
84
+ `--vote` takes `approve`, `reject`, or `abstain` — lowercase strings. Not `accept`, and not a
85
+ number.
86
+
87
+ ## Everything else
88
+
89
+ ```bash
90
+ certen identity get <id> | link-chain <id> --chain <chain>
91
+ certen portfolio # balances across every identity and chain
92
+ certen tx status <id> | list
93
+ certen governance add-delegate | set-threshold
94
+ certen admin api-keys list | create | rotate | revoke
95
+ certen admin audit-log | usage
96
+ ```
97
+
98
+ Run `certen <group> --help` for the flags on any of them.
99
+
100
+ ## Scripting and AI agents: `--json`
101
+
102
+ `--json` turns the CLI into a machine interface. It is a contract, documented in full in
103
+ [docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md) and enforced by a conformance suite.
104
+
105
+ ```bash
106
+ certen --json tx status <id>
107
+ # {"ok":true,"data":{"intent_id":"…","status":"completed"}}
108
+
109
+ certen --json portfolio
110
+ # {"ok":false,"error":{"code":"NETWORK_ERROR","message":"connect ECONNREFUSED","retryable":true,"status":0}}
111
+ ```
112
+
113
+ - **Exactly one JSON object on stdout**, nothing else. Every human-facing line goes to stderr.
114
+ - **Exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway unreachable. Branch on
115
+ these instead of parsing text. `3` guarantees nothing was submitted, so a retry cannot
116
+ double-execute.
117
+ - **`error.retryable`** comes from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
118
+ give an identical retry decision.
119
+ - **`certen --help --json`** returns the entire command tree every command, flag and exit code in
120
+ one call.
121
+
122
+ Without `--json`, output is the human table format as before. Do not parse it.
123
+
124
+ ## Configuration
125
+
126
+ | | |
127
+ |---|---|
128
+ | `CERTEN_API_KEY` | API key. Always wins, so CI never touches the keyring or config file. |
129
+ | `CERTEN_API_URL` | Gateway base URL. Defaults to `https://gateway.kompendium.co`. |
130
+ | `CERTEN_KEY_PASSPHRASE` | Passphrase for local signing keys. |
131
+
132
+ `certen auth login` stores the API key in your OS keyring by default, or in
133
+ `~/.certen/config.json` at `0600` with `--no-keyring`.
134
+
135
+ ## Things that will bite you
136
+
137
+ **Identity creation is asynchronous.** `identity create` returns `202` and provisioning continues.
138
+ Poll until the status is terminal, and check `can_sign` — it derives from the on-chain key page, so
139
+ it can read `true` while the status is still `creating`.
140
+
141
+ **A proof cycle takes 60–110 seconds.** Real validator work, not a tunable delay. Do not wrap it in
142
+ a 30-second timeout.
143
+
144
+ **Sign the bytes, not the text.** If you are producing signatures outside this CLI: sign the raw
145
+ bytes of the hash, do not hash it again, and do not sign the ASCII of the hex string. All three
146
+ mistakes produce a well-formed 128-hex signature the gateway rejects. `certen keys sign` handles
147
+ this for you.
148
+
149
+ ## Documentation
150
+
151
+ **<https://docs.kompendium.co>** — getting started, authentication, errors, idempotency, and
152
+ task-shaped guides: onboarding an identity, external signing, proof-gating a contract call, M-of-N
153
+ panels, and verifying a proof.
154
+
155
+ The [live API reference](https://gateway.kompendium.co/reference) is generated from the running
156
+ gateway and is authoritative — when a guide and the spec disagree, the spec is right.
157
+
158
+ ## License
159
+
160
+ MIT
@@ -1,5 +1,5 @@
1
1
  import { readConfig, writeConfig, setApiKey, clearApiKey, DEFAULT_API_URL } from '../config.js';
2
- import { printOutput } from '../output.js';
2
+ import { printOutput, human } from '../output.js';
3
3
  export function registerAuthCommands(program) {
4
4
  const auth = program.command('auth').description('Authentication management');
5
5
  auth
@@ -23,14 +23,14 @@ export function registerAuthCommands(program) {
23
23
  cfg.api_url = opts.apiUrl;
24
24
  writeConfig(cfg);
25
25
  }
26
- console.log(useKeyring ? 'API key saved to OS keyring' : 'API key saved to ~/.certen/config.json (mode 0600)');
26
+ human(useKeyring ? 'API key saved to OS keyring' : 'API key saved to ~/.certen/config.json (mode 0600)');
27
27
  });
28
28
  auth
29
29
  .command('logout')
30
30
  .description('Remove the saved API key from keyring or config file')
31
31
  .action(async () => {
32
32
  await clearApiKey();
33
- console.log('API key cleared');
33
+ human('API key cleared');
34
34
  });
35
35
  auth
36
36
  .command('status')
@@ -1 +1 @@
1
- {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"auth.js","sourceRoot":"","sources":["../../src/commands/auth.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,4 @@
1
- import { printOutput } from '../output.js';
1
+ import { printOutput, human } from '../output.js';
2
2
  import { resolvePassphrase, resolveNewPassphrase, PASSPHRASE_ENV_VAR } from '../passphrase.js';
3
3
  import { generateKey, listKeys, getKeyInfo, deleteKey, signHash, selfTest, keyPath, KEYS_DIR, } from '../keystore.js';
4
4
  /**
@@ -41,7 +41,7 @@ export function registerKeysCommands(program) {
41
41
  .action(() => {
42
42
  const all = listKeys();
43
43
  if (all.length === 0) {
44
- console.log(`(no keys in ${KEYS_DIR})`);
44
+ human(`(no keys in ${KEYS_DIR})`);
45
45
  return;
46
46
  }
47
47
  printOutput(all.map((k) => ({
@@ -96,7 +96,7 @@ export function registerKeysCommands(program) {
96
96
  // should not be deletable by an accidental Enter on a y/N prompt.
97
97
  const path = keyPath(name);
98
98
  deleteKey(name);
99
- console.log(`Deleted ${path}`);
99
+ human(`Deleted ${path}`);
100
100
  console.error('If this key was on a key page, it is still on that page — remove it there too.');
101
101
  });
102
102
  keys
@@ -1 +1 @@
1
- {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"keys.js","sourceRoot":"","sources":["../../src/commands/keys.ts"],"names":[],"mappings":"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"}
package/dist/config.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { readFileSync, writeFileSync, mkdirSync, existsSync, chmodSync, statSync } from 'fs';
2
2
  import { join } from 'path';
3
3
  import { homedir } from 'os';
4
+ import { UsageError } from './errors.js';
4
5
  const CONFIG_DIR = join(homedir(), '.certen');
5
6
  const CONFIG_FILE = join(CONFIG_DIR, 'config.json');
6
7
  export function readConfig() {
@@ -86,19 +87,17 @@ export async function getApiKey() {
86
87
  return v;
87
88
  }
88
89
  else {
89
- console.error('storage=keyring requested but `keytar` is not installed; install it or set CERTEN_API_KEY.');
90
- process.exit(1);
90
+ throw new UsageError('storage=keyring requested but `keytar` is not installed; install it or set CERTEN_API_KEY.', 'KEYRING_UNAVAILABLE');
91
91
  }
92
92
  }
93
93
  if (cfg.api_key) {
94
94
  if (!configFileIsSecure()) {
95
- console.error('refusing to read ~/.certen/config.json — file permissions are not 0600. Run `certen auth login` again to fix.');
96
- process.exit(1);
95
+ throw new UsageError('refusing to read ~/.certen/config.json — file permissions are not 0600. '
96
+ + 'Run `certen auth login` again to fix.', 'CONFIG_PERMISSIONS');
97
97
  }
98
98
  return cfg.api_key;
99
99
  }
100
- console.error('No API key configured. Run "certen auth login --api-key <key>" or set CERTEN_API_KEY.');
101
- process.exit(1);
100
+ throw new UsageError('No API key configured. Run "certen auth login --api-key <key>" or set CERTEN_API_KEY.', 'NO_API_KEY');
102
101
  }
103
102
  export async function setApiKey(apiKey, useKeyring) {
104
103
  const prefix = apiKey.substring(0, 12);
@@ -1 +1 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * Exit codes and the local error taxonomy.
3
+ *
4
+ * The CLI used to exit `1` for everything — a bad flag, a rejected request, and an unreachable
5
+ * gateway were indistinguishable without reading English off stderr. An automated caller cannot
6
+ * make a retry decision from that: "you passed a malformed address" and "the gateway is down" want
7
+ * opposite responses, and only one of them is worth retrying.
8
+ *
9
+ * These four codes are a contract. See docs/CLI-CONTRACT.md.
10
+ */
11
+ export declare const EXIT: {
12
+ /** Success. */
13
+ readonly OK: 0;
14
+ /** The request was well-formed and the gateway answered, but the operation did not succeed. */
15
+ readonly FAILED: 1;
16
+ /** The invocation was wrong: unknown command, missing flag, no API key configured. */
17
+ readonly USAGE: 2;
18
+ /** The gateway could not be reached at all. Nothing was submitted. */
19
+ readonly UNREACHABLE: 3;
20
+ };
21
+ export type ExitCode = (typeof EXIT)[keyof typeof EXIT];
22
+ /**
23
+ * An error raised by the CLI itself rather than by the gateway.
24
+ *
25
+ * `code` is machine-readable and lives in the same namespace as the gateway's codes, so a caller
26
+ * branching on `error.code` does not need to know whether the failure was local or remote.
27
+ */
28
+ export declare class CliError extends Error {
29
+ readonly code: string;
30
+ readonly exitCode: ExitCode;
31
+ readonly retryable: boolean;
32
+ constructor(message: string, code: string, exitCode?: ExitCode, retryable?: boolean);
33
+ }
34
+ /** A wrong invocation: exits 2, never retryable. */
35
+ export declare class UsageError extends CliError {
36
+ constructor(message: string, code?: string);
37
+ }
package/dist/errors.js ADDED
@@ -0,0 +1,46 @@
1
+ /**
2
+ * Exit codes and the local error taxonomy.
3
+ *
4
+ * The CLI used to exit `1` for everything — a bad flag, a rejected request, and an unreachable
5
+ * gateway were indistinguishable without reading English off stderr. An automated caller cannot
6
+ * make a retry decision from that: "you passed a malformed address" and "the gateway is down" want
7
+ * opposite responses, and only one of them is worth retrying.
8
+ *
9
+ * These four codes are a contract. See docs/CLI-CONTRACT.md.
10
+ */
11
+ export const EXIT = {
12
+ /** Success. */
13
+ OK: 0,
14
+ /** The request was well-formed and the gateway answered, but the operation did not succeed. */
15
+ FAILED: 1,
16
+ /** The invocation was wrong: unknown command, missing flag, no API key configured. */
17
+ USAGE: 2,
18
+ /** The gateway could not be reached at all. Nothing was submitted. */
19
+ UNREACHABLE: 3,
20
+ };
21
+ /**
22
+ * An error raised by the CLI itself rather than by the gateway.
23
+ *
24
+ * `code` is machine-readable and lives in the same namespace as the gateway's codes, so a caller
25
+ * branching on `error.code` does not need to know whether the failure was local or remote.
26
+ */
27
+ export class CliError extends Error {
28
+ code;
29
+ exitCode;
30
+ retryable;
31
+ constructor(message, code, exitCode = EXIT.FAILED, retryable = false) {
32
+ super(message);
33
+ this.name = 'CliError';
34
+ this.code = code;
35
+ this.exitCode = exitCode;
36
+ this.retryable = retryable;
37
+ }
38
+ }
39
+ /** A wrong invocation: exits 2, never retryable. */
40
+ export class UsageError extends CliError {
41
+ constructor(message, code = 'USAGE_ERROR') {
42
+ super(message, code, EXIT.USAGE, false);
43
+ this.name = 'UsageError';
44
+ }
45
+ }
46
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,eAAe;IACf,EAAE,EAAE,CAAC;IACL,+FAA+F;IAC/F,MAAM,EAAE,CAAC;IACT,sFAAsF;IACtF,KAAK,EAAE,CAAC;IACR,sEAAsE;IACtE,WAAW,EAAE,CAAC;CACN,CAAC;AAIX;;;;;GAKG;AACH,MAAM,OAAO,QAAS,SAAQ,KAAK;IACxB,IAAI,CAAS;IACb,QAAQ,CAAW;IACnB,SAAS,CAAU;IAE5B,YAAY,OAAe,EAAE,IAAY,EAAE,WAAqB,IAAI,CAAC,MAAM,EAAE,SAAS,GAAG,KAAK;QAC5F,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,UAAU,CAAC;QACvB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,QAAQ,GAAG,QAAQ,CAAC;QACzB,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;CACF;AAED,oDAAoD;AACpD,MAAM,OAAO,UAAW,SAAQ,QAAQ;IACtC,YAAY,OAAe,EAAE,IAAI,GAAG,aAAa;QAC/C,KAAK,CAAC,OAAO,EAAE,IAAI,EAAE,IAAI,CAAC,KAAK,EAAE,KAAK,CAAC,CAAC;QACxC,IAAI,CAAC,IAAI,GAAG,YAAY,CAAC;IAC3B,CAAC;CACF"}
@@ -0,0 +1,2 @@
1
+ import type { Command } from 'commander';
2
+ export declare function commandTree(program: Command, version: string): string;
@@ -0,0 +1,51 @@
1
+ function optionNode(o) {
2
+ return {
3
+ flags: o.flags,
4
+ name: o.attributeName ? o.attributeName() : (o.long ?? o.short ?? o.flags).replace(/^--?/, ''),
5
+ description: o.description ?? '',
6
+ required: Boolean(o.mandatory),
7
+ // `required` on a commander Option means "this flag takes a mandatory value", not "this flag
8
+ // must be present" — that is `mandatory`. Conflating them is an easy and very confusing bug.
9
+ takesValue: Boolean(o.required || o.optional),
10
+ ...(o.defaultValue !== undefined ? { default: o.defaultValue } : {}),
11
+ };
12
+ }
13
+ function argumentsOf(cmd) {
14
+ // `registeredArguments` is commander >= 12; `_args` is the older internal. Fall back rather than
15
+ // throw, so a commander bump degrades the help tree instead of breaking the command.
16
+ const raw = (cmd.registeredArguments
17
+ ?? cmd._args
18
+ ?? []);
19
+ return raw.map((a) => ({
20
+ name: a.name(),
21
+ required: Boolean(a.required),
22
+ description: a.description ?? '',
23
+ }));
24
+ }
25
+ function walk(cmd, prefix) {
26
+ const path = [...prefix, cmd.name()].filter(Boolean);
27
+ return {
28
+ name: cmd.name(),
29
+ description: cmd.description(),
30
+ path: path.join(' '),
31
+ arguments: argumentsOf(cmd),
32
+ options: cmd.options.map(optionNode),
33
+ commands: cmd.commands.map((c) => walk(c, path)),
34
+ };
35
+ }
36
+ export function commandTree(program, version) {
37
+ return JSON.stringify({
38
+ ok: true,
39
+ data: {
40
+ ...walk(program, []),
41
+ version,
42
+ exitCodes: {
43
+ 0: 'ok',
44
+ 1: 'operation failed',
45
+ 2: 'usage error',
46
+ 3: 'gateway unreachable',
47
+ },
48
+ },
49
+ });
50
+ }
51
+ //# sourceMappingURL=help-json.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"help-json.js","sourceRoot":"","sources":["../src/help-json.ts"],"names":[],"mappings":"AAoDA,SAAS,UAAU,CAAC,CAAsB;IACxC,OAAO;QACL,KAAK,EAAE,CAAC,CAAC,KAAK;QACd,IAAI,EAAE,CAAC,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC;QAC9F,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;QAChC,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,SAAS,CAAC;QAC9B,6FAA6F;QAC7F,6FAA6F;QAC7F,UAAU,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,IAAI,CAAC,CAAC,QAAQ,CAAC;QAC7C,GAAG,CAAC,CAAC,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,CAAC,YAAY,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACrE,CAAC;AACJ,CAAC;AAED,SAAS,WAAW,CAAC,GAAY;IAC/B,iGAAiG;IACjG,qFAAqF;IACrF,MAAM,GAAG,GACP,CAAE,GAAoE,CAAC,mBAAmB;WACpF,GAAsD,CAAC,KAAK;WAC7D,EAAE,CAAC,CAAC;IACX,OAAO,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;QACrB,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC,CAAC,CAAC,QAAQ,CAAC;QAC7B,WAAW,EAAE,CAAC,CAAC,WAAW,IAAI,EAAE;KACjC,CAAC,CAAC,CAAC;AACN,CAAC;AAED,SAAS,IAAI,CAAC,GAAY,EAAE,MAAgB;IAC1C,MAAM,IAAI,GAAG,CAAC,GAAG,MAAM,EAAE,GAAG,CAAC,IAAI,EAAE,CAAC,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC;IACrD,OAAO;QACL,IAAI,EAAE,GAAG,CAAC,IAAI,EAAE;QAChB,WAAW,EAAE,GAAG,CAAC,WAAW,EAAE;QAC9B,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;QACpB,SAAS,EAAE,WAAW,CAAC,GAAG,CAAC;QAC3B,OAAO,EAAG,GAAG,CAAC,OAA4C,CAAC,GAAG,CAAC,UAAU,CAAC;QAC1E,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,CAAY,EAAE,IAAI,CAAC,CAAC;KAC5D,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,OAAgB,EAAE,OAAe;IAC3D,OAAO,IAAI,CAAC,SAAS,CAAC;QACpB,EAAE,EAAE,IAAI;QACR,IAAI,EAAE;YACJ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,CAAC;YACpB,OAAO;YACP,SAAS,EAAE;gBACT,CAAC,EAAE,IAAI;gBACP,CAAC,EAAE,kBAAkB;gBACrB,CAAC,EAAE,aAAa;gBAChB,CAAC,EAAE,qBAAqB;aACzB;SACF;KACF,CAAC,CAAC;AACL,CAAC"}
package/dist/index.d.ts CHANGED
@@ -1,2 +1,5 @@
1
1
  #!/usr/bin/env node
2
- export {};
2
+ import { Command } from 'commander';
3
+ import { type ExitCode } from './errors.js';
4
+ export declare function buildProgram(): Command;
5
+ export declare function run(argv: string[]): Promise<ExitCode>;
package/dist/index.js CHANGED
@@ -1,9 +1,12 @@
1
1
  #!/usr/bin/env node
2
2
  import { readFileSync } from 'node:fs';
3
3
  import { dirname, join } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { Command } from 'commander';
4
+ import { fileURLToPath, pathToFileURL } from 'node:url';
5
+ import { Command, CommanderError } from 'commander';
6
6
  import { CertenError } from '@certen.io/sdk';
7
+ import { EXIT } from './errors.js';
8
+ import { setJsonMode, flushSuccess, emitFailure } from './output.js';
9
+ import { commandTree } from './help-json.js';
7
10
  /** Read the version from package.json — dist/ sits one level below the manifest. */
8
11
  function readVersion() {
9
12
  try {
@@ -22,43 +25,100 @@ import { registerPendingCommands } from './commands/pending.js';
22
25
  import { registerGovernanceCommands } from './commands/governance.js';
23
26
  import { registerPortfolioCommands } from './commands/portfolio.js';
24
27
  import { registerAdminCommands } from './commands/admin.js';
25
- const program = new Command();
26
- program
27
- .name('certen')
28
- .description('CERTEN Gateway CLI')
29
- // Was hardcoded to 0.1.0 while package.json said 0.2.0, so `certen --version` reported a
30
- // release that does not exist. Read it from the manifest so the two cannot drift again.
31
- .version(readVersion());
32
- registerAuthCommands(program);
33
- registerKeysCommands(program);
34
- registerIdentityCommands(program);
35
- registerTransactionCommands(program);
36
- registerPendingCommands(program);
37
- registerGovernanceCommands(program);
38
- registerPortfolioCommands(program);
39
- registerAdminCommands(program);
40
- // Global error handler
41
- program.hook('preAction', () => { });
42
- program.exitOverride();
43
- async function main() {
28
+ const VERSION = readVersion();
29
+ export function buildProgram() {
30
+ const program = new Command();
31
+ program
32
+ .name('certen')
33
+ .description('CERTEN Gateway CLI')
34
+ // Was hardcoded to 0.1.0 while package.json said 0.2.0, so `certen --version` reported a
35
+ // release that does not exist. Read it from the manifest so the two cannot drift again.
36
+ .version(VERSION)
37
+ // Declared so it appears in --help. It is stripped from argv before parsing (see run()), because
38
+ // a global flag that may appear after a subcommand is not something commander models.
39
+ .option('--json', 'Emit one JSON envelope on stdout; human output goes to stderr');
40
+ registerAuthCommands(program);
41
+ registerKeysCommands(program);
42
+ registerIdentityCommands(program);
43
+ registerTransactionCommands(program);
44
+ registerPendingCommands(program);
45
+ registerGovernanceCommands(program);
46
+ registerPortfolioCommands(program);
47
+ registerAdminCommands(program);
48
+ // Every command, not just the root. `exitOverride()` is NOT inherited by subcommands, so without
49
+ // this walk a missing required flag on `identity create` called process.exit(1) inside commander:
50
+ // stdout stayed empty, no envelope was ever emitted, and a usage error was indistinguishable from
51
+ // a failed request. Every nested command has to opt in explicitly.
52
+ applyExitOverride(program);
53
+ return program;
54
+ }
55
+ function applyExitOverride(cmd) {
56
+ cmd.exitOverride();
57
+ for (const sub of cmd.commands)
58
+ applyExitOverride(sub);
59
+ }
60
+ /**
61
+ * Map a thrown value to an exit code, and emit the matching envelope.
62
+ *
63
+ * The four codes exist so an automated caller never has to parse English to decide what to do:
64
+ * `2` means fix the invocation, `3` means the gateway was unreachable and nothing was submitted,
65
+ * `1` means the gateway answered and said no.
66
+ */
67
+ function handleError(err) {
68
+ if (err instanceof CommanderError) {
69
+ // --help and --version are successful terminations that commander reports by throwing.
70
+ if (err.exitCode === 0 || err.code === 'commander.helpDisplayed' || err.code === 'commander.version') {
71
+ return EXIT.OK;
72
+ }
73
+ return emitFailure({
74
+ message: err.message.replace(/^error: /, ''),
75
+ code: 'USAGE_ERROR',
76
+ exitCode: EXIT.USAGE,
77
+ });
78
+ }
79
+ if (err instanceof CertenError) {
80
+ // isRetryable is the SDK's own judgement — reuse it so both transports agree.
81
+ return emitFailure({
82
+ message: err.message,
83
+ code: err.code,
84
+ status: err.status,
85
+ requestId: err.requestId,
86
+ isRetryable: err.isRetryable,
87
+ });
88
+ }
89
+ return emitFailure(err);
90
+ }
91
+ export async function run(argv) {
92
+ // `--json` is resolved before parsing so it applies to every code path, including failures that
93
+ // happen while resolving credentials — those must be reportable in the envelope too.
94
+ const json = argv.includes('--json');
95
+ setJsonMode(json);
96
+ const cleanArgv = argv.filter((a) => a !== '--json');
97
+ const program = buildProgram();
98
+ // `certen --help --json` answers "what can this CLI do" in one call, instead of scraping help
99
+ // text once per subcommand.
100
+ if (json && (cleanArgv.includes('--help') || cleanArgv.includes('-h'))) {
101
+ process.stdout.write(`${commandTree(program, VERSION)}\n`);
102
+ return EXIT.OK;
103
+ }
44
104
  try {
45
- await program.parseAsync(process.argv);
105
+ await program.parseAsync(cleanArgv);
106
+ flushSuccess();
107
+ return EXIT.OK;
46
108
  }
47
109
  catch (err) {
48
- if (err instanceof CertenError) {
49
- console.error(`Error [${err.code}]: ${err.message}`);
50
- process.exit(1);
51
- }
52
- if (err instanceof Error) {
53
- // Commander exit override throws for --help etc
54
- if (err.exitCode === 0)
55
- return;
56
- console.error(`Error: ${err.message}`);
57
- process.exit(1);
58
- }
59
- console.error('Unknown error:', err);
60
- process.exit(1);
110
+ return handleError(err);
61
111
  }
62
112
  }
63
- main();
113
+ /* c8 ignore start — entrypoint wiring, exercised by the conformance suite as a subprocess */
114
+ // Run only when executed as the binary, not when imported by a test. `pathToFileURL` is what makes
115
+ // this correct on Windows, where a naive `file://` + path concatenation produces a URL that never
116
+ // matches `import.meta.url`.
117
+ const invokedDirectly = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
118
+ if (invokedDirectly) {
119
+ run(process.argv).then((code) => {
120
+ process.exitCode = code;
121
+ });
122
+ }
123
+ /* c8 ignore stop */
64
124
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAEA,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAC1C,OAAO,EAAE,aAAa,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AACxD,OAAO,EAAE,OAAO,EAAE,cAAc,EAAE,MAAM,WAAW,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAiB,MAAM,aAAa,CAAC;AAClD,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AACrE,OAAO,EAAE,WAAW,EAAE,MAAM,gBAAgB,CAAC;AAE7C,oFAAoF;AACpF,SAAS,WAAW;IAClB,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,OAAO,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;QACrD,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,EAAE,cAAc,CAAC,EAAE,OAAO,CAAC,CAAC,CAAC,OAAiB,CAAC;IAC/F,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,eAAe,CAAC;IACzB,CAAC;AACH,CAAC;AACD,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,wBAAwB,EAAE,MAAM,wBAAwB,CAAC;AAClE,OAAO,EAAE,2BAA2B,EAAE,MAAM,2BAA2B,CAAC;AACxE,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,0BAA0B,EAAE,MAAM,0BAA0B,CAAC;AACtE,OAAO,EAAE,yBAAyB,EAAE,MAAM,yBAAyB,CAAC;AACpE,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,MAAM,OAAO,GAAG,WAAW,EAAE,CAAC;AAE9B,MAAM,UAAU,YAAY;IAC1B,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;IAE9B,OAAO;SACJ,IAAI,CAAC,QAAQ,CAAC;SACd,WAAW,CAAC,oBAAoB,CAAC;QAClC,yFAAyF;QACzF,wFAAwF;SACvF,OAAO,CAAC,OAAO,CAAC;QACjB,iGAAiG;QACjG,sFAAsF;SACrF,MAAM,CAAC,QAAQ,EAAE,+DAA+D,CAAC,CAAC;IAErF,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAClC,2BAA2B,CAAC,OAAO,CAAC,CAAC;IACrC,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACpC,yBAAyB,CAAC,OAAO,CAAC,CAAC;IACnC,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAE/B,iGAAiG;IACjG,kGAAkG;IAClG,kGAAkG;IAClG,mEAAmE;IACnE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAC3B,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,iBAAiB,CAAC,GAAY;IACrC,GAAG,CAAC,YAAY,EAAE,CAAC;IACnB,KAAK,MAAM,GAAG,IAAI,GAAG,CAAC,QAAQ;QAAE,iBAAiB,CAAC,GAAc,CAAC,CAAC;AACpE,CAAC;AAED;;;;;;GAMG;AACH,SAAS,WAAW,CAAC,GAAY;IAC/B,IAAI,GAAG,YAAY,cAAc,EAAE,CAAC;QAClC,uFAAuF;QACvF,IAAI,GAAG,CAAC,QAAQ,KAAK,CAAC,IAAI,GAAG,CAAC,IAAI,KAAK,yBAAyB,IAAI,GAAG,CAAC,IAAI,KAAK,mBAAmB,EAAE,CAAC;YACrG,OAAO,IAAI,CAAC,EAAE,CAAC;QACjB,CAAC;QACD,OAAO,WAAW,CAAC;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO,CAAC,OAAO,CAAC,UAAU,EAAE,EAAE,CAAC;YAC5C,IAAI,EAAE,aAAa;YACnB,QAAQ,EAAE,IAAI,CAAC,KAAK;SACrB,CAAC,CAAC;IACL,CAAC;IAED,IAAI,GAAG,YAAY,WAAW,EAAE,CAAC;QAC/B,8EAA8E;QAC9E,OAAO,WAAW,CAAC;YACjB,OAAO,EAAE,GAAG,CAAC,OAAO;YACpB,IAAI,EAAE,GAAG,CAAC,IAAI;YACd,MAAM,EAAE,GAAG,CAAC,MAAM;YAClB,SAAS,EAAE,GAAG,CAAC,SAAS;YACxB,WAAW,EAAE,GAAG,CAAC,WAAW;SAC7B,CAAC,CAAC;IACL,CAAC;IAED,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;AAC1B,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,GAAG,CAAC,IAAc;IACtC,gGAAgG;IAChG,qFAAqF;IACrF,MAAM,IAAI,GAAG,IAAI,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IACrC,WAAW,CAAC,IAAI,CAAC,CAAC;IAClB,MAAM,SAAS,GAAG,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,QAAQ,CAAC,CAAC;IAErD,MAAM,OAAO,GAAG,YAAY,EAAE,CAAC;IAE/B,8FAA8F;IAC9F,4BAA4B;IAC5B,IAAI,IAAI,IAAI,CAAC,SAAS,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,SAAS,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,EAAE,CAAC;QACvE,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,WAAW,CAAC,OAAO,EAAE,OAAO,CAAC,IAAI,CAAC,CAAC;QAC3D,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAED,IAAI,CAAC;QACH,MAAM,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;QACpC,YAAY,EAAE,CAAC;QACf,OAAO,IAAI,CAAC,EAAE,CAAC;IACjB,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,CAAC;AACH,CAAC;AAED,6FAA6F;AAC7F,mGAAmG;AACnG,kGAAkG;AAClG,6BAA6B;AAC7B,MAAM,eAAe,GACnB,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;AAEtF,IAAI,eAAe,EAAE,CAAC;IACpB,GAAG,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE;QAC9B,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC;IAC1B,CAAC,CAAC,CAAC;AACL,CAAC;AACD,oBAAoB"}
package/dist/output.d.ts CHANGED
@@ -1,6 +1,36 @@
1
+ import { type ExitCode } from './errors.js';
2
+ export declare function setJsonMode(on: boolean): void;
3
+ export declare function isJsonMode(): boolean;
4
+ /** Test seam: reset module state between cases. */
5
+ export declare function resetOutput(): void;
1
6
  /**
2
- * Print data as an aligned table or JSON depending on user preference.
7
+ * Print a result. In JSON mode this buffers; call `flushSuccess()` once the command completes.
3
8
  */
4
9
  export declare function printOutput(data: Record<string, unknown>[] | Record<string, unknown>, opts?: {
5
10
  forceJson?: boolean;
6
11
  }): void;
12
+ /**
13
+ * A human-facing note — "API key saved", "(no keys)".
14
+ *
15
+ * In JSON mode this goes to stderr, because stdout is reserved for the single envelope. In table
16
+ * mode it is ordinary output and goes to stdout.
17
+ */
18
+ export declare function human(message: string): void;
19
+ /** A hint or warning. Always stderr — it is never the result of the command. */
20
+ export declare function hint(message: string): void;
21
+ /**
22
+ * Emit the success envelope. No-op outside JSON mode, and safe to call more than once.
23
+ *
24
+ * A command that produced no payload still emits `{"ok":true,"data":null}` rather than nothing, so
25
+ * a caller can always parse stdout instead of special-casing empty output.
26
+ */
27
+ export declare function flushSuccess(): void;
28
+ /**
29
+ * Emit the failure envelope (JSON mode) or a human error line (table mode), and return the exit code.
30
+ *
31
+ * `retryable` is taken from the SDK's own `CertenError.isRetryable` wherever the error came from the
32
+ * gateway, so the CLI and the SDK hand an automated caller the identical retry decision. That
33
+ * equivalence is the property worth having: a script can switch transports without re-deriving which
34
+ * failures are worth another attempt.
35
+ */
36
+ export declare function emitFailure(err: unknown): ExitCode;
package/dist/output.js CHANGED
@@ -1,13 +1,118 @@
1
1
  import { getOutputFormat } from './config.js';
2
+ import { CliError, EXIT } from './errors.js';
2
3
  /**
3
- * Print data as an aligned table or JSON depending on user preference.
4
+ * Two output modes with different audiences and different guarantees.
5
+ *
6
+ * Table mode is for humans and is NOT a contract — column widths and wording may change.
7
+ *
8
+ * JSON mode is a machine contract: exactly one envelope object on stdout and nothing else, every
9
+ * human-facing line on stderr, and an exit code that says which kind of failure occurred. See
10
+ * docs/CLI-CONTRACT.md. The single-object guarantee is why payloads are buffered rather than
11
+ * printed as they arrive: a command that prints twice would otherwise emit two top-level objects
12
+ * and break every streaming JSON parser pointed at it.
13
+ */
14
+ let jsonMode = false;
15
+ /** Payloads collected in JSON mode, flushed as one envelope when the command finishes. */
16
+ let collected = [];
17
+ let flushed = false;
18
+ export function setJsonMode(on) {
19
+ jsonMode = on;
20
+ }
21
+ export function isJsonMode() {
22
+ return jsonMode;
23
+ }
24
+ /** Test seam: reset module state between cases. */
25
+ export function resetOutput() {
26
+ jsonMode = false;
27
+ collected = [];
28
+ flushed = false;
29
+ }
30
+ /**
31
+ * Print a result. In JSON mode this buffers; call `flushSuccess()` once the command completes.
4
32
  */
5
33
  export function printOutput(data, opts) {
34
+ if (jsonMode) {
35
+ collected.push(data);
36
+ return;
37
+ }
6
38
  const format = opts?.forceJson ? 'json' : getOutputFormat();
7
39
  if (format === 'json') {
8
40
  console.log(JSON.stringify(data, null, 2));
9
41
  return;
10
42
  }
43
+ printTable(data);
44
+ }
45
+ /**
46
+ * A human-facing note — "API key saved", "(no keys)".
47
+ *
48
+ * In JSON mode this goes to stderr, because stdout is reserved for the single envelope. In table
49
+ * mode it is ordinary output and goes to stdout.
50
+ */
51
+ export function human(message) {
52
+ if (jsonMode)
53
+ console.error(message);
54
+ else
55
+ console.log(message);
56
+ }
57
+ /** A hint or warning. Always stderr — it is never the result of the command. */
58
+ export function hint(message) {
59
+ console.error(message);
60
+ }
61
+ /**
62
+ * Emit the success envelope. No-op outside JSON mode, and safe to call more than once.
63
+ *
64
+ * A command that produced no payload still emits `{"ok":true,"data":null}` rather than nothing, so
65
+ * a caller can always parse stdout instead of special-casing empty output.
66
+ */
67
+ export function flushSuccess() {
68
+ if (!jsonMode || flushed)
69
+ return;
70
+ flushed = true;
71
+ const data = collected.length === 0 ? null : collected.length === 1 ? collected[0] : collected;
72
+ process.stdout.write(`${JSON.stringify({ ok: true, data })}\n`);
73
+ }
74
+ /**
75
+ * Emit the failure envelope (JSON mode) or a human error line (table mode), and return the exit code.
76
+ *
77
+ * `retryable` is taken from the SDK's own `CertenError.isRetryable` wherever the error came from the
78
+ * gateway, so the CLI and the SDK hand an automated caller the identical retry decision. That
79
+ * equivalence is the property worth having: a script can switch transports without re-deriving which
80
+ * failures are worth another attempt.
81
+ */
82
+ export function emitFailure(err) {
83
+ const e = (err ?? {});
84
+ const message = e.message ?? String(err);
85
+ const code = e.code ?? 'UNKNOWN_ERROR';
86
+ const retryable = e instanceof CliError ? e.retryable : Boolean(e.isRetryable);
87
+ const exitCode = resolveExitCode(e);
88
+ if (jsonMode) {
89
+ flushed = true;
90
+ process.stdout.write(`${JSON.stringify({
91
+ ok: false,
92
+ error: {
93
+ code,
94
+ message,
95
+ retryable,
96
+ ...(e.status !== undefined ? { status: e.status } : {}),
97
+ ...(e.requestId ? { requestId: e.requestId } : {}),
98
+ },
99
+ })}\n`);
100
+ }
101
+ else {
102
+ console.error(code === 'UNKNOWN_ERROR' ? `Error: ${message}` : `Error [${code}]: ${message}`);
103
+ }
104
+ return exitCode;
105
+ }
106
+ function resolveExitCode(e) {
107
+ if (typeof e.exitCode === 'number')
108
+ return e.exitCode;
109
+ // status 0 is how the SDK reports "the request never reached the gateway".
110
+ if (e.code === 'NETWORK_ERROR' || e.status === 0)
111
+ return EXIT.UNREACHABLE;
112
+ return EXIT.FAILED;
113
+ }
114
+ // ── table rendering (human mode only) ───────────────────────────────────────────────────────────
115
+ function printTable(data) {
11
116
  // Single object: print key-value pairs
12
117
  if (!Array.isArray(data)) {
13
118
  const entries = Object.entries(data);
@@ -1 +1 @@
1
- {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"output.js","sourceRoot":"","sources":["../src/output.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAC9C,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAiB,MAAM,aAAa,CAAC;AAE5D;;;;;;;;;;GAUG;AAEH,IAAI,QAAQ,GAAG,KAAK,CAAC;AACrB,0FAA0F;AAC1F,IAAI,SAAS,GAAc,EAAE,CAAC;AAC9B,IAAI,OAAO,GAAG,KAAK,CAAC;AAEpB,MAAM,UAAU,WAAW,CAAC,EAAW;IACrC,QAAQ,GAAG,EAAE,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,mDAAmD;AACnD,MAAM,UAAU,WAAW;IACzB,QAAQ,GAAG,KAAK,CAAC;IACjB,SAAS,GAAG,EAAE,CAAC;IACf,OAAO,GAAG,KAAK,CAAC;AAClB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,WAAW,CACzB,IAAyD,EACzD,IAA8B;IAE9B,IAAI,QAAQ,EAAE,CAAC;QACb,SAAS,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,MAAM,GAAG,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,eAAe,EAAE,CAAC;IAC5D,IAAI,MAAM,KAAK,MAAM,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;QAC3C,OAAO;IACT,CAAC;IAED,UAAU,CAAC,IAAI,CAAC,CAAC;AACnB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,KAAK,CAAC,OAAe;IACnC,IAAI,QAAQ;QAAE,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;;QAChC,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;AAC5B,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,IAAI,CAAC,OAAe;IAClC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;AACzB,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,YAAY;IAC1B,IAAI,CAAC,QAAQ,IAAI,OAAO;QAAE,OAAO;IACjC,OAAO,GAAG,IAAI,CAAC;IACf,MAAM,IAAI,GAAG,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;IAC/F,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,CAAC,CAAC;AAClE,CAAC;AAWD;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,GAAY;IACtC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,EAAE,CAAc,CAAC;IACnC,MAAM,OAAO,GAAG,CAAC,CAAC,OAAO,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC;IACzC,MAAM,IAAI,GAAG,CAAC,CAAC,IAAI,IAAI,eAAe,CAAC;IACvC,MAAM,SAAS,GAAG,CAAC,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,WAAW,CAAC,CAAC;IAC/E,MAAM,QAAQ,GAAG,eAAe,CAAC,CAAC,CAAC,CAAC;IAEpC,IAAI,QAAQ,EAAE,CAAC;QACb,OAAO,GAAG,IAAI,CAAC;QACf,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,IAAI,CAAC,SAAS,CAAC;YAChB,EAAE,EAAE,KAAK;YACT,KAAK,EAAE;gBACL,IAAI;gBACJ,OAAO;gBACP,SAAS;gBACT,GAAG,CAAC,CAAC,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,GAAG,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;aACnD;SACF,CAAC,IAAI,CACP,CAAC;IACJ,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,eAAe,CAAC,CAAC,CAAC,UAAU,OAAO,EAAE,CAAC,CAAC,CAAC,UAAU,IAAI,MAAM,OAAO,EAAE,CAAC,CAAC;IAChG,CAAC;IAED,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,SAAS,eAAe,CAAC,CAAY;IACnC,IAAI,OAAO,CAAC,CAAC,QAAQ,KAAK,QAAQ;QAAE,OAAO,CAAC,CAAC,QAAoB,CAAC;IAClE,2EAA2E;IAC3E,IAAI,CAAC,CAAC,IAAI,KAAK,eAAe,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,IAAI,CAAC,WAAW,CAAC;IAC1E,OAAO,IAAI,CAAC,MAAM,CAAC;AACrB,CAAC;AAED,mGAAmG;AAEnG,SAAS,UAAU,CAAC,IAAyD;IAC3E,uCAAuC;IACvC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;QACrC,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC;QAC9D,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;YACnC,MAAM,YAAY,GAAG,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC,CAAC;YAC7F,OAAO,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,SAAS,GAAG,CAAC,CAAC,GAAG,YAAY,EAAE,CAAC,CAAC;QAC7D,CAAC;QACD,OAAO;IACT,CAAC;IAED,qBAAqB;IACrB,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,CAAC;QAC5B,OAAO;IACT,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IACrC,MAAM,MAAM,GAA2B,EAAE,CAAC;IAE1C,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;QAC1B,MAAM,CAAC,GAAG,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC;IAC3B,CAAC;IAED,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,KAAK,MAAM,GAAG,IAAI,OAAO,EAAE,CAAC;YAC1B,MAAM,GAAG,GAAG,UAAU,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAC;YACjC,MAAM,CAAC,GAAG,CAAC,GAAG,IAAI,CAAC,GAAG,CAAC,MAAM,CAAC,GAAG,CAAC,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;QAClD,CAAC;IACH,CAAC;IAED,SAAS;IACT,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IAChF,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;IACpB,OAAO,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;IAElE,OAAO;IACP,KAAK,MAAM,GAAG,IAAI,IAAI,EAAE,CAAC;QACvB,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjF,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACpB,CAAC;AACH,CAAC;AAED,SAAS,UAAU,CAAC,KAAc;IAChC,IAAI,KAAK,KAAK,IAAI,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,GAAG,CAAC;IACtD,IAAI,OAAO,KAAK,KAAK,QAAQ;QAAE,OAAO,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5D,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;AACvB,CAAC"}
package/package.json CHANGED
@@ -1,56 +1,57 @@
1
- {
2
- "name": "@certen.io/cli",
3
- "version": "0.3.0",
4
- "description": "Command line for the CERTEN Gateway API",
5
- "license": "MIT",
6
- "type": "module",
7
- "keywords": [
8
- "certen",
9
- "accumulate",
10
- "cli",
11
- "blockchain"
12
- ],
13
- "homepage": "https://github.com/certenIO/certen-sdk#readme",
14
- "repository": {
15
- "type": "git",
16
- "url": "git+https://github.com/certenIO/certen-sdk.git",
17
- "directory": "packages/cli"
18
- },
19
- "bugs": {
20
- "url": "https://github.com/certenIO/certen-sdk/issues"
21
- },
22
- "engines": {
23
- "node": ">=18"
24
- },
25
- "bin": {
26
- "certen": "dist/index.js"
27
- },
28
- "//files": "Build output plus docs. Without this npm ships the whole directory, including src/ and test/.",
29
- "files": [
30
- "dist/",
31
- "README.md",
32
- "LICENSE"
33
- ],
34
- "scripts": {
35
- "build": "tsc",
36
- "test": "vitest run",
37
- "typecheck": "tsc --noEmit",
38
- "//prepack": "Build before packing so the published bin can never point at a missing dist/index.js.",
39
- "prepack": "npm run build",
40
- "prepublishOnly": "npm run build && npm test"
41
- },
42
- "publishConfig": {
43
- "access": "public"
44
- },
45
- "//dependencies": "@certen.io/sdk MUST be a version range, not file:../sdk. A published package carrying a file: dependency installs and then fails to resolve on the consumer's machine, because that path does not exist there. Local development uses `npm link` or a workspace instead.",
46
- "dependencies": {
47
- "@certen.io/sdk": "^0.3.0",
48
- "commander": "^12.0.0"
49
- },
50
- "devDependencies": {
51
- "typescript": "^5.5.0",
52
- "vitest": "^1.6.1",
53
- "@types/node": "^22.0.0"
54
- },
55
- "//publishConfig": "Provenance is passed as --provenance by .github/workflows/release.yml. Setting it here instead would break every publish outside CI with an error that does not explain itself."
56
- }
1
+ {
2
+ "name": "@certen.io/cli",
3
+ "version": "0.4.0",
4
+ "description": "Command line for the CERTEN Gateway API",
5
+ "license": "MIT",
6
+ "type": "module",
7
+ "keywords": [
8
+ "certen",
9
+ "accumulate",
10
+ "cli",
11
+ "blockchain"
12
+ ],
13
+ "homepage": "https://github.com/certenIO/certen-sdk#readme",
14
+ "repository": {
15
+ "type": "git",
16
+ "url": "git+https://github.com/certenIO/certen-sdk.git",
17
+ "directory": "packages/cli"
18
+ },
19
+ "bugs": {
20
+ "url": "https://github.com/certenIO/certen-sdk/issues"
21
+ },
22
+ "engines": {
23
+ "node": ">=18"
24
+ },
25
+ "bin": {
26
+ "certen": "dist/index.js"
27
+ },
28
+ "//files": "Build output plus docs. Without this npm ships the whole directory, including src/ and test/.",
29
+ "files": [
30
+ "dist/",
31
+ "CHANGELOG.md",
32
+ "README.md",
33
+ "LICENSE"
34
+ ],
35
+ "scripts": {
36
+ "build": "tsc",
37
+ "test": "vitest run",
38
+ "typecheck": "tsc --noEmit",
39
+ "//prepack": "Build before packing so the published bin can never point at a missing dist/index.js.",
40
+ "prepack": "npm run build",
41
+ "prepublishOnly": "npm run build && npm test"
42
+ },
43
+ "publishConfig": {
44
+ "access": "public"
45
+ },
46
+ "//dependencies": "@certen.io/sdk MUST be a version range, not file:../sdk. A published package carrying a file: dependency installs and then fails to resolve on the consumer's machine, because that path does not exist there. Local development uses `npm link` or a workspace instead.",
47
+ "dependencies": {
48
+ "@certen.io/sdk": "^0.4.0",
49
+ "commander": "^12.0.0"
50
+ },
51
+ "devDependencies": {
52
+ "typescript": "^5.5.0",
53
+ "vitest": "^1.6.1",
54
+ "@types/node": "^22.0.0"
55
+ },
56
+ "//publishConfig": "Provenance is passed as --provenance by .github/workflows/release.yml. Setting it here instead would break every publish outside CI with an error that does not explain itself."
57
+ }