@arp-protocol/cli 0.0.1 → 0.0.4

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.
Files changed (31) hide show
  1. package/CHANGELOG.md +98 -0
  2. package/LICENSE +26 -0
  3. package/README.md +22 -8
  4. package/dist/chunks/backfill-5zmh0t43.js +1050 -0
  5. package/dist/chunks/{ccip-qmytgn8e.js → ccip-zxtpc4fx.js} +4 -4
  6. package/dist/chunks/check-k4qnc9ee.js +2011 -0
  7. package/dist/chunks/cli-00qp1sj2.js +116 -0
  8. package/dist/chunks/{cli-c8568g4c.js → cli-0gsbnq5w.js} +72 -72
  9. package/dist/chunks/{cli-zpft011j.js → cli-64fx73kx.js} +3 -3
  10. package/dist/chunks/cli-7c393v47.js +173 -0
  11. package/dist/chunks/{cli-0z6f3603.js → cli-8m56jsfx.js} +239 -183
  12. package/dist/chunks/{cli-v446mw5v.js → cli-fbwpcfvp.js} +34 -34
  13. package/dist/chunks/cli-kda5hz4w.js +23 -0
  14. package/dist/chunks/{cli-0hqxver6.js → cli-mhzh9z8k.js} +33 -33
  15. package/dist/chunks/{cli-tyey74p3.js → cli-n4qagybd.js} +6 -2
  16. package/dist/chunks/{cli-74hv4etk.js → cli-wer26exb.js} +4939 -4105
  17. package/dist/chunks/cli-zehr6kdx.js +719 -0
  18. package/dist/chunks/{commands-dnk10vze.js → commands-t5a0w785.js} +88 -17
  19. package/dist/chunks/{env-s4585w6j.js → env-n5ac8d1z.js} +1 -0
  20. package/dist/chunks/{index-3a3ssef1.js → index-jrs2shcc.js} +3 -3
  21. package/dist/chunks/line-kvm1ew55.js +215 -0
  22. package/dist/chunks/{node-init-4v2m2vj0.js → node-init-amedveja.js} +7 -6
  23. package/dist/chunks/{node-0ydee9hy.js → node-x35ncwhq.js} +7 -6
  24. package/dist/chunks/server-ek7fet5m.js +6924 -0
  25. package/dist/chunks/{share-g8v5qe6r.js → share-ax2k8805.js} +10 -5
  26. package/dist/cli.js +71 -19
  27. package/dist/hook.js +4178 -270
  28. package/package.json +10 -3
  29. package/dist/chunks/backfill-j4hxt1w1.js +0 -262
  30. package/dist/chunks/line-zy1tc2np.js +0 -45
  31. package/dist/chunks/server-jmyjttvv.js +0 -3170
@@ -15,6 +15,19 @@ import {
15
15
  } from "node:fs";
16
16
  import { dirname, join as join2 } from "node:path";
17
17
 
18
+ // ../../packages/protocol/src/share-offer.ts
19
+ var SHARE_OFFER = {
20
+ question: "Share this machine's skill failures as public lines?",
21
+ sends: `When a skill fails here, one public line on Intuition testnet: the skill's public address, its category when known, "failed" and a closed reason (missing-key, missing-program, missing-file).`,
22
+ signer: "Each line is signed by this machine's own ARP address, created on the first send: it is public and the same on every line, so this machine's lines can be told apart from others' and linked together.",
23
+ never: "Never your prompts, your files, your paths, your code or your keys.",
24
+ service: "Sending goes through ARP's sponsoring service, which is not online yet: until it is, nothing is sent and `arp share send` says so.",
25
+ later: "Off by default. Change it any time with `arp share on` or `arp share off`."
26
+ };
27
+ function shareOfferLines() {
28
+ return [SHARE_OFFER.sends, SHARE_OFFER.signer, SHARE_OFFER.never, SHARE_OFFER.service, SHARE_OFFER.later];
29
+ }
30
+
18
31
  // src/install/targets.ts
19
32
  import { existsSync, readFileSync } from "node:fs";
20
33
  import { join } from "node:path";
