@arp-protocol/cli 0.0.0-stage → 0.0.3

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.
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ decideShare,
4
+ installedFromReceipts,
5
+ installedFromSkillLock,
6
+ isSharingOn,
7
+ parseLocalFailures,
8
+ parseLocalOutcomes,
9
+ sharedLineKey
10
+ } from "./cli-wev0jgf7.js";
11
+ import"./cli-0gsbnq5w.js";
12
+ import"./cli-fbwpcfvp.js";
13
+ import"./cli-mhzh9z8k.js";
14
+ import"./cli-d3dy7cxe.js";
15
+ import"./cli-3kbbwfbp.js";
16
+ import"./cli-g5zvr10v.js";
17
+
18
+ // src/share.ts
19
+ import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
20
+ import { join } from "node:path";
21
+ var read = (path) => existsSync(path) ? readFileSync(path, "utf8") : null;
22
+ function shared(env) {
23
+ const keys = new Set;
24
+ for (const row of (read(join(env.arpHome, "shared-failures.jsonl")) ?? "").split(`
25
+ `)) {
26
+ if (row.trim() === "")
27
+ continue;
28
+ try {
29
+ keys.add(sharedLineKey(JSON.parse(row)));
30
+ } catch {
31
+ continue;
32
+ }
33
+ }
34
+ return keys;
35
+ }
36
+ function decide(env) {
37
+ const on = isSharingOn(read(join(env.arpHome, "sharing.json")));
38
+ const decision = decideShare({
39
+ on,
40
+ failures: parseLocalFailures(read(join(env.arpHome, "failures.jsonl")) ?? ""),
41
+ outcomes: parseLocalOutcomes(read(join(env.arpHome, "outcomes.jsonl")) ?? ""),
42
+ installed: [
43
+ ...installedFromSkillLock(read(join(env.home, ".agents", ".skill-lock.json"))),
44
+ ...installedFromReceipts(read(join(env.arpHome, "receipts.jsonl"))),
45
+ ...installedFromReceipts(read(join(env.cwd, ".arp", "receipts.jsonl")))
46
+ ],
47
+ alreadyShared: shared(env)
48
+ });
49
+ return { ...decision, on };
50
+ }
51
+ function setSharing(env, on) {
52
+ mkdirSync(env.arpHome, { recursive: true });
53
+ writeFileSync(join(env.arpHome, "sharing.json"), `${JSON.stringify({ failures: on })}
54
+ `);
55
+ }
56
+ async function sendShared(env, write) {
57
+ const { on, lines } = decide(env);
58
+ if (!on)
59
+ return { sent: 0, failed: 0, firstError: null };
60
+ let sent = 0;
61
+ let failed = 0;
62
+ let firstError = null;
63
+ for (const line of lines) {
64
+ try {
65
+ await write(line);
66
+ appendFileSync(join(env.arpHome, "shared-failures.jsonl"), `${JSON.stringify(line)}
67
+ `);
68
+ sent += 1;
69
+ } catch (error) {
70
+ failed += 1;
71
+ firstError ??= error instanceof Error ? error.message : String(error);
72
+ }
73
+ }
74
+ return { sent, failed, firstError };
75
+ }
76
+ var WHY = {
77
+ sharing_off: "sharing is off",
78
+ no_public_source: "no known public source",
79
+ several_sources: "several sources with this name"
80
+ };
81
+ function describe(decision) {
82
+ const out = [`sharing is ${decision.on ? "on" : "off"}`];
83
+ if (decision.lines.length > 0) {
84
+ out.push("", "would be public on testnet 13579:");
85
+ for (const line of decision.lines) {
86
+ const tail = line.outcome === "failed" ? `failed ${line.reason}${line.need === undefined ? "" : ` needs ${line.need}`}` : `worked${line.need === undefined ? "" : ` with ${line.need}`}`;
87
+ out.push(` ${line.toolUrl} ${line.domain ?? "(no domain)"} ${tail}`);
88
+ }
89
+ }
90
+ if (decision.keptLocal.length > 0) {
91
+ out.push("", "stays on this machine:");
92
+ for (const row of decision.keptLocal)
93
+ out.push(` ${row.skill}: ${WHY[row.why]}`);
94
+ }
95
+ return `${out.join(`
96
+ `)}
97
+ `;
98
+ }
99
+ export {
100
+ setSharing,
101
+ sendShared,
102
+ describe,
103
+ decide
104
+ };
package/dist/cli.js ADDED
@@ -0,0 +1,258 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ bufferedCopy
4
+ } from "./chunks/cli-n4qagybd.js";
5
+ import"./chunks/cli-fbwpcfvp.js";
6
+ import"./chunks/cli-mhzh9z8k.js";
7
+ import"./chunks/cli-d3dy7cxe.js";
8
+ import"./chunks/cli-3kbbwfbp.js";
9
+ import {
10
+ __require
11
+ } from "./chunks/cli-g5zvr10v.js";
12
+
13
+ // src/cli.ts
14
+ import { dirname } from "node:path";
15
+ import { fileURLToPath } from "node:url";
16
+ // package.json
17
+ var version = "0.0.3";
18
+
19
+ // src/cli.ts
20
+ var USAGE = `arp ${version} — ARP's agent-side programs
21
+
22
+ usage
23
+ arp mcp [--http] the MCP server. stdio by default, which is how an MCP client launches it
24
+ arp hook the runtime hook: one payload on stdin. Records what a session used in
25
+ .arp/session.jsonl, and a skill's failures in ~/.arp/failures.jsonl. On
26
+ Stop, asks once per skill whether it did its job: ~/.arp/outcomes.jsonl
27
+ arp backfill read old Claude Code transcripts into ~/.arp/failures.jsonl. Sends nothing
28
+ arp share say what would be public from ~/.arp/failures.jsonl and outcomes.jsonl,
29
+ and what stays here.
30
+ arp share on, off (off by default). arp share send writes them on testnet
31
+ arp node the hire endpoint. Opt-in: it listens on 127.0.0.1 and is reached through
32
+ a tunnel you rent (cloudflared or ngrok, or ARP_NODE_PUBLIC_URL)
33
+
34
+ arp line write one public line on testnet 13579 through ARP's sponsor: --tool <url>
35
+ --outcome worked|failed [--domain <category>] [--reason <reason>]
36
+ [--payment-tx <hash> --network eip155:8453] an x402 payment, read on Base;
37
+ with it, --tool is the exact URL you paid
38
+ [--needs <name>] or [--with <name>] the program or variable name that was
39
+ missing, or that you added; written only if the skill's SKILL.md names it
40
+ arp init add the MCP server and the hook to every runtime found here
41
+ arp uninstall remove them, and only them
42
+ arp doctor check what is installed and that the server answers
43
+ arp init --node bind this node to your ERC-8004 agent: the token's owner signs once
44
+ --agent-registry eip155:<chain>:<registry> --agent-id <id>
45
+ --endpoint <https URL> --directory <handshake URL>
46
+
47
+ options for init, uninstall, doctor
48
+ --dry-run, -n show the changes, write nothing
49
+ --yes, -y agree without a prompt
50
+ --no-input never prompt; fail if a change needs agreement
51
+ --runtime a,b only these: claude, grok, cursor, gemini, codex, copilot
52
+ --project the project's files instead of your user ones
53
+ --print (init) print the MCP entry for any other client, write nothing
54
+ --sponsored (init) testnet tools that sign nothing for the user: ARP's sponsor
55
+ pays, and a fetched skill is installed into .claude/skills once you
56
+ accept the question it shows
57
+ --capture (init) hook every runtime and keep each payload, redacted, in
58
+ ~/.arp/captures/ — to teach the hook a new runtime
59
+ --force (init) replace an MCP server named "arp" that ARP did not write
60
+ --share, --no-share (init) answer the sharing offer up front; off unless --share or a "y"
61
+ arp --version
62
+ arp --help
63
+
64
+ docs: https://github.com/intuition-box/ARP/blob/main/docs/22_RUNNING_THE_NODE.md
65
+ `;
66
+ var EXIT = { ok: 0, usage: 2, writeFailed: 5 };
67
+ var CLI_PATH = fileURLToPath(import.meta.url);
68
+ var ARGV = process.argv.slice(2);
69
+ var asksHelp = (rest) => rest.some((arg) => arg === "--help" || arg === "-h");
70
+ var WANTS_HELP = asksHelp(ARGV.slice(1));
71
+ var STDIO_INPUT = ARGV[0] === "mcp" && !ARGV.includes("--http") && !WANTS_HELP ? bufferedCopy(process.stdin) : undefined;
72
+ async function runNodeInit(rest) {
73
+ const { nodeInit, parseNodeInitFlags } = await import("./chunks/node-init-rcepfyeh.js");
74
+ const flags = parseNodeInitFlags(rest);
75
+ if (flags instanceof Error) {
76
+ process.stderr.write(`arp init --node: ${flags.message}
77
+ `);
78
+ return EXIT.usage;
79
+ }
80
+ const { homedir } = await import("node:os");
81
+ const { createInterface } = await import("node:readline/promises");
82
+ return nodeInit(flags, {
83
+ env: process.env,
84
+ home: homedir(),
85
+ interactive: process.stdin.isTTY === true,
86
+ readLine: async (prompt) => {
87
+ const rl = createInterface({ input: process.stdin, output: process.stderr });
88
+ try {
89
+ return await rl.question(prompt);
90
+ } finally {
91
+ rl.close();
92
+ }
93
+ },
94
+ out: (line) => process.stdout.write(`${line}
95
+ `),
96
+ err: (line) => process.stderr.write(`${line}
97
+ `)
98
+ });
99
+ }
100
+ async function shareCommand(rest) {
101
+ const { arpHome } = await import("./chunks/index-jrs2shcc.js");
102
+ const { homedir } = await import("node:os");
103
+ const share = await import("./chunks/share-vtbkzs5f.js");
104
+ const env = { arpHome: arpHome(process.env, homedir()), home: homedir(), cwd: process.cwd() };
105
+ if (rest[0] === "send") {
106
+ if (!share.decide(env).on) {
107
+ process.stderr.write("sharing is off: nothing was sent. `arp share on` turns it on\n");
108
+ return EXIT.ok;
109
+ }
110
+ process.env["ARP_TARGET"] ??= "testnet";
111
+ const { writeLineHere } = await import("./chunks/line-691gbaha.js");
112
+ const done = await share.sendShared(env, async (line) => {
113
+ await writeLineHere(line);
114
+ });
115
+ process.stdout.write(`sent ${done.sent}, failed ${done.failed}
116
+ `);
117
+ if (done.firstError !== null)
118
+ process.stderr.write(`${done.firstError}
119
+ `);
120
+ return done.failed === 0 ? EXIT.ok : 1;
121
+ }
122
+ if (rest[0] === "on" || rest[0] === "off")
123
+ share.setSharing(env, rest[0] === "on");
124
+ else if (rest[0] !== undefined) {
125
+ process.stderr.write(`usage: arp share [on|off|send]
126
+ `);
127
+ return EXIT.usage;
128
+ }
129
+ process.stdout.write(share.describe(share.decide(env)));
130
+ return EXIT.ok;
131
+ }
132
+ async function run(argv) {
133
+ const [command, ...rest] = argv;
134
+ if (asksHelp(rest)) {
135
+ process.stdout.write(USAGE);
136
+ return EXIT.ok;
137
+ }
138
+ if (command === "init" && rest.includes("--node"))
139
+ return runNodeInit(rest);
140
+ switch (command) {
141
+ case "mcp": {
142
+ const { main } = await import("./chunks/server-59zry2jp.js");
143
+ await main(rest.includes("--http") ? rest : ["--stdio", ...rest], STDIO_INPUT);
144
+ return EXIT.ok;
145
+ }
146
+ case "hook":
147
+ await import(new URL("./hook.js", import.meta.url).href);
148
+ return EXIT.ok;
149
+ case "share":
150
+ try {
151
+ return await shareCommand(rest);
152
+ } catch (error) {
153
+ process.stderr.write(`arp share: ${error instanceof Error ? error.message : String(error)}
154
+ `);
155
+ return EXIT.writeFailed;
156
+ }
157
+ case "line": {
158
+ const flag = (name) => {
159
+ const at = rest.indexOf(`--${name}`);
160
+ return at === -1 ? undefined : rest[at + 1];
161
+ };
162
+ const toolUrl = flag("tool");
163
+ const outcome = flag("outcome");
164
+ if (toolUrl === undefined || outcome === undefined) {
165
+ process.stderr.write(`usage: arp line --tool <url> --outcome worked|failed [--domain <category>] [--reason <reason>]
166
+ [--parent <category> --why <text>] adds a --domain the tree lacks, under --parent
167
+ [--payment-tx <hash> --network eip155:8453] the x402 payment this outcome refers to;
168
+ --tool is then the exact URL you paid
169
+ [--needs <name>] with missing-program or missing-key: the program or variable name (never a value)
170
+ [--with <name>] with --outcome worked: what you had to add; either is written only if the SKILL.md names it
171
+ `);
172
+ return EXIT.usage;
173
+ }
174
+ process.env["ARP_TARGET"] ??= "testnet";
175
+ const { lineFromArgs, writeLineHere } = await import("./chunks/line-691gbaha.js");
176
+ const input = lineFromArgs({
177
+ toolUrl,
178
+ outcome,
179
+ domain: flag("domain"),
180
+ reason: flag("reason"),
181
+ parent: flag("parent"),
182
+ why: flag("why"),
183
+ paymentTx: flag("payment-tx"),
184
+ network: flag("network"),
185
+ needs: flag("needs"),
186
+ with: flag("with")
187
+ });
188
+ if (input instanceof Error) {
189
+ process.stderr.write(`arp line: ${input.message}
190
+ `);
191
+ return EXIT.usage;
192
+ }
193
+ try {
194
+ const written = await writeLineHere(input);
195
+ process.stdout.write(`${JSON.stringify(written)}
196
+ `);
197
+ return EXIT.ok;
198
+ } catch (error) {
199
+ process.stderr.write(`arp line: ${error instanceof Error ? error.message : String(error)}
200
+ `);
201
+ return 1;
202
+ }
203
+ }
204
+ case "backfill": {
205
+ const { backfill } = await import("./chunks/backfill-awengrsd.js");
206
+ const found = backfill();
207
+ process.stdout.write(`read ${found.transcripts} transcripts: ${found.uses} skill uses, ${found.added} new failures in ${found.file}
208
+ `);
209
+ return EXIT.ok;
210
+ }
211
+ case "node": {
212
+ const { main } = await import("./chunks/node-m0mx4y5k.js");
213
+ await main();
214
+ return EXIT.ok;
215
+ }
216
+ case "init":
217
+ case "uninstall":
218
+ case "doctor": {
219
+ const install = await import("./chunks/commands-157bms70.js");
220
+ const { processEnv } = await import("./chunks/env-n5ac8d1z.js");
221
+ const flags = install.parseFlags(rest);
222
+ if (flags instanceof Error) {
223
+ process.stderr.write(`arp ${command}: ${flags.message}
224
+ `);
225
+ return EXIT.usage;
226
+ }
227
+ const env = processEnv(dirname(CLI_PATH), version);
228
+ if (command === "doctor")
229
+ return install.doctor(env, flags, CLI_PATH);
230
+ return command === "init" ? install.init(env, flags, CLI_PATH) : install.uninstall(env, flags, CLI_PATH);
231
+ }
232
+ case "--version":
233
+ case "-v":
234
+ process.stdout.write(`${version}
235
+ `);
236
+ return EXIT.ok;
237
+ case undefined:
238
+ case "help":
239
+ case "--help":
240
+ case "-h":
241
+ process.stdout.write(USAGE);
242
+ return EXIT.ok;
243
+ default:
244
+ process.stderr.write(`arp: unknown command '${command}'
245
+
246
+ ${USAGE}`);
247
+ return EXIT.usage;
248
+ }
249
+ }
250
+ process.stdout.on("error", (error) => {
251
+ if (error.code === "EPIPE")
252
+ process.exit(0);
253
+ throw error;
254
+ });
255
+ run(ARGV).then((code) => {
256
+ if (code !== EXIT.ok)
257
+ process.exit(code);
258
+ });