@certen.io/cli 0.7.1 → 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,232 +1,232 @@
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>** · **Portal: <https://gateway.kompendium.co/portal>**
7
-
8
- ```bash
9
- npm install -g @certen.io/cli
10
- ```
11
-
12
- ## From nothing to a proof
13
-
14
- ```bash
15
- certen login # approve this machine once in the portal; the key arrives here
16
- certen init # signing key, identity, funding — created and checked
17
-
18
- certen call --identity <id> --chain base-sepolia --to 0xYourContract \
19
- --fn 'confirm(bytes32)' --arg 0x… --sign-with dev --wait
20
-
21
- certen proof get <intent-id> # the evidence, to hand to a counterparty
22
- ```
23
-
24
- **You never copy an API key.** `certen login` uses the device authorization grant: it prints a
25
- short code, you approve that code in a portal session you already trust, and the CLI collects the
26
- key over its own channel. The secret is never displayed here and never passes through your
27
- clipboard or your shell history.
28
-
29
- `certen init` is idempotent. It creates only what is missing, records the identity id so a later
30
- run reuses it, waits until the identity can actually sign, and tells you if an abstract account
31
- needs gas before it can execute anything.
32
-
33
- Stuck at any point:
34
-
35
- ```bash
36
- certen doctor # names the one thing blocking you, and the command that fixes it
37
- ```
38
-
39
- ### If your gateway predates device authorization
40
-
41
- `certen login` will say so and point at the portal. Mint a key there and hand it over without
42
- putting it in your shell history:
43
-
44
- ```bash
45
- certen auth login --api-key - # reads the key from stdin
46
- ```
47
-
48
- ## Your key never leaves this machine
49
-
50
- `certen keys generate` creates an Ed25519 key, encrypts it with a passphrase (scrypt + AES-256-GCM),
51
- and writes it to `~/.certen/keys/<name>.json` with `0600` permissions. The CLI sends **signatures**
52
- to the gateway. It never sends a private key, and there is no code path that could.
53
-
54
- ```bash
55
- certen keys generate --name dev # prompts for a passphrase (confirmed)
56
- certen keys generate --name ci --no-passphrase # unencrypted; file permissions only
57
- certen keys list # metadata only — never decrypts
58
- certen keys show dev
59
- certen keys verify dev # proves the key decrypts and signs correctly
60
- certen keys sign --name dev --hash <hex> # print a signature, send nothing
61
- certen keys delete dev --yes
62
- certen keys path
63
- ```
64
-
65
- Set `CERTEN_KEY_PASSPHRASE` to skip the prompt in CI. When it is set and there is no TTY, the CLI
66
- uses it; when neither is available it fails with an explanation rather than hanging on a prompt
67
- nobody can see.
68
-
69
- **`certen keys sign` sends nothing anywhere.** It is the air-gapped path: generate on one machine,
70
- carry the hash to it, carry the signature back.
71
-
72
- ## Proof-gated contract calls
73
-
74
- ```bash
75
- certen call --identity <uuid> --chain base-sepolia --to 0xTarget \
76
- --fn 'confirm(bytes32)' --arg 0x… --sign-with dev --wait
77
- ```
78
-
79
- `--fn` takes a Solidity signature and `--arg` repeats positionally. Arguments are checked against
80
- the signature **before** anything is sent — on a proof-gated call, a valid proof of the *wrong*
81
- call is still a valid proof, so a mis-encoded argument is worse than an error.
82
-
83
- The ADI URL, the abstract account (`msg.sender` on chain) and the numeric chain id are all derived
84
- from the identity. You do not supply them, and you should not need to know that omitting them
85
- produces a bodyless 502.
86
-
87
- `--dry-run` prints the intent that would be sent without sending it — also the starting point if
88
- you need a multi-leg intent, which you then pass to `tx create --intent @file.json`.
89
-
90
- ## Transfers
91
-
92
- ```bash
93
- certen tx create --identity <uuid> --to-chain ethereum-sepolia \
94
- --from 0xYourAbstractAccount --to 0xRecipient --amount 0.001 --sign-with dev --wait
95
- ```
96
-
97
- **`--amount` is in WHOLE UNITS.** `1` means one ETH, `0.5` means half. This is the field most
98
- worth reading twice: the gateway documented it as wei until 2026-08-11, and someone sending `1`
99
- meaning one wei moves a whole ETH — which on a funded account succeeds silently.
100
-
101
- `--from` is the identity's abstract account on the source chain; `certen portfolio` shows it.
102
-
103
- If that account has no gas, the CLI refuses before submitting. That refusal is worth having: an
104
- intent from an empty abstract account is accepted, signed and submitted — every step reports
105
- success — and then parks at `anchoring` forever, because the execution leg cannot run on chain.
106
- `--force` overrides it.
107
-
108
- Or drive the steps yourself — useful when the signer is an HSM, another machine, or your own
109
- policy engine:
110
-
111
- ```bash
112
- certen tx create --identity <uuid> ... # returns signing_data.hash_to_sign
113
- certen keys sign --name dev --hash <hash> # or your HSM
114
- certen tx sign <intent-id> --signature <sig> --public-key <pub>
115
- ```
116
-
117
- `--signature`/`--public-key` remain first-class. `--sign-with` is a convenience, not a replacement.
118
-
119
- ## Proofs
120
-
121
- ```bash
122
- certen proof get <intent-id> # also accepts a proof id or a transaction hash
123
- certen proof bundle <proof-id> # the artifact to hand over
124
- certen proof share <proof-id> # a link a counterparty opens without a key of yours
125
- certen proof verify <intent-id> # what was, and was NOT, verified
126
- ```
127
-
128
- `proof verify` reports three separate judgements — inclusion, authorization, outcome — and it can
129
- establish only the first, and only as something the gateway asserted. It says so. Asking the
130
- gateway is not independent verification; to verify without trusting CERTEN, query an Accumulate
131
- node for the receipt and read the execution on the destination chain.
132
-
133
- `proof get` falls back to the Accumulate merkle receipt when the proof-service is unavailable or
134
- when an intent has no `proof_id` — the normal case for governance and authorization transactions.
135
- A 5xx from the proof-service means that service is down, **not** that your proof is missing.
136
-
137
- ## Multi-party approvals
138
-
139
- ```bash
140
- certen pending list
141
- certen pending sign <id> --identity <adi> --vote approve
142
- certen pending submit <request-id> --sign-with dev --hash <hash>
143
- ```
144
-
145
- `--vote` takes `approve`, `reject`, or `abstain` — lowercase strings. Not `accept`, and not a
146
- number.
147
-
148
- ## Everything else
149
-
150
- ```bash
151
- certen chains # what CERTEN is deployed on (no API key needed)
152
- certen whoami # which key, which gateway, what standing
153
- certen identity get <id> | list | link-chain <id> --chain <chain> | retire <id> --yes
154
- certen portfolio # balances across every identity and chain
155
- certen tx status <id> --wait | tx list
156
- certen pricing # everything CERTEN charges for, in one call
157
- certen balance | quote --chain <chain> [--sku <sku>] | fund <amount> --chain <chain>
158
- certen governance add-delegate | set-threshold
159
- certen admin api-keys list | create | rotate | revoke
160
- certen admin audit-log | usage
161
- ```
162
-
163
- Run `certen <group> --help` for the flags on any of them, or `certen --help` for the whole tree
164
- grouped by where you are in the journey.
165
-
166
- ## Chains
167
-
168
- This CLI targets `ethereum-sepolia`, `base-sepolia` and `arbitrum-sepolia`. A chain outside that
169
- set is refused with the reason — and if the gateway genuinely serves it, the refusal says so
170
- rather than claiming it does not exist. `CERTEN_ALLOW_ANY_CHAIN=1` lifts the restriction.
171
-
172
- ## Scripting and AI agents: `--json`
173
-
174
- `--json` turns the CLI into a machine interface. It is a contract, documented in full in
175
- [docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md) and enforced by a conformance suite.
176
-
177
- ```bash
178
- certen --json tx status <id>
179
- # {"ok":true,"data":{"intent_id":"…","status":"completed"}}
180
-
181
- certen --json portfolio
182
- # {"ok":false,"error":{"code":"NETWORK_ERROR","message":"connect ECONNREFUSED","retryable":true,"status":0}}
183
- ```
184
-
185
- - **Exactly one JSON object on stdout**, nothing else. Every human-facing line goes to stderr.
186
- - **Exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway unreachable. Branch on
187
- these instead of parsing text. `3` guarantees nothing was submitted, so a retry cannot
188
- double-execute.
189
- - **`error.retryable`** comes from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
190
- give an identical retry decision.
191
- - **`certen --help --json`** returns the entire command tree — every command, flag and exit code — in
192
- one call.
193
-
194
- Without `--json`, output is the human table format as before. Do not parse it.
195
-
196
- ## Configuration
197
-
198
- | | |
199
- |---|---|
200
- | `CERTEN_API_KEY` | API key. Always wins, so CI never touches the keyring or config file. |
201
- | `CERTEN_API_URL` | Gateway base URL. Defaults to `https://gateway.kompendium.co`. |
202
- | `CERTEN_KEY_PASSPHRASE` | Passphrase for local signing keys. |
203
-
204
- `certen auth login` stores the API key in your OS keyring by default, or in
205
- `~/.certen/config.json` at `0600` with `--no-keyring`.
206
-
207
- ## Things that will bite you
208
-
209
- **Identity creation is asynchronous.** `identity create` returns `202` and provisioning continues.
210
- Poll until the status is terminal, and check `can_sign` — it derives from the on-chain key page, so
211
- it can read `true` while the status is still `creating`.
212
-
213
- **A proof cycle takes 60–110 seconds.** Real validator work, not a tunable delay. Do not wrap it in
214
- a 30-second timeout.
215
-
216
- **Sign the bytes, not the text.** If you are producing signatures outside this CLI: sign the raw
217
- bytes of the hash, do not hash it again, and do not sign the ASCII of the hex string. All three
218
- mistakes produce a well-formed 128-hex signature the gateway rejects. `certen keys sign` handles
219
- this for you.
220
-
221
- ## Documentation
222
-
223
- **<https://docs.kompendium.co>** — getting started, authentication, errors, idempotency, and
224
- task-shaped guides: onboarding an identity, external signing, proof-gating a contract call, M-of-N
225
- panels, and verifying a proof.
226
-
227
- The [live API reference](https://gateway.kompendium.co/reference) is generated from the running
228
- gateway and is authoritative — when a guide and the spec disagree, the spec is right.
229
-
230
- ## License
231
-
232
- 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>** · **Portal: <https://gateway.kompendium.co/portal>**
7
+
8
+ ```bash
9
+ npm install -g @certen.io/cli
10
+ ```
11
+
12
+ ## From nothing to a proof
13
+
14
+ ```bash
15
+ certen login # approve this machine once in the portal; the key arrives here
16
+ certen init # signing key, identity, funding — created and checked
17
+
18
+ certen call --identity <id> --chain base-sepolia --to 0xYourContract \
19
+ --fn 'confirm(bytes32)' --arg 0x… --sign-with dev --wait
20
+
21
+ certen proof get <intent-id> # the evidence, to hand to a counterparty
22
+ ```
23
+
24
+ **You never copy an API key.** `certen login` uses the device authorization grant: it prints a
25
+ short code, you approve that code in a portal session you already trust, and the CLI collects the
26
+ key over its own channel. The secret is never displayed here and never passes through your
27
+ clipboard or your shell history.
28
+
29
+ `certen init` is idempotent. It creates only what is missing, records the identity id so a later
30
+ run reuses it, waits until the identity can actually sign, and tells you if an abstract account
31
+ needs gas before it can execute anything.
32
+
33
+ Stuck at any point:
34
+
35
+ ```bash
36
+ certen doctor # names the one thing blocking you, and the command that fixes it
37
+ ```
38
+
39
+ ### If your gateway predates device authorization
40
+
41
+ `certen login` will say so and point at the portal. Mint a key there and hand it over without
42
+ putting it in your shell history:
43
+
44
+ ```bash
45
+ certen auth login --api-key - # reads the key from stdin
46
+ ```
47
+
48
+ ## Your key never leaves this machine
49
+
50
+ `certen keys generate` creates an Ed25519 key, encrypts it with a passphrase (scrypt + AES-256-GCM),
51
+ and writes it to `~/.certen/keys/<name>.json` with `0600` permissions. The CLI sends **signatures**
52
+ to the gateway. It never sends a private key, and there is no code path that could.
53
+
54
+ ```bash
55
+ certen keys generate --name dev # prompts for a passphrase (confirmed)
56
+ certen keys generate --name ci --no-passphrase # unencrypted; file permissions only
57
+ certen keys list # metadata only — never decrypts
58
+ certen keys show dev
59
+ certen keys verify dev # proves the key decrypts and signs correctly
60
+ certen keys sign --name dev --hash <hex> # print a signature, send nothing
61
+ certen keys delete dev --yes
62
+ certen keys path
63
+ ```
64
+
65
+ Set `CERTEN_KEY_PASSPHRASE` to skip the prompt in CI. When it is set and there is no TTY, the CLI
66
+ uses it; when neither is available it fails with an explanation rather than hanging on a prompt
67
+ nobody can see.
68
+
69
+ **`certen keys sign` sends nothing anywhere.** It is the air-gapped path: generate on one machine,
70
+ carry the hash to it, carry the signature back.
71
+
72
+ ## Proof-gated contract calls
73
+
74
+ ```bash
75
+ certen call --identity <uuid> --chain base-sepolia --to 0xTarget \
76
+ --fn 'confirm(bytes32)' --arg 0x… --sign-with dev --wait
77
+ ```
78
+
79
+ `--fn` takes a Solidity signature and `--arg` repeats positionally. Arguments are checked against
80
+ the signature **before** anything is sent — on a proof-gated call, a valid proof of the *wrong*
81
+ call is still a valid proof, so a mis-encoded argument is worse than an error.
82
+
83
+ The ADI URL, the abstract account (`msg.sender` on chain) and the numeric chain id are all derived
84
+ from the identity. You do not supply them, and you should not need to know that omitting them
85
+ produces a bodyless 502.
86
+
87
+ `--dry-run` prints the intent that would be sent without sending it — also the starting point if
88
+ you need a multi-leg intent, which you then pass to `tx create --intent @file.json`.
89
+
90
+ ## Transfers
91
+
92
+ ```bash
93
+ certen tx create --identity <uuid> --to-chain ethereum-sepolia \
94
+ --from 0xYourAbstractAccount --to 0xRecipient --amount 0.001 --sign-with dev --wait
95
+ ```
96
+
97
+ **`--amount` is in WHOLE UNITS.** `1` means one ETH, `0.5` means half. This is the field most
98
+ worth reading twice: the gateway documented it as wei until 2026-08-11, and someone sending `1`
99
+ meaning one wei moves a whole ETH — which on a funded account succeeds silently.
100
+
101
+ `--from` is the identity's abstract account on the source chain; `certen portfolio` shows it.
102
+
103
+ If that account has no gas, the CLI refuses before submitting. That refusal is worth having: an
104
+ intent from an empty abstract account is accepted, signed and submitted — every step reports
105
+ success — and then parks at `anchoring` forever, because the execution leg cannot run on chain.
106
+ `--force` overrides it.
107
+
108
+ Or drive the steps yourself — useful when the signer is an HSM, another machine, or your own
109
+ policy engine:
110
+
111
+ ```bash
112
+ certen tx create --identity <uuid> ... # returns signing_data.hash_to_sign
113
+ certen keys sign --name dev --hash <hash> # or your HSM
114
+ certen tx sign <intent-id> --signature <sig> --public-key <pub>
115
+ ```
116
+
117
+ `--signature`/`--public-key` remain first-class. `--sign-with` is a convenience, not a replacement.
118
+
119
+ ## Proofs
120
+
121
+ ```bash
122
+ certen proof get <intent-id> # also accepts a proof id or a transaction hash
123
+ certen proof bundle <proof-id> # the artifact to hand over
124
+ certen proof share <proof-id> # a link a counterparty opens without a key of yours
125
+ certen proof verify <intent-id> # what was, and was NOT, verified
126
+ ```
127
+
128
+ `proof verify` reports three separate judgements — inclusion, authorization, outcome — and it can
129
+ establish only the first, and only as something the gateway asserted. It says so. Asking the
130
+ gateway is not independent verification; to verify without trusting CERTEN, query an Accumulate
131
+ node for the receipt and read the execution on the destination chain.
132
+
133
+ `proof get` falls back to the Accumulate merkle receipt when the proof-service is unavailable or
134
+ when an intent has no `proof_id` — the normal case for governance and authorization transactions.
135
+ A 5xx from the proof-service means that service is down, **not** that your proof is missing.
136
+
137
+ ## Multi-party approvals
138
+
139
+ ```bash
140
+ certen pending list
141
+ certen pending sign <id> --identity <adi> --vote approve
142
+ certen pending submit <request-id> --sign-with dev --hash <hash>
143
+ ```
144
+
145
+ `--vote` takes `approve`, `reject`, or `abstain` — lowercase strings. Not `accept`, and not a
146
+ number.
147
+
148
+ ## Everything else
149
+
150
+ ```bash
151
+ certen chains # what CERTEN is deployed on (no API key needed)
152
+ certen whoami # which key, which gateway, what standing
153
+ certen identity get <id> | list | link-chain <id> --chain <chain> | retire <id> --yes
154
+ certen portfolio # balances across every identity and chain
155
+ certen tx status <id> --wait | tx list
156
+ certen pricing # everything CERTEN charges for, in one call
157
+ certen balance | quote --chain <chain> [--sku <sku>] | fund <amount> --chain <chain>
158
+ certen governance add-delegate | set-threshold
159
+ certen admin api-keys list | create | rotate | revoke
160
+ certen admin audit-log | usage
161
+ ```
162
+
163
+ Run `certen <group> --help` for the flags on any of them, or `certen --help` for the whole tree
164
+ grouped by where you are in the journey.
165
+
166
+ ## Chains
167
+
168
+ This CLI targets `ethereum-sepolia`, `base-sepolia` and `arbitrum-sepolia`. A chain outside that
169
+ set is refused with the reason — and if the gateway genuinely serves it, the refusal says so
170
+ rather than claiming it does not exist. `CERTEN_ALLOW_ANY_CHAIN=1` lifts the restriction.
171
+
172
+ ## Scripting and AI agents: `--json`
173
+
174
+ `--json` turns the CLI into a machine interface. It is a contract, documented in full in
175
+ [docs/CLI-CONTRACT.md](../../docs/CLI-CONTRACT.md) and enforced by a conformance suite.
176
+
177
+ ```bash
178
+ certen --json tx status <id>
179
+ # {"ok":true,"data":{"intent_id":"…","status":"completed"}}
180
+
181
+ certen --json portfolio
182
+ # {"ok":false,"error":{"code":"NETWORK_ERROR","message":"connect ECONNREFUSED","retryable":true,"status":0}}
183
+ ```
184
+
185
+ - **Exactly one JSON object on stdout**, nothing else. Every human-facing line goes to stderr.
186
+ - **Exit codes:** `0` ok · `1` operation failed · `2` usage error · `3` gateway unreachable. Branch on
187
+ these instead of parsing text. `3` guarantees nothing was submitted, so a retry cannot
188
+ double-execute.
189
+ - **`error.retryable`** comes from the SDK's own `CertenError.isRetryable`, so the CLI and the SDK
190
+ give an identical retry decision.
191
+ - **`certen --help --json`** returns the entire command tree — every command, flag and exit code — in
192
+ one call.
193
+
194
+ Without `--json`, output is the human table format as before. Do not parse it.
195
+
196
+ ## Configuration
197
+
198
+ | | |
199
+ |---|---|
200
+ | `CERTEN_API_KEY` | API key. Always wins, so CI never touches the keyring or config file. |
201
+ | `CERTEN_API_URL` | Gateway base URL. Defaults to `https://gateway.kompendium.co`. |
202
+ | `CERTEN_KEY_PASSPHRASE` | Passphrase for local signing keys. |
203
+
204
+ `certen auth login` stores the API key in your OS keyring by default, or in
205
+ `~/.certen/config.json` at `0600` with `--no-keyring`.
206
+
207
+ ## Things that will bite you
208
+
209
+ **Identity creation is asynchronous.** `identity create` returns `202` and provisioning continues.
210
+ Poll until the status is terminal, and check `can_sign` — it derives from the on-chain key page, so
211
+ it can read `true` while the status is still `creating`.
212
+
213
+ **A proof cycle takes 60–110 seconds.** Real validator work, not a tunable delay. Do not wrap it in
214
+ a 30-second timeout.
215
+
216
+ **Sign the bytes, not the text.** If you are producing signatures outside this CLI: sign the raw
217
+ bytes of the hash, do not hash it again, and do not sign the ASCII of the hex string. All three
218
+ mistakes produce a well-formed 128-hex signature the gateway rejects. `certen keys sign` handles
219
+ this for you.
220
+
221
+ ## Documentation
222
+
223
+ **<https://docs.kompendium.co>** — getting started, authentication, errors, idempotency, and
224
+ task-shaped guides: onboarding an identity, external signing, proof-gating a contract call, M-of-N
225
+ panels, and verifying a proof.
226
+
227
+ The [live API reference](https://gateway.kompendium.co/reference) is generated from the running
228
+ gateway and is authoritative — when a guide and the spec disagree, the spec is right.
229
+
230
+ ## License
231
+
232
+ MIT
@@ -116,8 +116,8 @@ export function registerChainsCommands(program) {
116
116
  hint('');
117
117
  hint('Detail for one: certen chains base-sepolia');
118
118
  });
119
- chains.addHelpText('after', `
120
- Registry version and Accumulate network are included in --json output.
119
+ chains.addHelpText('after', `
120
+ Registry version and Accumulate network are included in --json output.
121
121
  This command needs no API key, so it also answers "is the gateway up".`);
122
122
  }
123
123
  //# sourceMappingURL=chains.js.map
package/dist/help-root.js CHANGED
@@ -36,16 +36,16 @@ const GROUPS = [
36
36
  commands: ['portfolio', 'webhooks', 'oauth-clients', 'orgs', 'admin', 'scopes', 'errors'],
37
37
  },
38
38
  ];
39
- const QUICKSTART = `
40
- From nothing to a proof:
41
-
42
- certen login # approve this machine in the portal
43
- certen init # key, identity, funding — all checked
44
- certen call --identity <id> --chain base-sepolia --to 0xContract \\
45
- --fn 'confirm(bytes32)' --arg 0x... --sign-with dev --wait
46
- certen proof get <intent-id> # the evidence, to hand over
47
-
48
- Stuck? Run: certen doctor
39
+ const QUICKSTART = `
40
+ From nothing to a proof:
41
+
42
+ certen login # approve this machine in the portal
43
+ certen init # key, identity, funding — all checked
44
+ certen call --identity <id> --chain base-sepolia --to 0xContract \\
45
+ --fn 'confirm(bytes32)' --arg 0x... --sign-with dev --wait
46
+ certen proof get <intent-id> # the evidence, to hand over
47
+
48
+ Stuck? Run: certen doctor
49
49
  `;
50
50
  export function formatRootHelp(cmd, helper) {
51
51
  // Subcommands inherit this configuration, so anything that is not the root is handed straight
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- import { readFileSync } from 'node:fs';
2
+ import { readFileSync, realpathSync } from 'node:fs';
3
3
  import { dirname, join } from 'node:path';
4
4
  import { fileURLToPath, pathToFileURL } from 'node:url';
5
5
  import { Command, CommanderError } from 'commander';
@@ -143,11 +143,41 @@ export async function run(argv) {
143
143
  }
144
144
  }
145
145
  /* c8 ignore start — entrypoint wiring, exercised by the conformance suite as a subprocess */
146
- // Run only when executed as the binary, not when imported by a test. `pathToFileURL` is what makes
147
- // this correct on Windows, where a naive `file://` + path concatenation produces a URL that never
148
- // matches `import.meta.url`.
149
- const invokedDirectly = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
150
- if (invokedDirectly) {
146
+ /**
147
+ * Was this file run as the program, rather than imported by a test?
148
+ *
149
+ * `import.meta.url` is always the REAL path of this module — node resolves symlinks before it
150
+ * records one. `process.argv[1]` is not: it is the path as typed. Every POSIX install of this
151
+ * package puts a SYMLINK at `node_modules/.bin/certen` pointing into `dist/`, and `npx` is no
152
+ * exception, so on Linux and macOS the two strings never matched and this comparison was false
153
+ * for every real user. The CLI then did nothing at all: no parse, no request, no output, exit 0.
154
+ * "It seems to run and prints nothing" is exactly what a silent `if` at the bottom of a binary
155
+ * looks like from outside.
156
+ *
157
+ * Windows hid it, which is why it shipped. npm writes a `.cmd` shim there instead of a symlink,
158
+ * and the shim invokes node on the real path — so argv[1] arrived already resolved and the guard
159
+ * passed. Every test hid it too: they all spawn `node dist/index.js` directly, never through the
160
+ * installed bin, which is the only path with a symlink in it.
161
+ *
162
+ * Resolving argv[1] the way node already resolved `import.meta.url` is what makes the two
163
+ * comparable. `realpathSync` throws on a path that does not exist, and a path that does not
164
+ * exist is not this module either way, so the fallback is the unresolved string rather than a
165
+ * crash in the first statement the binary runs.
166
+ */
167
+ function isMainModule() {
168
+ const argv1 = process.argv[1];
169
+ if (!argv1)
170
+ return false;
171
+ let resolved = argv1;
172
+ try {
173
+ resolved = realpathSync(argv1);
174
+ }
175
+ catch {
176
+ // Ignored: see above — the comparison below reaches the same answer without throwing.
177
+ }
178
+ return import.meta.url === pathToFileURL(resolved).href;
179
+ }
180
+ if (isMainModule()) {
151
181
  run(process.argv).then((code) => {
152
182
  process.exitCode = code;
153
183
  });
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,YAAY,EAAE,MAAM,SAAS,CAAC;AACrD,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;AAC5D,OAAO,EAAE,uBAAuB,EAAE,MAAM,uBAAuB,CAAC;AAChE,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAC;AAC5D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,oBAAoB,EAAE,MAAM,oBAAoB,CAAC;AAC1D,OAAO,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAC9D,OAAO,EAAE,uBAAuB,EAAE,MAAM,wBAAwB,CAAC;AACjE,OAAO,EAAE,2BAA2B,EAAE,MAAM,6BAA6B,CAAC;AAC1E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AACzD,OAAO,EAAE,sBAAsB,EAAE,MAAM,gCAAgC,CAAC;AACxE,OAAO,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAEhD,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,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAChC,wBAAwB,CAAC,OAAO,CAAC,CAAC;IAClC,2BAA2B,CAAC,OAAO,CAAC,CAAC;IACrC,oBAAoB,CAAC,OAAO,CAAC,CAAC;IAC9B,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC/B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,0BAA0B,CAAC,OAAO,CAAC,CAAC;IACpC,yBAAyB,CAAC,OAAO,CAAC,CAAC;IACnC,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,qBAAqB,CAAC,OAAO,CAAC,CAAC;IAC/B,uBAAuB,CAAC,OAAO,CAAC,CAAC;IACjC,2BAA2B,CAAC,OAAO,CAAC,CAAC;IACrC,mBAAmB,CAAC,OAAO,CAAC,CAAC;IAC7B,sBAAsB,CAAC,OAAO,CAAC,CAAC;IAEhC,iGAAiG;IACjG,kGAAkG;IAClG,kGAAkG;IAClG,mEAAmE;IACnE,iBAAiB,CAAC,OAAO,CAAC,CAAC;IAE3B,sFAAsF;IACtF,uFAAuF;IACvF,gCAAgC;IAChC,OAAO,CAAC,aAAa,CAAC,EAAE,UAAU,EAAE,cAAc,EAAE,CAAC,CAAC;IACtD,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,4CAA4C;QAC5C,EAAE;QACF,+EAA+E;QAC/E,+EAA+E;QAC/E,4EAA4E;QAC5E,sEAAsE;QACtE,EAAE;QACF,+EAA+E;QAC/E,gFAAgF;QAChF,2CAA2C;QAC3C,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC;IAC1B,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;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,SAAS,YAAY;IACnB,MAAM,KAAK,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK;QAAE,OAAO,KAAK,CAAC;IACzB,IAAI,QAAQ,GAAG,KAAK,CAAC;IACrB,IAAI,CAAC;QACH,QAAQ,GAAG,YAAY,CAAC,KAAK,CAAC,CAAC;IACjC,CAAC;IAAC,MAAM,CAAC;QACP,sFAAsF;IACxF,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,GAAG,KAAK,aAAa,CAAC,QAAQ,CAAC,CAAC,IAAI,CAAC;AAC1D,CAAC;AAED,IAAI,YAAY,EAAE,EAAE,CAAC;IACnB,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"}