@@ -51,11 +64,23 @@ function withMcpServer(config, name, entry) {
51
64
  var CLAUDE_HOOKS = {
52
65
  shape: "nested",
53
66
  events: [
54
- { name: "PostToolUse", matcher: "*" },
55
- { name: "PostToolUseFailure", matcher: "*" }
67
+ { name: "PostToolUse", matcher: "^(?!Skill$)" },
68
+ { name: "PostToolUse", matcher: "Skill", sync: true, timeout: 5 },
69
+ { name: "PostToolUseFailure", matcher: "*", sync: true },
70
+ { name: "PreToolUse", matcher: "Bash", sync: true, timeout: 15, if: "Bash(*skills*)" },
71
+ { name: "Stop", sync: true, timeout: 10 }
56
72
  ],
57
- entry: (command) => ({ type: "command", command, async: true, timeout: 10 })
73
+ entry: (command, event) => ({
74
+ type: "command",
75
+ command,
76
+ ...event.if === undefined ? {} : { if: event.if },
77
+ ...event.sync === true ? {} : { async: true },
78
+ timeout: event.timeout ?? 10
79
+ })
58
80
  };
81
+ function eventNames(spec) {
82
+ return [...new Set(spec.events.map((event) => event.name))];
83
+ }
59
84
  function isOurs(hook, marker) {
60
85
  return isRecord(hook) && typeof hook.command === "string" && hook.command.includes(marker);
61
86
  }
@@ -85,16 +110,18 @@ function ours(list, spec, marker) {
85
110
  }
86
111
  function withHooks(settings, spec, command, marker) {
87
112
  const hooks = isRecord(settings.hooks) ? { ...settings.hooks } : {};
88
- for (const event of spec.events) {
89
- const kept = strip(hooks[event.name], spec, marker);
113
+ for (const name of eventNames(spec)) {
114
+ const kept = strip(hooks[name], spec, marker);
90
115
  if (command !== null) {
91
- const entry = spec.entry(command);
92
- kept.push(spec.shape === "flat" ? entry : { ...event.matcher === undefined ? {} : { matcher: event.matcher }, hooks: [entry] });
116
+ for (const event of spec.events.filter((row) => row.name === name)) {
117
+ const entry = spec.entry(command, event);
118
+ kept.push(spec.shape === "flat" ? entry : { ...event.matcher === undefined ? {} : { matcher: event.matcher }, hooks: [entry] });
119
+ }
93
120
  }
94
121
  if (kept.length > 0)
95
- hooks[event.name] = kept;
122
+ hooks[name] = kept;
96
123
  else
97
- delete hooks[event.name];
124
+ delete hooks[name];
98
125
  }
99
126
  const next = { ...settings, hooks };
100
127
  if (Object.keys(hooks).length === 0) {
@@ -110,16 +137,19 @@ function hooksOf(settings, spec, marker) {
110
137
  if (!isRecord(settings.hooks))
111
138
  return {};
112
139
  const out = {};
113
- for (const event of spec.events) {
114
- const found = ours(settings.hooks[event.name], spec, marker);
140
+ for (const name of eventNames(spec)) {
141
+ const found = ours(settings.hooks[name], spec, marker);
115
142
  if (found.length > 0)
116
- out[event.name] = found;
143
+ out[name] = found;
117
144
  }
118
145
  return out;
119
146
  }
120
147
  function hasHooks(settings, spec, marker) {
121
148
  const found = hooksOf(settings, spec, marker);
122
- return spec.events.every((event) => (event.name in found));
149
+ return eventNames(spec).every((name) => {
150
+ const list = found[name];
151
+ return Array.isArray(list) && list.length >= spec.events.filter((row) => row.name === name).length;
152
+ });
123
153
  }
124
154
  var TOML_BEGIN = "# >>> arp — managed by `arp init`, removed by `arp uninstall` >>>";
125
155
  var TOML_END = "# <<< arp <<<";
@@ -327,8 +357,17 @@ function claudeMcpSteps(env, commands, project, remove, allowCli) {
327
357
  jsonStep(files.mcp, (config) => withMcpServer(config, SERVER_NAME, remove ? null : mcpEntry(commands.mcp, false)), remove ? "mcpServers.arp removed" : `mcpServers.arp → ${commands.mcp.command} ${commands.mcp.args.join(" ")}`, (config) => serversOf(config)[SERVER_NAME])
328
358
  ];
329
359
  }
360
+ function waitedLabel(event) {
361
+ if (event.sync !== true)
362
+ return "";
363
+ if (event.if !== undefined)
364
+ return " (waited on, Bash skills installs only)";
365
+ if (event.matcher !== undefined && event.matcher !== "*")
366
+ return ` (waited on, ${event.matcher} calls only)`;
367
+ return " (waited on)";
368
+ }
330
369
  function claudeHookStep(env, commands, project, remove) {
331
- return jsonStep(claudeFiles(env, project).settings, (settings) => withHooks(settings, CLAUDE_HOOKS, remove ? null : commands.hook, commands.hookFile), remove ? "hooks: arp removed from PostToolUse and PostToolUseFailure" : "hooks: arp on PostToolUse and PostToolUseFailure, async", (settings) => hooksOf(settings, CLAUDE_HOOKS, commands.hookFile));
370
+ return jsonStep(claudeFiles(env, project).settings, (settings) => withHooks(settings, CLAUDE_HOOKS, remove ? null : commands.hook, commands.hookFile), remove ? `hooks: arp removed from ${eventNames(CLAUDE_HOOKS).join(", ")}` : `hooks: arp on ${CLAUDE_HOOKS.events.map((event) => `${event.name}${waitedLabel(event)}`).join(", ")}`, (settings) => hooksOf(settings, CLAUDE_HOOKS, commands.hookFile));
332
371
  }
333
372
  var CLAUDE_HOOKS_SEEN_FROM = [2, 1, 316];
334
373
  function claudeVersionCheck(env) {
@@ -361,7 +400,7 @@ function claudeChecks(env, commands, project) {
361
400
  viaCli || SERVER_NAME in servers
362
401
  ],
363
402
  [
364
- `hook on PostToolUse and PostToolUseFailure (${files.settings})`,
403
+ `hook on ${eventNames(CLAUDE_HOOKS).join(", ")} (${files.settings})`,
365
404
  !(settings instanceof Error) && hasHooks(settings, CLAUDE_HOOKS, commands.hookFile)
366
405
  ],
367
406
  ...claudeVersionCheck(env)
@@ -424,7 +463,7 @@ function noHook(path, spec, commands) {
424
463
  return removal.kind === "file" && removal.before !== removal.after ? removal : NO_HOOK;
425
464
  }
426
465
  function hookStep(path, spec, commands, remove) {
427
- return jsonStep(path, (settings) => withHooks(settings, spec, remove ? null : commands.hook, commands.hookFile), remove ? `hooks: arp removed (${spec.events.map((e) => e.name).join(", ")})` : `hooks: arp on ${spec.events.map((e) => e.name).join(", ")}${commands.capture ? ", capturing" : ""}`, (settings) => hooksOf(settings, spec, commands.hookFile));
466
+ return jsonStep(path, (settings) => withHooks(settings, spec, remove ? null : commands.hook, commands.hookFile), remove ? `hooks: arp removed (${eventNames(spec).join(", ")})` : `hooks: arp on ${eventNames(spec).join(", ")}${commands.capture ? ", capturing" : ""}`, (settings) => hooksOf(settings, spec, commands.hookFile));
428
467
  }
429
468
  function jsonMcpRuntime(options) {
430
469
  const { id, name, dir, file, typed, binary, hook } = options;
@@ -558,6 +597,7 @@ function parseFlags(args) {
558
597
  print: false,
559
598
  capture: false,
560
599
  sponsored: false,
600
+ share: null,
561
601
  force: false,
562
602
  runtimes: null
563
603
  };
@@ -579,6 +619,10 @@ function parseFlags(args) {
579
619
  flags.sponsored = true;
580
620
  else if (arg === "--force")
581
621
  flags.force = true;
622
+ else if (arg === "--share")
623
+ flags.share = true;
624
+ else if (arg === "--no-share")
625
+ flags.share = false;
582
626
  else if (arg === "--runtime") {
583
627
  const list = (args[i + 1] ?? "").split(",").filter((name) => name.length > 0);
584
628
  i += 1;
@@ -733,7 +777,34 @@ async function init(env, flags, cliPath) {
733
777
  if (installsHook(runtimes, flags.capture)) {
734
778
  plan.push({ runtime: "hook", steps: [hookFileStep(env, commands, false)] });
735
779
  }
736
- return change(env, flags, plan, "Install");
780
+ const code = await change(env, flags, plan, "Install");
781
+ if ((code === EXIT.ok || code === EXIT.partly) && !flags.dryRun)
782
+ await offerSharing(env, flags);
783
+ return code;
784
+ }
785
+ async function offerSharing(env, flags) {
786
+ const home = env.arpHome ?? join2(env.home, ".arp");
787
+ const file = join2(home, "sharing.json");
788
+ const save = (on) => {
789
+ mkdirSync(home, { recursive: true });
790
+ writeFileSync(file, `${JSON.stringify({ failures: on })}
791
+ `);
792
+ };
793
+ if (flags.share !== null) {
794
+ save(flags.share);
795
+ env.out(`Sharing ${flags.share ? "on" : "off"}. ${SHARE_OFFER.later}`);
796
+ return;
797
+ }
798
+ if (existsSync2(file))
799
+ return;
800
+ if (flags.yes || flags.noInput || !env.interactive) {
801
+ env.out(`Sharing is off. ${SHARE_OFFER.later}`);
802
+ return;
803
+ }
804
+ env.out("");
805
+ for (const line of shareOfferLines())
806
+ env.out(line);
807
+ save(await env.ask(SHARE_OFFER.question));
737
808
  }
738
809
  async function uninstall(env, flags, cliPath) {
739
810
  const commands = commandsFor(env, cliPath);
@@ -20,6 +20,7 @@ function which(command) {
20
20
  function processEnv(dist, version) {
21
21
  return {
22
22
  home: homedir(),
23
+ arpHome: process.env["ARP_HOME"]?.trim() || join(homedir(), ".arp"),
23
24
  cwd: process.cwd(),
24
25
  which,
25
26
  run: (argv, stdin, timeoutMs = 15000) => {
@@ -20,11 +20,11 @@ import {
20
20
  refuseMovedState,
21
21
  serveFetch,
22
22
  stateFile
23
- } from "./cli-tyey74p3.js";
23
+ } from "./cli-n4qagybd.js";
24
24
  import {
25
25
  ERC8004_REGISTRY
26
- } from "./cli-v446mw5v.js";
27
- import"./cli-0hqxver6.js";
26
+ } from "./cli-fbwpcfvp.js";
27
+ import"./cli-mhzh9z8k.js";
28
28
  import"./cli-d3dy7cxe.js";
29
29
  import"./cli-3kbbwfbp.js";
30
30
  import"./cli-g5zvr10v.js";
@@ -0,0 +1,215 @@
1
+ #!/usr/bin/env node
2
+ import {
3
+ agentFor,
4
+ chainId,
5
+ domainWalk,
6
+ domainWords,
7
+ loopConfig,
8
+ sponsorApproval,
9
+ writeLine
10
+ } from "./cli-8m56jsfx.js";
11
+ import"./cli-7c393v47.js";
12
+ import"./cli-00qp1sj2.js";
13
+ import"./cli-n4qagybd.js";
14
+ import {
15
+ USAGE_REASONS,
16
+ X402_DEFAULT_NETWORKS,
17
+ chainIdOfNetwork,
18
+ isCategoryIn,
19
+ isExactEndpointUrl,
20
+ isTransactionAbsent,
21
+ isUsageOutcome,
22
+ isUsageReason,
23
+ needShapeProblem,
24
+ normaliseCategoryLabel,
25
+ readDomainTree,
26
+ redactEndpointUrl,
27
+ resolveDomain,
28
+ transfersIn,
29
+ x402NetworksFrom,
30
+ x402Reading
31
+ } from "./cli-wer26exb.js";
32
+ import"./cli-zehr6kdx.js";
33
+ import"./cli-0gsbnq5w.js";
34
+ import"./cli-fbwpcfvp.js";
35
+ import"./cli-mhzh9z8k.js";
36
+ import"./cli-d3dy7cxe.js";
37
+ import"./cli-3kbbwfbp.js";
38
+ import"./cli-g5zvr10v.js";
39
+
40
+ // ../mcp/src/line.ts
41
+ function lineNetworks(env = process.env) {
42
+ return x402NetworksFrom(X402_DEFAULT_NETWORKS, env);
43
+ }
44
+ function lineFromArgs(args, env = process.env) {
45
+ if (args.parent === undefined !== (args.why === undefined))
46
+ return new Error("--parent and --why go together");
47
+ if (args.paymentTx === undefined !== (args.network === undefined))
48
+ return new Error("--payment-tx and --network go together");
49
+ if (args.network !== undefined && chainIdOfNetwork(args.network) === null) {
50
+ return new Error("--network is a CAIP-2 EVM network, such as eip155:8453 for Base");
51
+ }
52
+ if (args.network !== undefined) {
53
+ let networks;
54
+ try {
55
+ networks = lineNetworks(env);
56
+ } catch (error) {
57
+ return error instanceof Error ? error : new Error(String(error));
58
+ }
59
+ if (!networks.has(args.network))
60
+ return new Error(`--network must be one of ${[...networks.keys()].join(", ")}`);
61
+ }
62
+ if (args.paymentTx !== undefined && !/^0x[0-9a-fA-F]{64}$/.test(args.paymentTx))
63
+ return new Error("--payment-tx is a 32-byte transaction hash");
64
+ const terms = termsFromArgs(args);
65
+ if (terms instanceof Error)
66
+ return terms;
67
+ if (args.reason === "no-delivery" && args.paymentTx === undefined) {
68
+ return new Error("--reason no-delivery means paid, nothing received: it takes --payment-tx and --network");
69
+ }
70
+ let toolUrl = args.toolUrl;
71
+ if (args.paymentTx !== undefined) {
72
+ if (!isExactEndpointUrl(args.toolUrl)) {
73
+ return new Error("with --payment-tx, --tool is the exact URL you paid, scheme included, as you called it");
74
+ }
75
+ try {
76
+ toolUrl = redactEndpointUrl(args.toolUrl);
77
+ } catch (error) {
78
+ return error instanceof Error ? error : new Error(String(error));
79
+ }
80
+ }
81
+ if (args.parent !== undefined && args.domain === undefined)
82
+ return new Error("--parent and --why add a --domain");
83
+ if (args.why !== undefined && args.why.trim() === "")
84
+ return new Error("--why says why no category fits");
85
+ if (!isUsageOutcome(args.outcome))
86
+ return new Error("--outcome must be worked or failed");
87
+ if (args.reason !== undefined && !isUsageReason(args.reason)) {
88
+ return new Error(`--reason must be one of ${USAGE_REASONS.join(", ")}`);
89
+ }
90
+ if (args.reason !== undefined && args.outcome !== "failed")
91
+ return new Error("a reason only follows --outcome failed");
92
+ if (args.needs !== undefined && args.outcome !== "failed")
93
+ return new Error("--needs follows --outcome failed; a worked line takes --with");
94
+ if (args.with !== undefined && args.outcome !== "worked")
95
+ return new Error("--with follows --outcome worked; a failure takes --needs");
96
+ const need = args.needs ?? args.with;
97
+ if (need !== undefined) {
98
+ const problem = needShapeProblem({ need, outcome: args.outcome, reason: args.reason ?? "" });
99
+ if (problem !== null)
100
+ return new Error(problem);
101
+ if (args.paymentTx !== undefined)
102
+ return new Error("--needs and --with name a skill's word; a paid endpoint has no SKILL.md");
103
+ }
104
+ return {
105
+ toolUrl,
106
+ outcome: args.outcome,
107
+ ...args.domain === undefined ? {} : { domain: args.domain },
108
+ ...args.reason === undefined ? {} : { reason: args.reason },
109
+ ...args.parent === undefined || args.why === undefined ? {} : { newDomain: { parent: args.parent, why: args.why.trim() } },
110
+ ...args.paymentTx === undefined || args.network === undefined ? {} : { payment: { network: args.network, txHash: args.paymentTx.toLowerCase() } },
111
+ ...terms === null ? {} : { terms },
112
+ ...need === undefined ? {} : { need }
113
+ };
114
+ }
115
+ var TERMS_FLAGS = ["--pay-to", "--asset", "--price", "--terms-at"];
116
+ function termsFromArgs(args) {
117
+ const given = [args.payTo, args.asset, args.price, args.termsAt];
118
+ if (args.paymentTx === undefined) {
119
+ return given.every((value) => value === undefined) ? null : new Error(`${TERMS_FLAGS.join(", ")} follow --payment-tx`);
120
+ }
121
+ if (given.some((value) => value === undefined)) {
122
+ return new Error(`with --payment-tx, name the terms the 402 gave and you paid against: ${TERMS_FLAGS.join(" ")}`);
123
+ }
124
+ const { payTo, asset, price, termsAt } = args;
125
+ if (!/^0x[0-9a-fA-F]{40}$/.test(payTo))
126
+ return new Error("--pay-to is the 402's payTo address");
127
+ if (!/^0x[0-9a-fA-F]{40}$/.test(asset))
128
+ return new Error("--asset is the 402's asset address");
129
+ if (!/^[1-9][0-9]{0,77}$/.test(price))
130
+ return new Error("--price is the 402's amount, a positive integer in the asset's smallest unit");
131
+ const receivedAt = /^[0-9]+$/.test(termsAt) ? Number(termsAt) : Math.floor(Date.parse(termsAt) / 1000);
132
+ if (!Number.isSafeInteger(receivedAt) || receivedAt <= 0)
133
+ return new Error("--terms-at is when the 402 was received: unix seconds or ISO 8601");
134
+ if (receivedAt > Math.floor(Date.now() / 1000) + 300)
135
+ return new Error("--terms-at is in the future");
136
+ return { payTo, asset, price, receivedAt };
137
+ }
138
+ function matchesTerms(payment, terms) {
139
+ return payment.transfers.some((transfer) => transfer.payTo.toLowerCase() === terms.payTo.toLowerCase() && transfer.asset.toLowerCase() === terms.asset.toLowerCase() && BigInt(transfer.amount) >= BigInt(terms.price));
140
+ }
141
+ async function readLinePayment(input, reading) {
142
+ if (input.payment === undefined)
143
+ return null;
144
+ const { network, txHash } = input.payment;
145
+ const assets = reading.policy.get(network)?.assets ?? [];
146
+ const reads = reading.readsFor(network);
147
+ let receipt;
148
+ try {
149
+ receipt = await reads.getTransactionReceipt({ hash: txHash });
150
+ } catch (error) {
151
+ if (isTransactionAbsent(error))
152
+ throw new Error(`transaction ${txHash} not found on ${network}`);
153
+ throw new Error(`${network} could not be read: ${error instanceof Error ? error.message.split(`
154
+ `)[0] : String(error)}`);
155
+ }
156
+ if (receipt.status !== "success")
157
+ throw new Error(`the payment ${txHash} reverted on ${network}`);
158
+ const transfers = transfersIn(receipt.logs, assets);
159
+ if (transfers.length === 0)
160
+ throw new Error(`${txHash} on ${network} moves no accepted asset (${assets.join(", ")})`);
161
+ return { network, txHash, transfers: transfers.map((transfer) => ({ ...transfer, amount: transfer.amount.toString() })) };
162
+ }
163
+ async function writeLineChecked(steps, input) {
164
+ let line = input;
165
+ let payment = null;
166
+ if (input.payment !== undefined) {
167
+ if (!isExactEndpointUrl(input.toolUrl))
168
+ throw new Error(`${input.toolUrl} is not the exact http(s) URL that was paid`);
169
+ if (steps.payments === undefined)
170
+ throw new Error("this build reads no payment network");
171
+ payment = await readLinePayment(input, steps.payments);
172
+ if (input.terms === undefined)
173
+ throw new Error("a line with a payment names the terms it paid against");
174
+ if (payment !== null && !matchesTerms(payment, input.terms)) {
175
+ throw new Error(`no transfer in ${input.payment.txHash} pays ${input.terms.payTo} at least ${input.terms.price} of ${input.terms.asset}: check --pay-to, --asset and --price`);
176
+ }
177
+ }
178
+ if (input.domain !== undefined) {
179
+ const domain = normaliseCategoryLabel(input.domain);
180
+ const resolved = await steps.isCategory(domain) ? null : await steps.resolve?.(domain);
181
+ if (resolved === null || resolved?.status === "node") {
182
+ const { newDomain: _unused, ...rest } = input;
183
+ line = { ...rest, domain: resolved?.status === "node" ? resolved.label : domain };
184
+ } else if (input.newDomain === undefined) {
185
+ const closest = resolved?.status === "unknown" && resolved.suggestions.length > 0 ? ` Closest: ${resolved.suggestions.join(", ")}.` : "";
186
+ throw new Error(`"${input.domain}" is not a category under tool.${closest} Pick one, or add it with --parent <category> --why <reason>`);
187
+ } else {
188
+ const parent = normaliseCategoryLabel(input.newDomain.parent);
189
+ if (!await steps.isCategory(parent))
190
+ throw new Error(`--parent "${input.newDomain.parent}" is not a category under tool`);
191
+ line = { ...input, domain, newDomain: { parent, why: input.newDomain.why } };
192
+ }
193
+ }
194
+ await sponsorApproval(steps.config);
195
+ const written = await (steps.write ?? writeLine)(steps.config, steps.agent(), line);
196
+ return payment === null ? written : { ...written, payment };
197
+ }
198
+ async function writeLineHere(input) {
199
+ if (chainId !== 13579)
200
+ throw new Error("a line is written on testnet 13579 only for now");
201
+ return writeLineChecked({
202
+ config: loopConfig(),
203
+ isCategory: async (label) => isCategoryIn(await readDomainTree(domainWalk()))(label),
204
+ resolve: async (word) => resolveDomain(word, domainWords(await readDomainTree(domainWalk()))),
205
+ agent: agentFor,
206
+ payments: x402Reading(lineNetworks(), process.env)
207
+ }, input);
208
+ }
209
+ export {
210
+ writeLineHere,
211
+ writeLineChecked,
212
+ readLinePayment,
213
+ lineNetworks,
214
+ lineFromArgs
215
+ };
@@ -1,20 +1,21 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveNodeKey
4
- } from "./cli-zpft011j.js";
5
- import"./cli-tyey74p3.js";
4
+ } from "./cli-64fx73kx.js";
5
+ import"./cli-n4qagybd.js";
6
6
  import {
7
7
  asEndpointBinding,
8
8
  endpointBindingDocument,
9
9
  normaliseEndpoint,
10
10
  parseAgentRegistry,
11
11
  validateHandshakeRequest
12
- } from "./cli-74hv4etk.js";
13
- import"./cli-c8568g4c.js";
14
- import"./cli-v446mw5v.js";
12
+ } from "./cli-wer26exb.js";
13
+ import"./cli-zehr6kdx.js";
14
+ import"./cli-0gsbnq5w.js";
15
+ import"./cli-fbwpcfvp.js";
15
16
  import {
16
17
  isHex
17
- } from "./cli-0hqxver6.js";
18
+ } from "./cli-mhzh9z8k.js";
18
19
  import"./cli-d3dy7cxe.js";
19
20
  import"./cli-3kbbwfbp.js";
20
21
  import"./cli-g5zvr10v.js";
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
  import {
3
3
  resolveNodeKey
4
- } from "./cli-zpft011j.js";
4
+ } from "./cli-64fx73kx.js";
5
5
  import {
6
6
  appendJsonLine,
7
7
  bigintSafe,
@@ -9,7 +9,7 @@ import {
9
9
  readJsonLines,
10
10
  serveFetch,
11
11
  stateFile
12
- } from "./cli-tyey74p3.js";
12
+ } from "./cli-n4qagybd.js";
13
13
  import {
14
14
  HIRE_RECEIPT_VERSION,
15
15
  createPublicClient,
@@ -18,15 +18,16 @@ import {
18
18
  normaliseEndpoint,
19
19
  parseEther,
20
20
  signHireReceipt
21
- } from "./cli-74hv4etk.js";
22
- import"./cli-c8568g4c.js";
21
+ } from "./cli-wer26exb.js";
22
+ import"./cli-zehr6kdx.js";
23
+ import"./cli-0gsbnq5w.js";
23
24
  import {
24
25
  ERC8004_REGISTRY
25
- } from "./cli-v446mw5v.js";
26
+ } from "./cli-fbwpcfvp.js";
26
27
  import {
27
28
  formatEther,
28
29
  isAddress
29
- } from "./cli-0hqxver6.js";
30
+ } from "./cli-mhzh9z8k.js";
30
31
  import"./cli-d3dy7cxe.js";
31
32
  import"./cli-3kbbwfbp.js";
32
33
  import"./cli-g5zvr10v.js";