@orangecheck/agent-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 OrangeCheck
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,134 @@
1
+ # @orangecheck/agent-cli
2
+
3
+ Command-line tool for [OC Agent](https://github.com/orangecheck/oc-agent-protocol). Verify, inspect, canonicalize, and reason about delegation / action / revocation envelopes from your shell. Exits 0 on success, 1 on any error. Every command supports `--json` for script-friendly output.
4
+
5
+ ## Install
6
+
7
+ ```bash
8
+ npm i -g @orangecheck/agent-cli
9
+ # or run once, no install:
10
+ npx @orangecheck/agent-cli verify delegation.json
11
+ ```
12
+
13
+ ## Commands
14
+
15
+ ### `oc-agent verify <file>`
16
+
17
+ Verify an envelope. Accepts a single envelope, or an array `[delegation, action|revocation]` for full authority verification. Runs the §SPEC 8 algorithm including BIP-322 signature check.
18
+
19
+ ```bash
20
+ oc-agent verify delegation.json
21
+ # → OK · delegation verified
22
+ # id: 36d79600…
23
+
24
+ oc-agent verify '[delegation.json-contents, action.json-contents]'
25
+ # → OK · action + delegation verified
26
+ ```
27
+
28
+ Flags:
29
+ - `--skip-sig` — skip BIP-322 signature verification (useful for test vectors with placeholder sigs)
30
+ - `--skip-temporal` — skip `issued_at` / `expires_at` checks (for inspecting historical envelopes)
31
+ - `--json` — emit machine-readable JSON
32
+
33
+ Exits `1` with an error code on rejection:
34
+ ```
35
+ oc-agent verify tampered.json
36
+ # → REJECTED · E_BAD_ID
37
+ # reconstructed id (…) does not match envelope.id (…)
38
+ ```
39
+
40
+ ### `oc-agent inspect <file>`
41
+
42
+ Pretty-print an envelope with key fields and the recomputed id. Works on any kind (delegation / action / revocation).
43
+
44
+ ```bash
45
+ oc-agent inspect delegation.json
46
+ # → kind: agent-delegation
47
+ # id: 36d79…
48
+ # id(recomputed): 36d79… ✓
49
+ # principal: bc1qalice…
50
+ # agent: bc1qagent…
51
+ # scopes:
52
+ # - ln:send(max_sats<=1000,node=03abc)
53
+ ```
54
+
55
+ ### `oc-agent canonical <file>`
56
+
57
+ Print the canonical message the envelope commits to (what a signer actually signed via BIP-322). Useful for debugging id mismatches — just diff two runs.
58
+
59
+ ```bash
60
+ oc-agent canonical delegation.json
61
+ # → oc-agent:delegation:v1
62
+ # principal: bc1qalice…
63
+ # agent: bc1qagent…
64
+ # scopes: lock:seal(recipient=bc1qbob)
65
+ # bond_sats: 0
66
+ # bond_attestation: none
67
+ # issued_at: 2026-04-22T12:00:00Z
68
+ # expires_at: 2026-04-29T12:00:00Z
69
+ # nonce: 0123…cdef
70
+ ```
71
+
72
+ ### `oc-agent scope <string>`
73
+
74
+ Parse a scope string and print its canonical form plus the registered-key check.
75
+
76
+ ```bash
77
+ oc-agent scope 'ln:send(node=03abc,max_sats<=1000)'
78
+ # → ok
79
+ # canonical: ln:send(max_sats<=1000,node=03abc)
80
+ # product: ln
81
+ # verb: send
82
+ # registered: yes
83
+ # constraints:
84
+ # - node = 03abc
85
+ # - max_sats <= 1000
86
+ ```
87
+
88
+ Flags:
89
+ - `--permissive` — accept unregistered products, verbs, and constraint keys
90
+ - `--json` — machine-readable output
91
+
92
+ ### `oc-agent subscope <granted> <exercised>`
93
+
94
+ Check whether `exercised` is a sub-scope of `granted` per [SPEC §7.4](https://github.com/orangecheck/oc-agent-protocol/blob/main/SPEC.md#74-sub-scope-relation). Exits 0 (admitted) or 1 (rejected).
95
+
96
+ ```bash
97
+ oc-agent subscope 'ln:send(max_sats<=1000)' 'ln:send(max_sats=500,node=03abc)'
98
+ # → admitted
99
+
100
+ oc-agent subscope 'stamp:sign(mime=text/markdown)' 'stamp:sign(mime=application/pdf)'
101
+ # → rejected (E_SCOPE_DENIED)
102
+ # (exit 1)
103
+ ```
104
+
105
+ Great for CI: gate a PR merge on an exercised scope matching a granted grant.
106
+
107
+ ## Use with stdin
108
+
109
+ Every file-taking command accepts `-` to read from stdin:
110
+
111
+ ```bash
112
+ curl -s https://agent.example.com/delegations/abc.json | oc-agent verify -
113
+ ```
114
+
115
+ ## Composing with other tools
116
+
117
+ ```bash
118
+ # Pretty-print every delegation under ~/delegations/
119
+ find ~/delegations -name '*.json' -exec oc-agent inspect {} \;
120
+
121
+ # Fail the pipeline on any rejected envelope
122
+ for f in *.delegation.json; do
123
+ oc-agent verify "$f" --json || { echo "bad: $f"; exit 1; }
124
+ done
125
+
126
+ # Batch scope check from a CSV
127
+ while IFS=, read -r granted exercised; do
128
+ oc-agent subscope "$granted" "$exercised" --json
129
+ done < pairs.csv
130
+ ```
131
+
132
+ ## License
133
+
134
+ MIT. See [LICENSE](./LICENSE).
package/dist/cli.js ADDED
@@ -0,0 +1,251 @@
1
+ #!/usr/bin/env node
2
+ import { readFile } from 'fs/promises';
3
+ import { verifyAction, verifyRevocation, verifyDelegation, parseScope, validateScope, canonicalizeScope, REGISTERED_SCOPES, isSubScope, computeDelegationId, computeActionId, computeRevocationId, delegationCanonicalMessage, actionCanonicalMessage, revocationCanonicalMessage } from '@orangecheck/agent-core';
4
+ import { Verifier } from 'bip322-js';
5
+ import { Command } from 'commander';
6
+
7
+ var program = new Command();
8
+ program.name("oc-agent").description("command-line verifier for OC Agent envelopes").version("0.1.0");
9
+ program.command("verify").description(
10
+ "verify an envelope (delegation / action / revocation). accepts a single envelope, or an array [delegation, action|revocation] for full authority verification."
11
+ ).argument("<file>", 'path to the envelope JSON file, or "-" for stdin').option("--json", "machine-readable JSON output", false).option("--skip-sig", "skip BIP-322 signature verification", false).option("--skip-temporal", "skip issued_at / expires_at checks", false).action(async (file, opts) => {
12
+ const parsed = JSON.parse(await read(file));
13
+ const verifyBip322 = opts.skipSig ? void 0 : async (msg, sig, addr) => {
14
+ try {
15
+ return Verifier.verifySignature(addr, msg, sig);
16
+ } catch {
17
+ return false;
18
+ }
19
+ };
20
+ if (Array.isArray(parsed) && parsed.length === 2) {
21
+ const [d, a] = parsed;
22
+ if (a.kind === "agent-action") {
23
+ const r = await verifyAction({
24
+ action: a,
25
+ delegation: d,
26
+ verifyBip322,
27
+ skipSignatureVerification: opts.skipSig
28
+ });
29
+ report(r, opts.json, "action + delegation");
30
+ return;
31
+ }
32
+ if (a.kind === "agent-revocation") {
33
+ const r = await verifyRevocation({
34
+ envelope: a,
35
+ delegation: d,
36
+ verifyBip322,
37
+ skipSignatureVerification: opts.skipSig
38
+ });
39
+ report(r, opts.json, "revocation + delegation");
40
+ return;
41
+ }
42
+ die(opts.json, "UNKNOWN_PAIR", `unknown second envelope kind: ${a.kind}`);
43
+ }
44
+ const env = parsed;
45
+ if (env.kind === "agent-delegation") {
46
+ const r = await verifyDelegation({
47
+ envelope: env,
48
+ verifyBip322,
49
+ skipSignatureVerification: opts.skipSig,
50
+ skipTemporalCheck: opts.skipTemporal
51
+ });
52
+ report(r, opts.json, "delegation");
53
+ return;
54
+ }
55
+ if (env.kind === "agent-action") {
56
+ die(
57
+ opts.json,
58
+ "NEED_DELEGATION",
59
+ "an action envelope needs the cited delegation. pass an array: [delegation, action]."
60
+ );
61
+ }
62
+ if (env.kind === "agent-revocation") {
63
+ die(
64
+ opts.json,
65
+ "NEED_DELEGATION",
66
+ "a revocation envelope needs the cited delegation. pass an array: [delegation, revocation]."
67
+ );
68
+ }
69
+ die(opts.json, "UNKNOWN_KIND", `unknown envelope kind: ${env.kind}`);
70
+ });
71
+ program.command("inspect").description("pretty-print an envelope with key fields and a recomputed id.").argument("<file>", 'path to the envelope JSON file, or "-" for stdin').option("--json", "machine-readable JSON output", false).action(async (file, opts) => {
72
+ const env = JSON.parse(await read(file));
73
+ const recomputed = recomputeId(env);
74
+ if (opts.json) {
75
+ console.log(JSON.stringify({ envelope: env, recomputed_id: recomputed }, null, 2));
76
+ return;
77
+ }
78
+ console.log(`kind: ${env.kind}`);
79
+ console.log(`v: ${env.v}`);
80
+ console.log(`id: ${env.id}`);
81
+ console.log(`id(recomputed): ${recomputed} ${recomputed === env.id ? "\u2713" : "\u2717"}`);
82
+ if (env.kind === "agent-delegation") {
83
+ console.log(`principal: ${env.principal.address}`);
84
+ console.log(`agent: ${env.agent.address}`);
85
+ console.log(`issued: ${env.issued_at}`);
86
+ console.log(`expires: ${env.expires_at}`);
87
+ if (env.bond) {
88
+ console.log(`bond: ${env.bond.sats.toLocaleString()} sats \xB7 attestation=${env.bond.attestation_id}`);
89
+ } else {
90
+ console.log(`bond: none`);
91
+ }
92
+ console.log(`scopes:`);
93
+ for (const s of env.scopes) console.log(` - ${s}`);
94
+ } else if (env.kind === "agent-action") {
95
+ console.log(`agent: ${env.signer.address}`);
96
+ console.log(`signed_at: ${env.signed_at}`);
97
+ console.log(`delegation_id: ${env.delegation_id}`);
98
+ console.log(`scope_exercised: ${env.scope_exercised}`);
99
+ console.log(`content.hash: ${env.content.hash}`);
100
+ console.log(`content.length: ${env.content.length}`);
101
+ console.log(`content.mime: ${env.content.mime}`);
102
+ console.log(`ots: ${env.ots?.status ?? "none"}`);
103
+ } else if (env.kind === "agent-revocation") {
104
+ console.log(`signer: ${env.signer.address}`);
105
+ console.log(`delegation_id: ${env.delegation_id}`);
106
+ console.log(`reason: ${env.reason || "(none)"}`);
107
+ console.log(`signed_at: ${env.signed_at}`);
108
+ console.log(`ots: ${env.ots?.status ?? "none"}`);
109
+ }
110
+ });
111
+ program.command("canonical").description("print the canonical message that an envelope commits to.").argument("<file>", 'path to the envelope JSON file, or "-" for stdin').action(async (file) => {
112
+ const env = JSON.parse(await read(file));
113
+ process.stdout.write(canonicalMessageFor(env));
114
+ });
115
+ program.command("scope").description("parse a scope string and print its canonical form + registered-key check.").argument("<scope>", 'the scope string, e.g. "ln:send(max_sats<=1000)"').option("--json", "machine-readable JSON output", false).option("--permissive", "accept unregistered products / verbs / keys", false).action((scope, opts) => {
116
+ try {
117
+ const parsed = parseScope(scope);
118
+ validateScope(parsed, { mode: opts.permissive ? "permissive" : "strict" });
119
+ const canonical = canonicalizeScope(parsed);
120
+ const registered = !!REGISTERED_SCOPES[`${parsed.product}:${parsed.verb}`];
121
+ if (opts.json) {
122
+ console.log(JSON.stringify({ ok: true, canonical, parsed, registered }, null, 2));
123
+ } else {
124
+ console.log(`ok`);
125
+ console.log(`canonical: ${canonical}`);
126
+ console.log(`product: ${parsed.product}`);
127
+ console.log(`verb: ${parsed.verb}`);
128
+ console.log(`registered: ${registered ? "yes" : "NO (strict mode would reject)"}`);
129
+ if (parsed.constraints.length > 0) {
130
+ console.log(`constraints:`);
131
+ for (const c of parsed.constraints) {
132
+ console.log(` - ${c.key} ${c.op} ${c.value ?? "(wildcard)"}`);
133
+ }
134
+ }
135
+ }
136
+ } catch (e) {
137
+ die(opts.json, "E_BAD_SCOPE_GRAMMAR", e.message);
138
+ }
139
+ });
140
+ program.command("subscope").description("check whether exercised scope is a sub-scope of granted.").argument("<granted>", "the granted scope string").argument("<exercised>", "the exercised scope string").option("--json", "machine-readable JSON output", false).action((granted, exercised, opts) => {
141
+ try {
142
+ const g = parseScope(granted);
143
+ const e = parseScope(exercised);
144
+ const admitted = isSubScope(e, g);
145
+ if (opts.json) {
146
+ console.log(JSON.stringify({ admitted }));
147
+ } else {
148
+ console.log(admitted ? "admitted" : "rejected (E_SCOPE_DENIED)");
149
+ }
150
+ if (!admitted) process.exit(1);
151
+ } catch (err) {
152
+ die(opts.json, "E_BAD_SCOPE_GRAMMAR", err.message);
153
+ }
154
+ });
155
+ async function read(path) {
156
+ if (path === "-") {
157
+ let acc = "";
158
+ for await (const chunk of process.stdin) acc += chunk;
159
+ return acc;
160
+ }
161
+ return readFile(path, "utf8");
162
+ }
163
+ function recomputeId(env) {
164
+ if (env.kind === "agent-delegation") {
165
+ return computeDelegationId({
166
+ principal: env.principal.address,
167
+ agent: env.agent.address,
168
+ scopes: env.scopes,
169
+ bond_sats: env.bond?.sats ?? 0,
170
+ bond_attestation: env.bond?.attestation_id ?? "none",
171
+ issued_at: env.issued_at,
172
+ expires_at: env.expires_at,
173
+ nonce: env.nonce
174
+ });
175
+ }
176
+ if (env.kind === "agent-action") {
177
+ return computeActionId({
178
+ address: env.signer.address,
179
+ content_hash: env.content.hash,
180
+ content_length: env.content.length,
181
+ content_mime: env.content.mime,
182
+ signed_at: env.signed_at,
183
+ delegation_id: env.delegation_id,
184
+ scope_exercised: env.scope_exercised
185
+ });
186
+ }
187
+ return computeRevocationId({
188
+ address: env.signer.address,
189
+ delegation_id: env.delegation_id,
190
+ reason: env.reason,
191
+ signed_at: env.signed_at
192
+ });
193
+ }
194
+ function canonicalMessageFor(env) {
195
+ if (env.kind === "agent-delegation") {
196
+ return delegationCanonicalMessage({
197
+ principal: env.principal.address,
198
+ agent: env.agent.address,
199
+ scopes: env.scopes,
200
+ bond_sats: env.bond?.sats ?? 0,
201
+ bond_attestation: env.bond?.attestation_id ?? "none",
202
+ issued_at: env.issued_at,
203
+ expires_at: env.expires_at,
204
+ nonce: env.nonce
205
+ });
206
+ }
207
+ if (env.kind === "agent-action") {
208
+ return actionCanonicalMessage({
209
+ address: env.signer.address,
210
+ content_hash: env.content.hash,
211
+ content_length: env.content.length,
212
+ content_mime: env.content.mime,
213
+ signed_at: env.signed_at,
214
+ delegation_id: env.delegation_id,
215
+ scope_exercised: env.scope_exercised
216
+ });
217
+ }
218
+ return revocationCanonicalMessage({
219
+ address: env.signer.address,
220
+ delegation_id: env.delegation_id,
221
+ reason: env.reason,
222
+ signed_at: env.signed_at
223
+ });
224
+ }
225
+ function report(result, asJson, what) {
226
+ if (result.ok) {
227
+ if (asJson) {
228
+ console.log(JSON.stringify({ ok: true, verified: what, id: result.id }));
229
+ } else {
230
+ console.log(`OK \xB7 ${what} verified`);
231
+ console.log(` id: ${result.id}`);
232
+ }
233
+ return;
234
+ }
235
+ die(asJson, result.code, result.message);
236
+ }
237
+ function die(asJson, code, message) {
238
+ if (asJson) {
239
+ console.error(JSON.stringify({ ok: false, code, message }));
240
+ } else {
241
+ console.error(`REJECTED \xB7 ${code}`);
242
+ console.error(` ${message}`);
243
+ }
244
+ process.exit(1);
245
+ }
246
+ program.parseAsync().catch((err) => {
247
+ console.error(err.message);
248
+ process.exit(1);
249
+ });
250
+ //# sourceMappingURL=cli.js.map
251
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli.ts"],"names":[],"mappings":"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","file":"cli.js","sourcesContent":["// oc-agent — command-line tool for OC Agent v1 envelopes.\n//\n// Verify, inspect, canonicalize, and check scope containment against the\n// same @orangecheck/agent-core the reference web client uses. Exits 0 on\n// success, 1 on any verification/parse error; every command supports --json\n// for script-friendly output.\n\nimport { readFile } from 'node:fs/promises';\n\nimport {\n actionCanonicalMessage,\n canonicalizeScope,\n computeActionId,\n computeDelegationId,\n computeRevocationId,\n delegationCanonicalMessage,\n isSubScope,\n parseScope,\n REGISTERED_SCOPES,\n revocationCanonicalMessage,\n validateScope,\n verifyAction,\n verifyDelegation,\n verifyRevocation,\n type ActionEnvelope,\n type DelegationEnvelope,\n type RevocationEnvelope,\n} from '@orangecheck/agent-core';\nimport { Verifier } from 'bip322-js';\nimport { Command } from 'commander';\n\ntype AnyEnvelope = DelegationEnvelope | ActionEnvelope | RevocationEnvelope;\n\nconst program = new Command();\n\nprogram\n .name('oc-agent')\n .description('command-line verifier for OC Agent envelopes')\n .version('0.1.0');\n\n// ─────────────────────────────────────────────────────────────────────────────\n// verify\n// ─────────────────────────────────────────────────────────────────────────────\n\nprogram\n .command('verify')\n .description(\n 'verify an envelope (delegation / action / revocation). accepts a single envelope, or an array [delegation, action|revocation] for full authority verification.'\n )\n .argument('<file>', 'path to the envelope JSON file, or \"-\" for stdin')\n .option('--json', 'machine-readable JSON output', false)\n .option('--skip-sig', 'skip BIP-322 signature verification', false)\n .option('--skip-temporal', 'skip issued_at / expires_at checks', false)\n .action(async (file: string, opts: { json: boolean; skipSig: boolean; skipTemporal: boolean }) => {\n const parsed = JSON.parse(await read(file));\n\n const verifyBip322 = opts.skipSig\n ? undefined\n : async (msg: string, sig: string, addr: string) => {\n try {\n return Verifier.verifySignature(addr, msg, sig);\n } catch {\n return false;\n }\n };\n\n if (Array.isArray(parsed) && parsed.length === 2) {\n const [d, a] = parsed as [DelegationEnvelope, ActionEnvelope | RevocationEnvelope];\n if (a.kind === 'agent-action') {\n const r = await verifyAction({\n action: a,\n delegation: d,\n verifyBip322,\n skipSignatureVerification: opts.skipSig,\n });\n report(r, opts.json, 'action + delegation');\n return;\n }\n if (a.kind === 'agent-revocation') {\n const r = await verifyRevocation({\n envelope: a,\n delegation: d,\n verifyBip322,\n skipSignatureVerification: opts.skipSig,\n });\n report(r, opts.json, 'revocation + delegation');\n return;\n }\n die(opts.json, 'UNKNOWN_PAIR', `unknown second envelope kind: ${(a as AnyEnvelope).kind}`);\n }\n\n const env = parsed as AnyEnvelope;\n if (env.kind === 'agent-delegation') {\n const r = await verifyDelegation({\n envelope: env,\n verifyBip322,\n skipSignatureVerification: opts.skipSig,\n skipTemporalCheck: opts.skipTemporal,\n });\n report(r, opts.json, 'delegation');\n return;\n }\n if (env.kind === 'agent-action') {\n die(\n opts.json,\n 'NEED_DELEGATION',\n 'an action envelope needs the cited delegation. pass an array: [delegation, action].'\n );\n }\n if (env.kind === 'agent-revocation') {\n die(\n opts.json,\n 'NEED_DELEGATION',\n 'a revocation envelope needs the cited delegation. pass an array: [delegation, revocation].'\n );\n }\n die(opts.json, 'UNKNOWN_KIND', `unknown envelope kind: ${(env as AnyEnvelope).kind}`);\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// inspect\n// ─────────────────────────────────────────────────────────────────────────────\n\nprogram\n .command('inspect')\n .description('pretty-print an envelope with key fields and a recomputed id.')\n .argument('<file>', 'path to the envelope JSON file, or \"-\" for stdin')\n .option('--json', 'machine-readable JSON output', false)\n .action(async (file: string, opts: { json: boolean }) => {\n const env = JSON.parse(await read(file)) as AnyEnvelope;\n const recomputed = recomputeId(env);\n if (opts.json) {\n console.log(JSON.stringify({ envelope: env, recomputed_id: recomputed }, null, 2));\n return;\n }\n console.log(`kind: ${env.kind}`);\n console.log(`v: ${env.v}`);\n console.log(`id: ${env.id}`);\n console.log(`id(recomputed): ${recomputed} ${recomputed === env.id ? '✓' : '✗'}`);\n if (env.kind === 'agent-delegation') {\n console.log(`principal: ${env.principal.address}`);\n console.log(`agent: ${env.agent.address}`);\n console.log(`issued: ${env.issued_at}`);\n console.log(`expires: ${env.expires_at}`);\n if (env.bond) {\n console.log(`bond: ${env.bond.sats.toLocaleString()} sats · attestation=${env.bond.attestation_id}`);\n } else {\n console.log(`bond: none`);\n }\n console.log(`scopes:`);\n for (const s of env.scopes) console.log(` - ${s}`);\n } else if (env.kind === 'agent-action') {\n console.log(`agent: ${env.signer.address}`);\n console.log(`signed_at: ${env.signed_at}`);\n console.log(`delegation_id: ${env.delegation_id}`);\n console.log(`scope_exercised: ${env.scope_exercised}`);\n console.log(`content.hash: ${env.content.hash}`);\n console.log(`content.length: ${env.content.length}`);\n console.log(`content.mime: ${env.content.mime}`);\n console.log(`ots: ${env.ots?.status ?? 'none'}`);\n } else if (env.kind === 'agent-revocation') {\n console.log(`signer: ${env.signer.address}`);\n console.log(`delegation_id: ${env.delegation_id}`);\n console.log(`reason: ${env.reason || '(none)'}`);\n console.log(`signed_at: ${env.signed_at}`);\n console.log(`ots: ${env.ots?.status ?? 'none'}`);\n }\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// canonical\n// ─────────────────────────────────────────────────────────────────────────────\n\nprogram\n .command('canonical')\n .description('print the canonical message that an envelope commits to.')\n .argument('<file>', 'path to the envelope JSON file, or \"-\" for stdin')\n .action(async (file: string) => {\n const env = JSON.parse(await read(file)) as AnyEnvelope;\n process.stdout.write(canonicalMessageFor(env));\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// scope\n// ─────────────────────────────────────────────────────────────────────────────\n\nprogram\n .command('scope')\n .description('parse a scope string and print its canonical form + registered-key check.')\n .argument('<scope>', 'the scope string, e.g. \"ln:send(max_sats<=1000)\"')\n .option('--json', 'machine-readable JSON output', false)\n .option('--permissive', 'accept unregistered products / verbs / keys', false)\n .action((scope: string, opts: { json: boolean; permissive: boolean }) => {\n try {\n const parsed = parseScope(scope);\n validateScope(parsed, { mode: opts.permissive ? 'permissive' : 'strict' });\n const canonical = canonicalizeScope(parsed);\n const registered = !!REGISTERED_SCOPES[`${parsed.product}:${parsed.verb}`];\n if (opts.json) {\n console.log(JSON.stringify({ ok: true, canonical, parsed, registered }, null, 2));\n } else {\n console.log(`ok`);\n console.log(`canonical: ${canonical}`);\n console.log(`product: ${parsed.product}`);\n console.log(`verb: ${parsed.verb}`);\n console.log(`registered: ${registered ? 'yes' : 'NO (strict mode would reject)'}`);\n if (parsed.constraints.length > 0) {\n console.log(`constraints:`);\n for (const c of parsed.constraints) {\n console.log(` - ${c.key} ${c.op} ${c.value ?? '(wildcard)'}`);\n }\n }\n }\n } catch (e) {\n die(opts.json, 'E_BAD_SCOPE_GRAMMAR', (e as Error).message);\n }\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// subscope\n// ─────────────────────────────────────────────────────────────────────────────\n\nprogram\n .command('subscope')\n .description('check whether exercised scope is a sub-scope of granted.')\n .argument('<granted>', 'the granted scope string')\n .argument('<exercised>', 'the exercised scope string')\n .option('--json', 'machine-readable JSON output', false)\n .action((granted: string, exercised: string, opts: { json: boolean }) => {\n try {\n const g = parseScope(granted);\n const e = parseScope(exercised);\n const admitted = isSubScope(e, g);\n if (opts.json) {\n console.log(JSON.stringify({ admitted }));\n } else {\n console.log(admitted ? 'admitted' : 'rejected (E_SCOPE_DENIED)');\n }\n if (!admitted) process.exit(1);\n } catch (err) {\n die(opts.json, 'E_BAD_SCOPE_GRAMMAR', (err as Error).message);\n }\n });\n\n// ─────────────────────────────────────────────────────────────────────────────\n// helpers\n// ─────────────────────────────────────────────────────────────────────────────\n\nasync function read(path: string): Promise<string> {\n if (path === '-') {\n let acc = '';\n for await (const chunk of process.stdin) acc += chunk;\n return acc;\n }\n return readFile(path, 'utf8');\n}\n\nfunction recomputeId(env: AnyEnvelope): string {\n if (env.kind === 'agent-delegation') {\n return computeDelegationId({\n principal: env.principal.address,\n agent: env.agent.address,\n scopes: env.scopes,\n bond_sats: env.bond?.sats ?? 0,\n bond_attestation: env.bond?.attestation_id ?? 'none',\n issued_at: env.issued_at,\n expires_at: env.expires_at,\n nonce: env.nonce,\n });\n }\n if (env.kind === 'agent-action') {\n return computeActionId({\n address: env.signer.address,\n content_hash: env.content.hash,\n content_length: env.content.length,\n content_mime: env.content.mime,\n signed_at: env.signed_at,\n delegation_id: env.delegation_id,\n scope_exercised: env.scope_exercised,\n });\n }\n return computeRevocationId({\n address: env.signer.address,\n delegation_id: env.delegation_id,\n reason: env.reason,\n signed_at: env.signed_at,\n });\n}\n\nfunction canonicalMessageFor(env: AnyEnvelope): string {\n if (env.kind === 'agent-delegation') {\n return delegationCanonicalMessage({\n principal: env.principal.address,\n agent: env.agent.address,\n scopes: env.scopes,\n bond_sats: env.bond?.sats ?? 0,\n bond_attestation: env.bond?.attestation_id ?? 'none',\n issued_at: env.issued_at,\n expires_at: env.expires_at,\n nonce: env.nonce,\n });\n }\n if (env.kind === 'agent-action') {\n return actionCanonicalMessage({\n address: env.signer.address,\n content_hash: env.content.hash,\n content_length: env.content.length,\n content_mime: env.content.mime,\n signed_at: env.signed_at,\n delegation_id: env.delegation_id,\n scope_exercised: env.scope_exercised,\n });\n }\n return revocationCanonicalMessage({\n address: env.signer.address,\n delegation_id: env.delegation_id,\n reason: env.reason,\n signed_at: env.signed_at,\n });\n}\n\nfunction report(\n result: { ok: true; id: string } | { ok: false; code: string; message: string },\n asJson: boolean,\n what: string\n): void {\n if (result.ok) {\n if (asJson) {\n console.log(JSON.stringify({ ok: true, verified: what, id: result.id }));\n } else {\n console.log(`OK · ${what} verified`);\n console.log(` id: ${result.id}`);\n }\n return;\n }\n die(asJson, result.code, result.message);\n}\n\nfunction die(asJson: boolean, code: string, message: string): never {\n if (asJson) {\n console.error(JSON.stringify({ ok: false, code, message }));\n } else {\n console.error(`REJECTED · ${code}`);\n console.error(` ${message}`);\n }\n process.exit(1);\n}\n\nprogram.parseAsync().catch((err: Error) => {\n console.error(err.message);\n process.exit(1);\n});\n"]}
package/package.json ADDED
@@ -0,0 +1,54 @@
1
+ {
2
+ "name": "@orangecheck/agent-cli",
3
+ "version": "0.1.0",
4
+ "description": "Command-line tool for OC Agent — verify, inspect, and canonicalize delegation / action / revocation envelopes from your shell.",
5
+ "keywords": [
6
+ "oc-agent",
7
+ "orangecheck",
8
+ "bitcoin",
9
+ "delegation",
10
+ "authority",
11
+ "bip322",
12
+ "cli",
13
+ "nostr"
14
+ ],
15
+ "author": "OrangeCheck",
16
+ "license": "MIT",
17
+ "repository": {
18
+ "type": "git",
19
+ "url": "https://github.com/orangecheck/oc-packages.git",
20
+ "directory": "agent-cli"
21
+ },
22
+ "homepage": "https://agent.ochk.io",
23
+ "bugs": {
24
+ "url": "https://github.com/orangecheck/oc-agent-protocol/issues"
25
+ },
26
+ "type": "module",
27
+ "bin": {
28
+ "oc-agent": "./dist/cli.js"
29
+ },
30
+ "main": "./dist/cli.js",
31
+ "files": [
32
+ "dist",
33
+ "README.md",
34
+ "LICENSE"
35
+ ],
36
+ "scripts": {
37
+ "build": "tsup",
38
+ "dev": "tsup --watch",
39
+ "type-check": "tsc --noEmit",
40
+ "clean": "rm -rf dist",
41
+ "prepublishOnly": "npm run clean && npm run build"
42
+ },
43
+ "dependencies": {
44
+ "@noble/hashes": "^1.5.0",
45
+ "@orangecheck/agent-core": "^0.1.0",
46
+ "bip322-js": "^3.0.0",
47
+ "commander": "^12.1.0"
48
+ },
49
+ "devDependencies": {
50
+ "@types/node": "^22.10.2",
51
+ "tsup": "^8.3.5",
52
+ "typescript": "^5.7.2"
53
+ }
54
+ }