@arp-protocol/cli 0.0.4 → 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -1
- package/README.md +2 -2
- package/dist/chunks/{backfill-5zmh0t43.js → backfill-kzgeaffa.js} +1 -1
- package/dist/chunks/{cli-wer26exb.js → cli-g3q6fxm0.js} +25 -10
- package/dist/chunks/{cli-8m56jsfx.js → cli-jew4syvf.js} +1 -1
- package/dist/chunks/{commands-t5a0w785.js → commands-vvrdahbr.js} +31 -11
- package/dist/chunks/{line-kvm1ew55.js → line-wra91qkr.js} +2 -2
- package/dist/chunks/{node-x35ncwhq.js → node-2rw44jrf.js} +1 -1
- package/dist/chunks/{node-init-amedveja.js → node-init-rmrmmg59.js} +1 -1
- package/dist/chunks/{server-ek7fet5m.js → server-bcsxfd7q.js} +9 -24
- package/dist/chunks/share-k1dnzsna.js +219 -0
- package/dist/cli.js +44 -17
- package/dist/hook.js +218 -34
- package/package.json +1 -1
- package/dist/chunks/share-ax2k8805.js +0 -106
package/CHANGELOG.md
CHANGED
|
@@ -3,7 +3,18 @@
|
|
|
3
3
|
`@arp-protocol/cli`. What a person or an agent running `arp` sees change, with the task that changed it
|
|
4
4
|
(`docs/tasks/<n>-*.md` in the repository). Everything writes on Intuition testnet 13579 only.
|
|
5
5
|
|
|
6
|
-
## 0.0.
|
|
6
|
+
## 0.0.5 — unreleased
|
|
7
|
+
|
|
8
|
+
- **Sharing is asked once** (task 126, ADR `0191`). After the first skill result (worked or failed) on a
|
|
9
|
+
machine where sharing was never chosen, the agent asks: "yes, this once", "always" or "no". Nothing
|
|
10
|
+
leaves without a yes. "Always" turns sharing on and sends lines in the background at the end of each
|
|
11
|
+
session (`arp share send --auto`, a lock, failures in `~/.arp/share-log.jsonl`), counting only results
|
|
12
|
+
kept after the choice. "No" is kept and the question does not come back. `ARP_SHARE_AUTO=off` stops
|
|
13
|
+
both the question and the background send.
|
|
14
|
+
- Sharing turned on any other way (`arp init`, `/arp:share-on`) now also sends at the end of a session.
|
|
15
|
+
- `arp share` prints when and how sharing was chosen.
|
|
16
|
+
|
|
17
|
+
## 0.0.4 — published 2026-11-11
|
|
7
18
|
|
|
8
19
|
- **The sponsoring service is hosted** (task 117): `ARP_SPONSOR` defaults to
|
|
9
20
|
`https://sponsor.arp.intuition.box` instead of `http://127.0.0.1:3200`, so `arp line`, `arp share send`
|
package/README.md
CHANGED
|
@@ -41,9 +41,9 @@ With no `arp` on `PATH`, its commands stand in for `arp share` and `arp line`. A
|
|
|
41
41
|
|
|
42
42
|
```
|
|
43
43
|
/arp:share what would be public, and what stays here. Sends nothing
|
|
44
|
-
/arp:share-on turn sharing on (off by default)
|
|
44
|
+
/arp:share-on turn sharing on (off by default); the hook then sends at the end of each session
|
|
45
45
|
/arp:share-off turn it off
|
|
46
|
-
/arp:share-send write the shared
|
|
46
|
+
/arp:share-send write the shared lines now as public lines on testnet. Needs a sponsoring service
|
|
47
47
|
/arp:line write one public line on testnet: --tool <url> --outcome worked|failed
|
|
48
48
|
```
|
|
49
49
|
|
|
@@ -9857,6 +9857,30 @@ function domainInText(text, words) {
|
|
|
9857
9857
|
return alias === undefined ? null : words.aliases[alias];
|
|
9858
9858
|
}
|
|
9859
9859
|
|
|
9860
|
+
// ../../packages/protocol/dist/sharing-state.js
|
|
9861
|
+
var SHARING_HOWS = ["init", "command", "desktop", "asked-once", "asked-always", "asked-no"];
|
|
9862
|
+
function sharingChoiceOf(text) {
|
|
9863
|
+
if (text === null)
|
|
9864
|
+
return null;
|
|
9865
|
+
try {
|
|
9866
|
+
const parsed = JSON.parse(text);
|
|
9867
|
+
if (typeof parsed !== "object" || parsed === null)
|
|
9868
|
+
return { on: false, at: null, how: null };
|
|
9869
|
+
const { failures, at, how } = parsed;
|
|
9870
|
+
return {
|
|
9871
|
+
on: failures === true,
|
|
9872
|
+
at: typeof at === "string" ? at : null,
|
|
9873
|
+
how: typeof how === "string" && SHARING_HOWS.includes(how) ? how : null
|
|
9874
|
+
};
|
|
9875
|
+
} catch {
|
|
9876
|
+
return { on: false, at: null, how: null };
|
|
9877
|
+
}
|
|
9878
|
+
}
|
|
9879
|
+
function sharingFileText(on, how, at) {
|
|
9880
|
+
return `${JSON.stringify({ failures: on, at: at.toISOString(), how })}
|
|
9881
|
+
`;
|
|
9882
|
+
}
|
|
9883
|
+
|
|
9860
9884
|
// ../../packages/protocol/dist/declare/line-need.js
|
|
9861
9885
|
var NEEDS_LABEL2 = "needs";
|
|
9862
9886
|
var WITH_LABEL2 = "with";
|
|
@@ -13255,15 +13279,6 @@ ${path}`;
|
|
|
13255
13279
|
quota: () => ({ ...quota })
|
|
13256
13280
|
};
|
|
13257
13281
|
}
|
|
13258
|
-
// ../../packages/protocol/dist/share-offer.js
|
|
13259
|
-
var SHARE_OFFER = {
|
|
13260
|
-
question: "Share this machine's skill failures as public lines?",
|
|
13261
|
-
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).`,
|
|
13262
|
-
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.",
|
|
13263
|
-
never: "Never your prompts, your files, your paths, your code or your keys.",
|
|
13264
|
-
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.",
|
|
13265
|
-
later: "Off by default. Change it any time with `arp share on` or `arp share off`."
|
|
13266
|
-
};
|
|
13267
13282
|
// ../../packages/protocol/dist/pulse-score.js
|
|
13268
13283
|
var SCORE_VERSION = "pulse-score-3";
|
|
13269
13284
|
var PRIOR_TOP = 0.8;
|
|
@@ -15202,4 +15217,4 @@ var RUNG_NAMES = {
|
|
|
15202
15217
|
};
|
|
15203
15218
|
var API_NAMES = new Set(["api", "rest", "openai", "jsonrpc", "grpc"]);
|
|
15204
15219
|
var ANSWERED = new Set(["live", "serves-declared-protocol", "declared-protocol-not-served"]);
|
|
15205
|
-
export { decodeEventLog, createPublicClient, createWalletClient, http, verifyMessage3 as verifyMessage, parseEther2 as parseEther, resolveRef, toCaip19, parseCaip19, isTransactionAbsent, HAS_TAG, IS_A_SUB_DOMAIN_OF, USES, intuitionSource, createErc8004Client, IPFS_GATEWAYS, privateProbeTarget, guardedFetchText, probeEndpoint, resolveAgent, listAgents, readDeclaredEndpoints, partitionByCheckability, getToolUsage, multiVaultDeclareAbi, multiVaultReads, prepareMarketPosition, prepareMarketExit, toolAtomUri, redactEndpointUrl, intuitionToolAtomLookup, prepareDeclareUsed, prepareStakeOnUsed, resolveDeclarationSubject, normaliseCategoryLabel, isCategoryIn, intuitionTestnet, ARP_DOMAIN_ATTESTORS, chainIdOfNetwork, paymentAtomLabel, isExactEndpointUrl, transfersIn, x402NetworksFrom, x402Reading, X402_DEFAULT_NETWORKS, listTools, listRegisteredTools, verdictOf, readReachabilityState2 as readReachabilityState, planReachability2 as planReachability, readDomainTree, toolsInDomain, findAgents, parseSessionLog, resolveInvocations, skillRefFromUrl, resolveContentPath, readRequires, contentsFileOf, readSkillContents, parseSkillsFind, fuseSearches, readPulse, groupByContent, githubPulseSource, resolveDomain, domainInText,
|
|
15220
|
+
export { decodeEventLog, createPublicClient, createWalletClient, http, verifyMessage3 as verifyMessage, parseEther2 as parseEther, resolveRef, toCaip19, parseCaip19, isTransactionAbsent, HAS_TAG, IS_A_SUB_DOMAIN_OF, USES, intuitionSource, createErc8004Client, IPFS_GATEWAYS, privateProbeTarget, guardedFetchText, probeEndpoint, resolveAgent, listAgents, readDeclaredEndpoints, partitionByCheckability, getToolUsage, multiVaultDeclareAbi, multiVaultReads, prepareMarketPosition, prepareMarketExit, toolAtomUri, redactEndpointUrl, intuitionToolAtomLookup, prepareDeclareUsed, prepareStakeOnUsed, resolveDeclarationSubject, normaliseCategoryLabel, isCategoryIn, intuitionTestnet, ARP_DOMAIN_ATTESTORS, chainIdOfNetwork, paymentAtomLabel, isExactEndpointUrl, transfersIn, x402NetworksFrom, x402Reading, X402_DEFAULT_NETWORKS, listTools, listRegisteredTools, verdictOf, readReachabilityState2 as readReachabilityState, planReachability2 as planReachability, readDomainTree, toolsInDomain, findAgents, parseSessionLog, resolveInvocations, skillRefFromUrl, resolveContentPath, readRequires, contentsFileOf, readSkillContents, parseSkillsFind, fuseSearches, readPulse, groupByContent, githubPulseSource, resolveDomain, domainInText, sharingChoiceOf, sharingFileText, NEEDS_LABEL2 as NEEDS_LABEL, WITH_LABEL2 as WITH_LABEL, needKindOfReason2 as needKindOfReason, publishableNeed2 as publishableNeed, needShapeProblem2 as needShapeProblem, HAS_OUTCOME_LABEL2 as HAS_OUTCOME_LABEL, USAGE_REASONS2 as USAGE_REASONS, BECAUSE_LABEL2 as BECAUSE_LABEL, isUsageOutcome2 as isUsageOutcome, isUsageReason2 as isUsageReason, prepareUsageContext2 as prepareUsageContext, budgetRefusal2 as budgetRefusal, parseLocalFailures, yourFailures, parseLocalOutcomes, isSharingOn, installedFromSkillLock, installedFromReceipts, sharedLineKey, decideShare, SCORE_VERSION, WALLETS_TO_MOVE, signalOf, entersList, unconfirmedNote, scoreSkill, findToolAtoms, findDeclaredTools, readThingUrl, workedInDomain, readEdgeWriters, getPulseUsage, HIRE_RECEIPT_VERSION, hireDigest, signHireReceipt, atomIsCanonicalFor, resolveAgentAtom, walletControlsSubject, findAgentsInDomains, findAgentsWithEndpoints, wordsMatchingOffer, readLineReceipts, receiptHolds, contentRequestTypedData, recoverContentRequester, verifyContentReceipt, corroborationOf, receiptMatchesContent, serveContent, contentIndexOf, bundleMatchesReceipt, serveSkillBundle, reviewSkill, renderSkillPrompt, contentsLines, repoFacts, endpointFacts, parseAgentRegistry, normaliseEndpoint, validateHandshakeRequest, asEndpointBinding, endpointBindingDocument, getAgentEndpoints, encodeApproveDeposit, sponsorProofDigest, signSponsorRequest, signMintGasRequest, signListToolRequest, signLineRequest, CATEGORY_REQUEST_TYPES, categoryRequestTypedData, signCategoryRequest, verifyCategoryRequest, searchSkillsIndex, RUNG_NAMES };
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
statSync,
|
|
14
14
|
writeFileSync
|
|
15
15
|
} from "node:fs";
|
|
16
|
-
import { dirname, join as join2 } from "node:path";
|
|
16
|
+
import { dirname as dirname2, join as join2 } from "node:path";
|
|
17
17
|
|
|
18
18
|
// ../../packages/protocol/src/share-offer.ts
|
|
19
19
|
var SHARE_OFFER = {
|
|
@@ -28,9 +28,15 @@ function shareOfferLines() {
|
|
|
28
28
|
return [SHARE_OFFER.sends, SHARE_OFFER.signer, SHARE_OFFER.never, SHARE_OFFER.service, SHARE_OFFER.later];
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
+
// ../../packages/protocol/src/sharing-state.ts
|
|
32
|
+
function sharingFileText(on, how, at) {
|
|
33
|
+
return `${JSON.stringify({ failures: on, at: at.toISOString(), how })}
|
|
34
|
+
`;
|
|
35
|
+
}
|
|
36
|
+
|
|
31
37
|
// src/install/targets.ts
|
|
32
38
|
import { existsSync, readFileSync } from "node:fs";
|
|
33
|
-
import { join } from "node:path";
|
|
39
|
+
import { dirname, join } from "node:path";
|
|
34
40
|
|
|
35
41
|
// src/install/edits.ts
|
|
36
42
|
function isRecord(value) {
|
|
@@ -68,7 +74,8 @@ var CLAUDE_HOOKS = {
|
|
|
68
74
|
{ name: "PostToolUse", matcher: "Skill", sync: true, timeout: 5 },
|
|
69
75
|
{ name: "PostToolUseFailure", matcher: "*", sync: true },
|
|
70
76
|
{ name: "PreToolUse", matcher: "Bash", sync: true, timeout: 15, if: "Bash(*skills*)" },
|
|
71
|
-
{ name: "Stop", sync: true, timeout: 10 }
|
|
77
|
+
{ name: "Stop", sync: true, timeout: 10 },
|
|
78
|
+
{ name: "SessionEnd", sync: true, timeout: 5 }
|
|
72
79
|
],
|
|
73
80
|
entry: (command, event) => ({
|
|
74
81
|
type: "command",
|
|
@@ -244,10 +251,10 @@ function read(path) {
|
|
|
244
251
|
return null;
|
|
245
252
|
}
|
|
246
253
|
}
|
|
247
|
-
function npxLaunch(pkg) {
|
|
254
|
+
function npxLaunch(pkg, command = "mcp") {
|
|
248
255
|
return {
|
|
249
256
|
command: "sh",
|
|
250
|
-
args: ["-c", `export ARP_PROJECT_DIR="$PWD"; cd / && exec npx --prefix / -y --fetch-retries=0 --fetch-timeout=5000 ${pkg}
|
|
257
|
+
args: ["-c", `export ARP_PROJECT_DIR="$PWD"; cd / && exec npx --prefix / -y --fetch-retries=0 --fetch-timeout=5000 ${pkg} ${command}`]
|
|
251
258
|
};
|
|
252
259
|
}
|
|
253
260
|
var SERVER_ENV = { ARP_TARGET: "testnet" };
|
|
@@ -266,7 +273,8 @@ function commandsFor(env, cliPath, capture = false, sponsored = false, force = f
|
|
|
266
273
|
env: sponsored ? SPONSORED_ENV : SERVER_ENV
|
|
267
274
|
};
|
|
268
275
|
const hook = `"${env.node}" "${hookFile}"${capture ? " --capture" : ""}`;
|
|
269
|
-
|
|
276
|
+
const send = fromNpx ? npxLaunch(`@arp-protocol/cli@${env.version}`, "share send --auto") : { command: env.node, args: [cliPath, "share", "send", "--auto"] };
|
|
277
|
+
return { mcp, hook, hookFile, sendFile: join(dirname(hookFile), "send.json"), send, cliPath, capture, force };
|
|
270
278
|
}
|
|
271
279
|
function diffLines(before, after) {
|
|
272
280
|
const lines = (value, sign) => value === undefined || typeof value === "object" && value !== null && Object.keys(value).length === 0 ? [] : JSON.stringify(value, null, 2).split(`
|
|
@@ -669,7 +677,7 @@ function apply(env, step) {
|
|
|
669
677
|
rmSync(step.path, { force: true });
|
|
670
678
|
return null;
|
|
671
679
|
}
|
|
672
|
-
mkdirSync(
|
|
680
|
+
mkdirSync(dirname2(step.path), { recursive: true });
|
|
673
681
|
const mode = step.before === null ? undefined : statSync(step.path).mode & 511;
|
|
674
682
|
const temp = `${step.path}.arp-tmp`;
|
|
675
683
|
writeFileSync(temp, step.after, mode === undefined ? undefined : { mode });
|
|
@@ -700,6 +708,19 @@ function hookFileStep(env, commands, remove) {
|
|
|
700
708
|
diff: []
|
|
701
709
|
};
|
|
702
710
|
}
|
|
711
|
+
function sendFileStep(commands, remove) {
|
|
712
|
+
const before = read2(commands.sendFile);
|
|
713
|
+
const after = remove ? null : `${JSON.stringify(commands.send, null, 2)}
|
|
714
|
+
`;
|
|
715
|
+
return {
|
|
716
|
+
kind: "file",
|
|
717
|
+
path: commands.sendFile,
|
|
718
|
+
before,
|
|
719
|
+
after,
|
|
720
|
+
summary: remove ? "removed" : "how the hook starts `arp share send --auto` when sharing is on",
|
|
721
|
+
diff: []
|
|
722
|
+
};
|
|
723
|
+
}
|
|
703
724
|
async function consent(env, flags, question) {
|
|
704
725
|
if (flags.yes)
|
|
705
726
|
return true;
|
|
@@ -775,7 +796,7 @@ async function init(env, flags, cliPath) {
|
|
|
775
796
|
steps: runtime.install(env, commands, flags.project)
|
|
776
797
|
}));
|
|
777
798
|
if (installsHook(runtimes, flags.capture)) {
|
|
778
|
-
plan.push({ runtime: "hook", steps: [hookFileStep(env, commands, false)] });
|
|
799
|
+
plan.push({ runtime: "hook", steps: [hookFileStep(env, commands, false), sendFileStep(commands, false)] });
|
|
779
800
|
}
|
|
780
801
|
const code = await change(env, flags, plan, "Install");
|
|
781
802
|
if ((code === EXIT.ok || code === EXIT.partly) && !flags.dryRun)
|
|
@@ -787,8 +808,7 @@ async function offerSharing(env, flags) {
|
|
|
787
808
|
const file = join2(home, "sharing.json");
|
|
788
809
|
const save = (on) => {
|
|
789
810
|
mkdirSync(home, { recursive: true });
|
|
790
|
-
writeFileSync(file,
|
|
791
|
-
`);
|
|
811
|
+
writeFileSync(file, sharingFileText(on, "init", env.now()));
|
|
792
812
|
};
|
|
793
813
|
if (flags.share !== null) {
|
|
794
814
|
save(flags.share);
|
|
@@ -813,7 +833,7 @@ async function uninstall(env, flags, cliPath) {
|
|
|
813
833
|
runtime: runtime.name,
|
|
814
834
|
steps: runtime.remove(env, commands, flags.project)
|
|
815
835
|
}));
|
|
816
|
-
plan.push({ runtime: "hook", steps: [hookFileStep(env, commands, true)] });
|
|
836
|
+
plan.push({ runtime: "hook", steps: [hookFileStep(env, commands, true), sendFileStep(commands, true)] });
|
|
817
837
|
const code = await change(env, flags, plan, "Remove");
|
|
818
838
|
const captures = join2(env.home, ".arp", "captures");
|
|
819
839
|
if (existsSync2(captures))
|
|
@@ -7,7 +7,7 @@ import {
|
|
|
7
7
|
loopConfig,
|
|
8
8
|
sponsorApproval,
|
|
9
9
|
writeLine
|
|
10
|
-
} from "./cli-
|
|
10
|
+
} from "./cli-jew4syvf.js";
|
|
11
11
|
import"./cli-7c393v47.js";
|
|
12
12
|
import"./cli-00qp1sj2.js";
|
|
13
13
|
import"./cli-n4qagybd.js";
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
transfersIn,
|
|
29
29
|
x402NetworksFrom,
|
|
30
30
|
x402Reading
|
|
31
|
-
} from "./cli-
|
|
31
|
+
} from "./cli-g3q6fxm0.js";
|
|
32
32
|
import"./cli-zehr6kdx.js";
|
|
33
33
|
import"./cli-0gsbnq5w.js";
|
|
34
34
|
import"./cli-fbwpcfvp.js";
|
|
@@ -48,7 +48,7 @@ import {
|
|
|
48
48
|
targetName,
|
|
49
49
|
text,
|
|
50
50
|
toolAtoms
|
|
51
|
-
} from "./cli-
|
|
51
|
+
} from "./cli-jew4syvf.js";
|
|
52
52
|
import"./cli-7c393v47.js";
|
|
53
53
|
import"./cli-00qp1sj2.js";
|
|
54
54
|
import {
|
|
@@ -69,7 +69,6 @@ import {
|
|
|
69
69
|
NEEDS_LABEL,
|
|
70
70
|
RUNG_NAMES,
|
|
71
71
|
SCORE_VERSION,
|
|
72
|
-
SHARE_OFFER,
|
|
73
72
|
USAGE_REASONS,
|
|
74
73
|
WALLETS_TO_MOVE,
|
|
75
74
|
WITH_LABEL,
|
|
@@ -135,6 +134,7 @@ import {
|
|
|
135
134
|
resolveRef,
|
|
136
135
|
scoreSkill,
|
|
137
136
|
searchSkillsIndex,
|
|
137
|
+
sharingFileText,
|
|
138
138
|
signalOf,
|
|
139
139
|
skillRefFromUrl,
|
|
140
140
|
toCaip19,
|
|
@@ -149,7 +149,7 @@ import {
|
|
|
149
149
|
wordsMatchingOffer,
|
|
150
150
|
workedInDomain,
|
|
151
151
|
yourFailures
|
|
152
|
-
} from "./cli-
|
|
152
|
+
} from "./cli-g3q6fxm0.js";
|
|
153
153
|
import"./cli-zehr6kdx.js";
|
|
154
154
|
import {
|
|
155
155
|
parseAbi
|
|
@@ -166,26 +166,13 @@ import"./cli-3kbbwfbp.js";
|
|
|
166
166
|
import"./cli-g5zvr10v.js";
|
|
167
167
|
|
|
168
168
|
// ../mcp/src/share-ask.ts
|
|
169
|
-
import {
|
|
169
|
+
import { mkdirSync, writeFileSync } from "node:fs";
|
|
170
170
|
import { join } from "node:path";
|
|
171
|
-
function shareAskInstructions(arpHome2) {
|
|
172
|
-
if (existsSync(join(arpHome2, "sharing.json")))
|
|
173
|
-
return null;
|
|
174
|
-
return [
|
|
175
|
-
"SHARING IS NOT SET YET. Once in this session, at a natural pause (never in the middle of a task), ask the",
|
|
176
|
-
`person: "${SHARE_OFFER.question}" and give them, in your own short words, exactly this: ${SHARE_OFFER.sends}`,
|
|
177
|
-
`${SHARE_OFFER.signer} ${SHARE_OFFER.never} ${SHARE_OFFER.service}`,
|
|
178
|
-
"It is off unless they agree. If they agree, they type /arp:share-on; if not, /arp:share-off, so the",
|
|
179
|
-
"question is not asked again. Do not run either yourself, and do not ask twice."
|
|
180
|
-
].join(`
|
|
181
|
-
`);
|
|
182
|
-
}
|
|
183
171
|
function applyDesktopShare(value, arpHome2) {
|
|
184
172
|
if (value !== "true" && value !== "false")
|
|
185
173
|
return null;
|
|
186
174
|
mkdirSync(arpHome2, { recursive: true });
|
|
187
|
-
writeFileSync(join(arpHome2, "sharing.json"),
|
|
188
|
-
`);
|
|
175
|
+
writeFileSync(join(arpHome2, "sharing.json"), sharingFileText(value === "true", "desktop", new Date));
|
|
189
176
|
return value === "true";
|
|
190
177
|
}
|
|
191
178
|
|
|
@@ -5882,7 +5869,7 @@ async function findTools(id, args) {
|
|
|
5882
5869
|
}
|
|
5883
5870
|
|
|
5884
5871
|
// ../mcp/src/handlers/pulse.ts
|
|
5885
|
-
import { chmodSync as chmodSync2, existsSync
|
|
5872
|
+
import { chmodSync as chmodSync2, existsSync, mkdirSync as mkdirSync3, readFileSync as readFileSync3, rmSync } from "node:fs";
|
|
5886
5873
|
import { homedir } from "node:os";
|
|
5887
5874
|
import { join as join3, delimiter } from "node:path";
|
|
5888
5875
|
|
|
@@ -6207,7 +6194,7 @@ function searchHome() {
|
|
|
6207
6194
|
return join3(arpHome(process.env, homedir()), "skills-cli");
|
|
6208
6195
|
}
|
|
6209
6196
|
function searchIsCached() {
|
|
6210
|
-
return
|
|
6197
|
+
return existsSync(join3(searchHome(), ".npm", "_npx"));
|
|
6211
6198
|
}
|
|
6212
6199
|
async function search(query, timeoutMs, stop, firstDownload = false) {
|
|
6213
6200
|
if (!canSearch({ holdsAgentKey: DESKTOP, setting: process.env["ARP_PULSE_SEARCH"] })) {
|
|
@@ -6316,7 +6303,7 @@ function usageLine(usage, domain) {
|
|
|
6316
6303
|
function readYourFailures() {
|
|
6317
6304
|
try {
|
|
6318
6305
|
const path = join3(arpHome(process.env, homedir()), "failures.jsonl");
|
|
6319
|
-
return
|
|
6306
|
+
return existsSync(path) ? parseLocalFailures(readFileSync3(path, "utf8")) : [];
|
|
6320
6307
|
} catch {
|
|
6321
6308
|
return [];
|
|
6322
6309
|
}
|
|
@@ -6811,9 +6798,7 @@ var handler = {
|
|
|
6811
6798
|
protocolVersion: PROTOCOL_VERSION,
|
|
6812
6799
|
capabilities: { tools: {} },
|
|
6813
6800
|
serverInfo: { name: "ARP", version: "0.2.0" },
|
|
6814
|
-
instructions: DESKTOP ? DESKTOP_INSTRUCTIONS : HOSTED ? READ_INSTRUCTIONS :
|
|
6815
|
-
|
|
6816
|
-
`) : SERVER_INSTRUCTIONS
|
|
6801
|
+
instructions: DESKTOP ? DESKTOP_INSTRUCTIONS : READ_ONLY || HOSTED ? READ_INSTRUCTIONS : SERVER_INSTRUCTIONS
|
|
6817
6802
|
});
|
|
6818
6803
|
case "notifications/initialized":
|
|
6819
6804
|
return new Response(null, { status: 202 });
|
|
@@ -0,0 +1,219 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import {
|
|
3
|
+
decideShare,
|
|
4
|
+
installedFromReceipts,
|
|
5
|
+
installedFromSkillLock,
|
|
6
|
+
isSharingOn,
|
|
7
|
+
parseLocalFailures,
|
|
8
|
+
parseLocalOutcomes,
|
|
9
|
+
sharedLineKey,
|
|
10
|
+
sharingChoiceOf,
|
|
11
|
+
sharingFileText
|
|
12
|
+
} from "./cli-g3q6fxm0.js";
|
|
13
|
+
import"./cli-zehr6kdx.js";
|
|
14
|
+
import"./cli-0gsbnq5w.js";
|
|
15
|
+
import"./cli-fbwpcfvp.js";
|
|
16
|
+
import"./cli-mhzh9z8k.js";
|
|
17
|
+
import"./cli-d3dy7cxe.js";
|
|
18
|
+
import"./cli-3kbbwfbp.js";
|
|
19
|
+
import"./cli-g5zvr10v.js";
|
|
20
|
+
|
|
21
|
+
// src/share.ts
|
|
22
|
+
import { appendFileSync, existsSync, mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
|
|
23
|
+
import { join } from "node:path";
|
|
24
|
+
var read = (path) => existsSync(path) ? readFileSync(path, "utf8") : null;
|
|
25
|
+
function shared(env) {
|
|
26
|
+
const keys = new Set;
|
|
27
|
+
for (const row of (read(join(env.arpHome, "shared-failures.jsonl")) ?? "").split(`
|
|
28
|
+
`)) {
|
|
29
|
+
if (row.trim() === "")
|
|
30
|
+
continue;
|
|
31
|
+
try {
|
|
32
|
+
keys.add(sharedLineKey(JSON.parse(row)));
|
|
33
|
+
} catch {
|
|
34
|
+
continue;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return keys;
|
|
38
|
+
}
|
|
39
|
+
function onceGrants(env) {
|
|
40
|
+
const grants = [];
|
|
41
|
+
for (const row of (read(join(env.arpHome, "share-once.jsonl")) ?? "").split(`
|
|
42
|
+
`)) {
|
|
43
|
+
try {
|
|
44
|
+
const { session, skill } = JSON.parse(row);
|
|
45
|
+
if (typeof session === "string" && typeof skill === "string")
|
|
46
|
+
grants.push({ session, skill });
|
|
47
|
+
} catch {
|
|
48
|
+
continue;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
return grants;
|
|
52
|
+
}
|
|
53
|
+
var nameOf = (skill) => skill.split(":").pop() ?? skill;
|
|
54
|
+
function granted(text, grants, since = null) {
|
|
55
|
+
return text.split(`
|
|
56
|
+
`).filter((row) => {
|
|
57
|
+
try {
|
|
58
|
+
const { session, skill, at } = JSON.parse(row);
|
|
59
|
+
if (since !== null && typeof at === "string" && at >= since)
|
|
60
|
+
return true;
|
|
61
|
+
return grants.some((grant) => grant.session === session && typeof skill === "string" && nameOf(skill) === nameOf(grant.skill));
|
|
62
|
+
} catch {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
}).join(`
|
|
66
|
+
`);
|
|
67
|
+
}
|
|
68
|
+
var rowCount = (text) => text.split(`
|
|
69
|
+
`).filter((row) => row.trim() !== "").length;
|
|
70
|
+
function decide(env) {
|
|
71
|
+
const choice = sharingChoiceOf(read(join(env.arpHome, "sharing.json")));
|
|
72
|
+
const on = isSharingOn(read(join(env.arpHome, "sharing.json")));
|
|
73
|
+
const since = on && choice?.how === "asked-always" && choice.at !== null ? choice.at : null;
|
|
74
|
+
const grants = on && since === null ? [] : onceGrants(env);
|
|
75
|
+
const failuresAll = read(join(env.arpHome, "failures.jsonl")) ?? "";
|
|
76
|
+
const outcomesAll = read(join(env.arpHome, "outcomes.jsonl")) ?? "";
|
|
77
|
+
const failuresText = since === null ? failuresAll : granted(failuresAll, grants, since);
|
|
78
|
+
const outcomesText = since === null ? outcomesAll : granted(outcomesAll, grants, since);
|
|
79
|
+
const earlier = rowCount(failuresAll) + rowCount(outcomesAll) - rowCount(failuresText) - rowCount(outcomesText);
|
|
80
|
+
const installed = [
|
|
81
|
+
...installedFromSkillLock(read(join(env.home, ".agents", ".skill-lock.json"))),
|
|
82
|
+
...installedFromSkillLock(read(join(env.cwd, "skills-lock.json"))),
|
|
83
|
+
...installedFromReceipts(read(join(env.arpHome, "receipts.jsonl"))),
|
|
84
|
+
...installedFromReceipts(read(join(env.cwd, ".arp", "receipts.jsonl")))
|
|
85
|
+
];
|
|
86
|
+
const alreadyShared = shared(env);
|
|
87
|
+
const all = decideShare({
|
|
88
|
+
on,
|
|
89
|
+
failures: parseLocalFailures(failuresText),
|
|
90
|
+
outcomes: parseLocalOutcomes(outcomesText),
|
|
91
|
+
installed,
|
|
92
|
+
alreadyShared
|
|
93
|
+
});
|
|
94
|
+
if (on || grants.length === 0)
|
|
95
|
+
return { ...all, on, choice, once: false, earlier };
|
|
96
|
+
const once = decideShare({
|
|
97
|
+
on: true,
|
|
98
|
+
failures: parseLocalFailures(granted(failuresText, grants)),
|
|
99
|
+
outcomes: parseLocalOutcomes(granted(outcomesText, grants)),
|
|
100
|
+
installed,
|
|
101
|
+
alreadyShared
|
|
102
|
+
});
|
|
103
|
+
const onceSkills = new Set(grants.map((grant) => nameOf(grant.skill)));
|
|
104
|
+
const stillOff = all.keptLocal.filter((row) => !onceSkills.has(row.skill));
|
|
105
|
+
return { lines: once.lines, keptLocal: [...once.keptLocal, ...stillOff], on, choice, once: once.lines.length > 0, earlier: 0 };
|
|
106
|
+
}
|
|
107
|
+
function setSharing(env, on, how = "command", now = new Date) {
|
|
108
|
+
mkdirSync(env.arpHome, { recursive: true });
|
|
109
|
+
writeFileSync(join(env.arpHome, "sharing.json"), sharingFileText(on, how, now));
|
|
110
|
+
}
|
|
111
|
+
var LOCK = "share-send.lock";
|
|
112
|
+
var STALE_MS = 10 * 60 * 1000;
|
|
113
|
+
async function withSendLock(env, send, now = Date.now) {
|
|
114
|
+
mkdirSync(env.arpHome, { recursive: true });
|
|
115
|
+
const path = join(env.arpHome, LOCK);
|
|
116
|
+
const take = () => {
|
|
117
|
+
try {
|
|
118
|
+
writeFileSync(path, `${JSON.stringify({ pid: process.pid, at: new Date(now()).toISOString() })}
|
|
119
|
+
`, { flag: "wx" });
|
|
120
|
+
return true;
|
|
121
|
+
} catch {
|
|
122
|
+
return false;
|
|
123
|
+
}
|
|
124
|
+
};
|
|
125
|
+
if (!take()) {
|
|
126
|
+
let at = 0;
|
|
127
|
+
try {
|
|
128
|
+
at = Date.parse(JSON.parse(readFileSync(path, "utf8")).at ?? "");
|
|
129
|
+
} catch {
|
|
130
|
+
at = 0;
|
|
131
|
+
}
|
|
132
|
+
if (Number.isFinite(at) && now() - at < STALE_MS)
|
|
133
|
+
return null;
|
|
134
|
+
rmSync(path, { force: true });
|
|
135
|
+
if (!take())
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
try {
|
|
139
|
+
return await send();
|
|
140
|
+
} finally {
|
|
141
|
+
rmSync(path, { force: true });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function logSend(env, result, now = new Date) {
|
|
145
|
+
mkdirSync(env.arpHome, { recursive: true });
|
|
146
|
+
const row = { at: now.toISOString(), sent: result.sent, failed: result.failed, ...result.firstError === null ? {} : { error: result.firstError } };
|
|
147
|
+
appendFileSync(join(env.arpHome, "share-log.jsonl"), `${JSON.stringify(row)}
|
|
148
|
+
`);
|
|
149
|
+
}
|
|
150
|
+
async function sendShared(env, write) {
|
|
151
|
+
const { on, once, lines } = decide(env);
|
|
152
|
+
if (!on && !once)
|
|
153
|
+
return { sent: 0, failed: 0, firstError: null };
|
|
154
|
+
let sent = 0;
|
|
155
|
+
let failed = 0;
|
|
156
|
+
let firstError = null;
|
|
157
|
+
for (const line of lines) {
|
|
158
|
+
try {
|
|
159
|
+
await write(line);
|
|
160
|
+
appendFileSync(join(env.arpHome, "shared-failures.jsonl"), `${JSON.stringify(line)}
|
|
161
|
+
`);
|
|
162
|
+
sent += 1;
|
|
163
|
+
} catch (error) {
|
|
164
|
+
failed += 1;
|
|
165
|
+
firstError ??= error instanceof Error ? error.message : String(error);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
return { sent, failed, firstError };
|
|
169
|
+
}
|
|
170
|
+
var WHY = {
|
|
171
|
+
sharing_off: "sharing is off",
|
|
172
|
+
no_public_source: "no known public source",
|
|
173
|
+
several_sources: "several sources with this name"
|
|
174
|
+
};
|
|
175
|
+
var HOW = {
|
|
176
|
+
init: "at install",
|
|
177
|
+
command: "by command",
|
|
178
|
+
desktop: "in Claude Desktop's settings",
|
|
179
|
+
"asked-once": 'answering "yes, this once"',
|
|
180
|
+
"asked-always": 'answering "always"',
|
|
181
|
+
"asked-no": 'answering "no"'
|
|
182
|
+
};
|
|
183
|
+
function status(decision) {
|
|
184
|
+
const state = decision.on ? "on" : "off";
|
|
185
|
+
if (decision.choice === null)
|
|
186
|
+
return `sharing is ${state}, not decided yet`;
|
|
187
|
+
const when = decision.choice.at === null ? "" : ` ${decision.choice.at.slice(0, 10)}`;
|
|
188
|
+
const how = decision.choice.how === null ? "" : ` ${HOW[decision.choice.how]}`;
|
|
189
|
+
return when === "" && how === "" ? `sharing is ${state}` : `sharing is ${state}, chosen${when}${how}`;
|
|
190
|
+
}
|
|
191
|
+
function describe(decision) {
|
|
192
|
+
const out = [status(decision)];
|
|
193
|
+
if (decision.lines.length > 0) {
|
|
194
|
+
out.push("", decision.on ? "would be public on testnet 13579:" : "would be public on testnet 13579, agreed once:");
|
|
195
|
+
for (const line of decision.lines) {
|
|
196
|
+
const tail = line.outcome === "failed" ? `failed ${line.reason}${line.need === undefined ? "" : ` needs ${line.need}`}` : `worked${line.need === undefined ? "" : ` with ${line.need}`}`;
|
|
197
|
+
out.push(` ${line.toolUrl} ${line.domain ?? "(no domain)"} ${tail}`);
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (decision.keptLocal.length > 0) {
|
|
201
|
+
out.push("", "stays on this machine:");
|
|
202
|
+
for (const row of decision.keptLocal)
|
|
203
|
+
out.push(` ${row.skill}: ${WHY[row.why]}`);
|
|
204
|
+
}
|
|
205
|
+
if (decision.earlier > 0) {
|
|
206
|
+
out.push("", `kept before "always" was chosen, and staying here: ${decision.earlier} record(s). \`arp share on\` would show and include them`);
|
|
207
|
+
}
|
|
208
|
+
return `${out.join(`
|
|
209
|
+
`)}
|
|
210
|
+
`;
|
|
211
|
+
}
|
|
212
|
+
export {
|
|
213
|
+
withSendLock,
|
|
214
|
+
setSharing,
|
|
215
|
+
sendShared,
|
|
216
|
+
logSend,
|
|
217
|
+
describe,
|
|
218
|
+
decide
|
|
219
|
+
};
|
package/dist/cli.js
CHANGED
|
@@ -14,7 +14,7 @@ import {
|
|
|
14
14
|
import { dirname } from "node:path";
|
|
15
15
|
import { fileURLToPath } from "node:url";
|
|
16
16
|
// package.json
|
|
17
|
-
var version = "0.0.
|
|
17
|
+
var version = "0.0.5";
|
|
18
18
|
|
|
19
19
|
// src/cli.ts
|
|
20
20
|
var USAGE = `arp ${version} — ARP's agent-side programs
|
|
@@ -23,11 +23,14 @@ usage
|
|
|
23
23
|
arp mcp [--http] the MCP server. stdio by default, which is how an MCP client launches it
|
|
24
24
|
arp hook the runtime hook: one payload on stdin. Records what a session used in
|
|
25
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
|
|
26
|
+
Stop, asks once per skill whether it did its job: ~/.arp/outcomes.jsonl.
|
|
27
|
+
While sharing is undecided, the first result also asks once whether to share
|
|
28
|
+
it; with sharing on, SessionEnd starts arp share send --auto in the background
|
|
27
29
|
arp backfill read old Claude Code transcripts into ~/.arp/failures.jsonl. Sends nothing
|
|
28
30
|
arp share say what would be public from ~/.arp/failures.jsonl and outcomes.jsonl,
|
|
29
31
|
and what stays here.
|
|
30
|
-
arp share on, off (off by default). arp share send writes them on testnet
|
|
32
|
+
arp share on, off (off by default). arp share send writes them on testnet;
|
|
33
|
+
--auto prints nothing and keeps the result in ~/.arp/share-log.jsonl
|
|
31
34
|
arp check <skill> before you use a skill: what its files contain, what agents wrote about
|
|
32
35
|
it, and whether what it needed when it failed is on this machine.
|
|
33
36
|
<owner/repo/skill> or a github.com URL with ?skill=. Writes nothing
|
|
@@ -75,7 +78,7 @@ var asksHelp = (rest) => rest.some((arg) => arg === "--help" || arg === "-h");
|
|
|
75
78
|
var WANTS_HELP = asksHelp(ARGV.slice(1));
|
|
76
79
|
var STDIO_INPUT = ARGV[0] === "mcp" && !ARGV.includes("--http") && !WANTS_HELP ? bufferedCopy(process.stdin) : undefined;
|
|
77
80
|
async function runNodeInit(rest) {
|
|
78
|
-
const { nodeInit, parseNodeInitFlags } = await import("./chunks/node-init-
|
|
81
|
+
const { nodeInit, parseNodeInitFlags } = await import("./chunks/node-init-rmrmmg59.js");
|
|
79
82
|
const flags = parseNodeInitFlags(rest);
|
|
80
83
|
if (flags instanceof Error) {
|
|
81
84
|
process.stderr.write(`arp init --node: ${flags.message}
|
|
@@ -105,18 +108,42 @@ async function runNodeInit(rest) {
|
|
|
105
108
|
async function shareCommand(rest) {
|
|
106
109
|
const { arpHome } = await import("./chunks/index-jrs2shcc.js");
|
|
107
110
|
const { homedir } = await import("node:os");
|
|
108
|
-
const share = await import("./chunks/share-
|
|
109
|
-
const
|
|
111
|
+
const share = await import("./chunks/share-k1dnzsna.js");
|
|
112
|
+
const cwd = process.env["ARP_PROJECT_DIR"]?.trim() || process.cwd();
|
|
113
|
+
const env = { arpHome: arpHome(process.env, homedir()), home: homedir(), cwd };
|
|
110
114
|
if (rest[0] === "send") {
|
|
111
|
-
|
|
112
|
-
|
|
115
|
+
const auto = rest.includes("--auto");
|
|
116
|
+
const decision = share.decide(env);
|
|
117
|
+
if (!decision.on && !decision.once) {
|
|
118
|
+
if (!auto)
|
|
119
|
+
process.stderr.write("sharing is off: nothing was sent. `arp share on` turns it on\n");
|
|
113
120
|
return EXIT.ok;
|
|
114
121
|
}
|
|
122
|
+
if (auto && decision.lines.length === 0)
|
|
123
|
+
return EXIT.ok;
|
|
115
124
|
process.env["ARP_TARGET"] ??= "testnet";
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
await
|
|
119
|
-
|
|
125
|
+
let done;
|
|
126
|
+
try {
|
|
127
|
+
const { writeLineHere } = await import("./chunks/line-wra91qkr.js");
|
|
128
|
+
done = await share.withSendLock(env, () => share.sendShared(env, async (line) => {
|
|
129
|
+
await writeLineHere(line);
|
|
130
|
+
}));
|
|
131
|
+
} catch (error) {
|
|
132
|
+
if (!auto)
|
|
133
|
+
throw error;
|
|
134
|
+
share.logSend(env, { sent: 0, failed: 0, firstError: error instanceof Error ? error.message : String(error) });
|
|
135
|
+
return EXIT.ok;
|
|
136
|
+
}
|
|
137
|
+
if (done === null) {
|
|
138
|
+
if (!auto)
|
|
139
|
+
process.stderr.write(`another send is running: nothing was sent by this one
|
|
140
|
+
`);
|
|
141
|
+
return EXIT.ok;
|
|
142
|
+
}
|
|
143
|
+
if (auto) {
|
|
144
|
+
share.logSend(env, done);
|
|
145
|
+
return EXIT.ok;
|
|
146
|
+
}
|
|
120
147
|
process.stdout.write(`sent ${done.sent}, failed ${done.failed}
|
|
121
148
|
`);
|
|
122
149
|
if (done.firstError !== null)
|
|
@@ -144,7 +171,7 @@ async function run(argv) {
|
|
|
144
171
|
return runNodeInit(rest);
|
|
145
172
|
switch (command) {
|
|
146
173
|
case "mcp": {
|
|
147
|
-
const { main } = await import("./chunks/server-
|
|
174
|
+
const { main } = await import("./chunks/server-bcsxfd7q.js");
|
|
148
175
|
await main(rest.includes("--http") ? rest : ["--stdio", ...rest], STDIO_INPUT);
|
|
149
176
|
return EXIT.ok;
|
|
150
177
|
}
|
|
@@ -191,7 +218,7 @@ async function run(argv) {
|
|
|
191
218
|
return EXIT.usage;
|
|
192
219
|
}
|
|
193
220
|
process.env["ARP_TARGET"] ??= "testnet";
|
|
194
|
-
const { lineFromArgs, writeLineHere } = await import("./chunks/line-
|
|
221
|
+
const { lineFromArgs, writeLineHere } = await import("./chunks/line-wra91qkr.js");
|
|
195
222
|
const input = lineFromArgs({
|
|
196
223
|
toolUrl,
|
|
197
224
|
outcome,
|
|
@@ -225,21 +252,21 @@ async function run(argv) {
|
|
|
225
252
|
}
|
|
226
253
|
}
|
|
227
254
|
case "backfill": {
|
|
228
|
-
const { backfill } = await import("./chunks/backfill-
|
|
255
|
+
const { backfill } = await import("./chunks/backfill-kzgeaffa.js");
|
|
229
256
|
const found = backfill();
|
|
230
257
|
process.stdout.write(`read ${found.transcripts} transcripts: ${found.uses} skill uses, ${found.added} new failures in ${found.file}
|
|
231
258
|
`);
|
|
232
259
|
return EXIT.ok;
|
|
233
260
|
}
|
|
234
261
|
case "node": {
|
|
235
|
-
const { main } = await import("./chunks/node-
|
|
262
|
+
const { main } = await import("./chunks/node-2rw44jrf.js");
|
|
236
263
|
await main();
|
|
237
264
|
return EXIT.ok;
|
|
238
265
|
}
|
|
239
266
|
case "init":
|
|
240
267
|
case "uninstall":
|
|
241
268
|
case "doctor": {
|
|
242
|
-
const install = await import("./chunks/commands-
|
|
269
|
+
const install = await import("./chunks/commands-vvrdahbr.js");
|
|
243
270
|
const { processEnv } = await import("./chunks/env-n5ac8d1z.js");
|
|
244
271
|
const flags = install.parseFlags(rest);
|
|
245
272
|
if (flags instanceof Error) {
|
package/dist/hook.js
CHANGED
|
@@ -14,9 +14,9 @@ function appendOwn(path, text) {
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
// ../hook/src/hook.ts
|
|
17
|
-
import { existsSync as
|
|
17
|
+
import { existsSync as existsSync4, lstatSync as lstatSync2, mkdirSync as mkdirSync5, readFileSync as readFileSync5, writeFileSync as writeFileSync3 } from "node:fs";
|
|
18
18
|
import { homedir as homedir3 } from "node:os";
|
|
19
|
-
import { dirname as
|
|
19
|
+
import { dirname as dirname4, join as join6 } from "node:path";
|
|
20
20
|
// ../../packages/protocol/dist/declare/tool-thing.js
|
|
21
21
|
class InvalidToolUrlError extends Error {
|
|
22
22
|
input;
|
|
@@ -4622,19 +4622,200 @@ async function postToolUseFailure(payload) {
|
|
|
4622
4622
|
return context === null ? null : failureOutput(context);
|
|
4623
4623
|
}
|
|
4624
4624
|
|
|
4625
|
+
// ../hook/src/share-ask.ts
|
|
4626
|
+
import { spawn } from "node:child_process";
|
|
4627
|
+
import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3, writeFileSync as writeFileSync2 } from "node:fs";
|
|
4628
|
+
import { dirname as dirname3, join as join4 } from "node:path";
|
|
4629
|
+
import { fileURLToPath } from "node:url";
|
|
4630
|
+
|
|
4631
|
+
// ../../packages/protocol/src/sharing-state.ts
|
|
4632
|
+
var SHARING_HOWS2 = ["init", "command", "desktop", "asked-once", "asked-always", "asked-no"];
|
|
4633
|
+
function sharingChoiceOf2(text) {
|
|
4634
|
+
if (text === null)
|
|
4635
|
+
return null;
|
|
4636
|
+
try {
|
|
4637
|
+
const parsed2 = JSON.parse(text);
|
|
4638
|
+
if (typeof parsed2 !== "object" || parsed2 === null)
|
|
4639
|
+
return { on: false, at: null, how: null };
|
|
4640
|
+
const { failures, at, how } = parsed2;
|
|
4641
|
+
return {
|
|
4642
|
+
on: failures === true,
|
|
4643
|
+
at: typeof at === "string" ? at : null,
|
|
4644
|
+
how: typeof how === "string" && SHARING_HOWS2.includes(how) ? how : null
|
|
4645
|
+
};
|
|
4646
|
+
} catch {
|
|
4647
|
+
return { on: false, at: null, how: null };
|
|
4648
|
+
}
|
|
4649
|
+
}
|
|
4650
|
+
function sharingFileText2(on, how, at) {
|
|
4651
|
+
return `${JSON.stringify({ failures: on, at: at.toISOString(), how })}
|
|
4652
|
+
`;
|
|
4653
|
+
}
|
|
4654
|
+
function choiceForAnswer2(answer) {
|
|
4655
|
+
return { on: answer === "always", how: `asked-${answer}` };
|
|
4656
|
+
}
|
|
4657
|
+
var ANSWER = /^[\s>*`-]*arp-share:\s*(once|always|no)[\s.`*]*$/gim;
|
|
4658
|
+
function shareAnswerIn2(text) {
|
|
4659
|
+
const found = new Set;
|
|
4660
|
+
for (const match of text.matchAll(ANSWER)) {
|
|
4661
|
+
const word = match[1]?.toLowerCase();
|
|
4662
|
+
if (word === "once" || word === "always" || word === "no")
|
|
4663
|
+
found.add(word);
|
|
4664
|
+
}
|
|
4665
|
+
return found.size === 1 ? [...found][0] ?? null : null;
|
|
4666
|
+
}
|
|
4667
|
+
|
|
4668
|
+
// ../hook/src/share-ask.ts
|
|
4669
|
+
var isOff = () => process.env["ARP_SHARE_AUTO"]?.trim().toLowerCase() === "off";
|
|
4670
|
+
var GITHUB_REPO = /^[\w.-]+\/[\w.-]+$/;
|
|
4671
|
+
var readIfThere2 = (path) => existsSync2(path) ? readFileSync3(path, "utf8") : null;
|
|
4672
|
+
function shareQuestionFor() {
|
|
4673
|
+
return " Sharing is not set on this machine yet. If that line says worked or failed, ask the person once, right after it, " + "in their language: share this result as a public line on Intuition testnet? Three choices: yes, this once; " + "always (this result and every one from now on, sent at the end of each session; earlier ones stay here); no (not asked again). Say what would leave: " + "the skill's public address, its category, worked or failed with a closed reason, signed by this machine's own " + "ARP address. Never their prompts, files, paths, code or keys. Do not choose for them. At the end of your reply to " + "their answer, add one line: `arp-share: once`, `arp-share: always` or `arp-share: no`, the one they chose; if " + "they did not answer it, add none.";
|
|
4674
|
+
}
|
|
4675
|
+
function stateOf(home) {
|
|
4676
|
+
const text = readIfThere2(join4(home, "share-question.json"));
|
|
4677
|
+
if (text === null)
|
|
4678
|
+
return null;
|
|
4679
|
+
try {
|
|
4680
|
+
const row = JSON.parse(text);
|
|
4681
|
+
if (typeof row.session !== "string" || typeof row.skill !== "string")
|
|
4682
|
+
return null;
|
|
4683
|
+
if (row.state !== "offered" && row.state !== "put" && row.state !== "answered")
|
|
4684
|
+
return null;
|
|
4685
|
+
return { at: typeof row.at === "string" ? row.at : "", session: row.session, skill: row.skill, state: row.state };
|
|
4686
|
+
} catch {
|
|
4687
|
+
return { at: "", session: "", skill: "", state: "put" };
|
|
4688
|
+
}
|
|
4689
|
+
}
|
|
4690
|
+
var writeState = (home, state) => writeFileSync2(join4(home, "share-question.json"), `${JSON.stringify(state)}
|
|
4691
|
+
`);
|
|
4692
|
+
function offerShare(session, skill, source, cwd, now = new Date) {
|
|
4693
|
+
if (isOff())
|
|
4694
|
+
return false;
|
|
4695
|
+
try {
|
|
4696
|
+
const home = arpHome();
|
|
4697
|
+
if (existsSync2(join4(home, "sharing.json")))
|
|
4698
|
+
return false;
|
|
4699
|
+
const state = stateOf(home);
|
|
4700
|
+
if (state !== null && (state.state !== "offered" || state.session === session))
|
|
4701
|
+
return false;
|
|
4702
|
+
const name = skill.split(":").pop() ?? skill;
|
|
4703
|
+
const known = source ?? installedSource(name, cwd);
|
|
4704
|
+
if (known === null || !GITHUB_REPO.test(known))
|
|
4705
|
+
return false;
|
|
4706
|
+
mkdirSync3(home, { recursive: true });
|
|
4707
|
+
writeState(home, { at: now.toISOString(), session, skill, state: "offered" });
|
|
4708
|
+
return true;
|
|
4709
|
+
} catch {
|
|
4710
|
+
return false;
|
|
4711
|
+
}
|
|
4712
|
+
}
|
|
4713
|
+
function onStopShare(session, last, recorded, now = new Date) {
|
|
4714
|
+
if (isOff())
|
|
4715
|
+
return;
|
|
4716
|
+
try {
|
|
4717
|
+
const home = arpHome();
|
|
4718
|
+
const state = stateOf(home);
|
|
4719
|
+
if (state === null || state.session !== session)
|
|
4720
|
+
return;
|
|
4721
|
+
if (state.state === "put") {
|
|
4722
|
+
if (existsSync2(join4(home, "sharing.json")))
|
|
4723
|
+
return;
|
|
4724
|
+
const answer = shareAnswerIn2(last);
|
|
4725
|
+
if (answer === null)
|
|
4726
|
+
return;
|
|
4727
|
+
const choice = choiceForAnswer2(answer);
|
|
4728
|
+
writeFileSync2(join4(home, "sharing.json"), sharingFileText2(choice.on, choice.how, now));
|
|
4729
|
+
if (answer !== "no") {
|
|
4730
|
+
appendOwn(join4(home, "share-once.jsonl"), `${JSON.stringify({ at: now.toISOString(), session, skill: state.skill })}
|
|
4731
|
+
`);
|
|
4732
|
+
}
|
|
4733
|
+
writeState(home, { ...state, state: "answered", answer, at: now.toISOString() });
|
|
4734
|
+
return;
|
|
4735
|
+
}
|
|
4736
|
+
if (state.state !== "offered")
|
|
4737
|
+
return;
|
|
4738
|
+
const outcome = recorded.get(state.skill);
|
|
4739
|
+
if (outcome === "worked" || outcome === "failed")
|
|
4740
|
+
writeState(home, { ...state, state: "put", at: now.toISOString() });
|
|
4741
|
+
} catch {}
|
|
4742
|
+
}
|
|
4743
|
+
function senderOf(here = dirname3(fileURLToPath(import.meta.url))) {
|
|
4744
|
+
const send = ["share", "send", "--auto"];
|
|
4745
|
+
const given = process.env["ARP_CLI"]?.trim();
|
|
4746
|
+
if (given !== undefined && given !== "")
|
|
4747
|
+
return { command: process.execPath, args: [given, ...send] };
|
|
4748
|
+
for (const name of ["arp.js", "cli.js"]) {
|
|
4749
|
+
if (existsSync2(join4(here, name)))
|
|
4750
|
+
return { command: process.execPath, args: [join4(here, name), ...send] };
|
|
4751
|
+
}
|
|
4752
|
+
const written = readIfThere2(join4(here, "send.json"));
|
|
4753
|
+
if (written === null)
|
|
4754
|
+
return null;
|
|
4755
|
+
try {
|
|
4756
|
+
const parsed2 = JSON.parse(written);
|
|
4757
|
+
if (typeof parsed2.command !== "string" || !Array.isArray(parsed2.args))
|
|
4758
|
+
return null;
|
|
4759
|
+
const args = parsed2.args.filter((arg) => typeof arg === "string");
|
|
4760
|
+
return { command: parsed2.command, args };
|
|
4761
|
+
} catch {
|
|
4762
|
+
return null;
|
|
4763
|
+
}
|
|
4764
|
+
}
|
|
4765
|
+
function onceFor(home, session) {
|
|
4766
|
+
for (const line of (readIfThere2(join4(home, "share-once.jsonl")) ?? "").split(`
|
|
4767
|
+
`)) {
|
|
4768
|
+
try {
|
|
4769
|
+
if (JSON.parse(line).session === session)
|
|
4770
|
+
return true;
|
|
4771
|
+
} catch {
|
|
4772
|
+
continue;
|
|
4773
|
+
}
|
|
4774
|
+
}
|
|
4775
|
+
return false;
|
|
4776
|
+
}
|
|
4777
|
+
async function sessionEnd(payload) {
|
|
4778
|
+
if (isOff() || typeof payload !== "object" || payload === null)
|
|
4779
|
+
return null;
|
|
4780
|
+
const raw = payload;
|
|
4781
|
+
const session = raw["session_id"] ?? raw["sessionId"];
|
|
4782
|
+
if (typeof session !== "string")
|
|
4783
|
+
return null;
|
|
4784
|
+
const cwd = typeof raw["cwd"] === "string" ? raw["cwd"] : process.cwd();
|
|
4785
|
+
try {
|
|
4786
|
+
const home = arpHome();
|
|
4787
|
+
const choice = sharingChoiceOf2(readIfThere2(join4(home, "sharing.json")));
|
|
4788
|
+
if (choice?.on !== true && !onceFor(home, session))
|
|
4789
|
+
return null;
|
|
4790
|
+
const sender = senderOf();
|
|
4791
|
+
if (sender === null) {
|
|
4792
|
+
mkdirSync3(home, { recursive: true });
|
|
4793
|
+
appendOwn(join4(home, "share-log.jsonl"), `${JSON.stringify({ at: new Date().toISOString(), sent: 0, failed: 0, error: "no arp program beside the hook; run arp share send" })}
|
|
4794
|
+
`);
|
|
4795
|
+
return null;
|
|
4796
|
+
}
|
|
4797
|
+
const child = spawn(sender.command, sender.args, { cwd, detached: true, stdio: "ignore", env: process.env });
|
|
4798
|
+
child.on("error", () => {
|
|
4799
|
+
return;
|
|
4800
|
+
});
|
|
4801
|
+
child.unref();
|
|
4802
|
+
} catch {}
|
|
4803
|
+
return null;
|
|
4804
|
+
}
|
|
4805
|
+
|
|
4625
4806
|
// ../hook/src/worked.ts
|
|
4626
|
-
import { existsSync as
|
|
4627
|
-
import { join as
|
|
4807
|
+
import { existsSync as existsSync3, mkdirSync as mkdirSync4, readFileSync as readFileSync4 } from "node:fs";
|
|
4808
|
+
import { join as join5 } from "node:path";
|
|
4628
4809
|
|
|
4629
4810
|
// ../../packages/protocol/src/local-outcomes.ts
|
|
4630
4811
|
var OUTCOME_ANSWERS2 = ["worked", "failed", "unsure"];
|
|
4631
4812
|
function isOutcomeAnswer2(word) {
|
|
4632
4813
|
return OUTCOME_ANSWERS2.includes(word);
|
|
4633
4814
|
}
|
|
4634
|
-
var
|
|
4815
|
+
var ANSWER2 = /^[\s>*`-]*arp:\s*([A-Za-z0-9._:@/-]+)\s+(worked|failed|unsure)[\s.`*]*$/gim;
|
|
4635
4816
|
function answersIn2(text, asked) {
|
|
4636
4817
|
const found = new Map;
|
|
4637
|
-
for (const match of text.matchAll(
|
|
4818
|
+
for (const match of text.matchAll(ANSWER2)) {
|
|
4638
4819
|
const [, skill, word] = match;
|
|
4639
4820
|
if (skill === undefined || word === undefined)
|
|
4640
4821
|
continue;
|
|
@@ -4665,18 +4846,18 @@ function stopInputOf(raw) {
|
|
|
4665
4846
|
transcript: text(field(raw, "transcript_path", "transcriptPath"))
|
|
4666
4847
|
};
|
|
4667
4848
|
}
|
|
4668
|
-
function requestFor(skill) {
|
|
4669
|
-
return `ARP: at the end of your final reply, add one line saying whether the skill ${skill} did its job: ` + `\`arp: ${skill} worked\`, \`arp: ${skill} failed\` or \`arp: ${skill} unsure\`. ` + "Kept on this machine unless `arp share` is on.";
|
|
4849
|
+
function requestFor(skill, share = false) {
|
|
4850
|
+
return `ARP: at the end of your final reply, add one line saying whether the skill ${skill} did its job: ` + `\`arp: ${skill} worked\`, \`arp: ${skill} failed\` or \`arp: ${skill} unsure\`. ` + "Kept on this machine unless `arp share` is on." + (share ? shareQuestionFor() : "");
|
|
4670
4851
|
}
|
|
4671
4852
|
function requestOutput(context) {
|
|
4672
4853
|
return JSON.stringify({ hookSpecificOutput: { hookEventName: "PostToolUse", additionalContext: context } });
|
|
4673
4854
|
}
|
|
4674
4855
|
var isArpsOwn = (name) => name === "arp" || name.endsWith(":arp");
|
|
4675
4856
|
function rows(path) {
|
|
4676
|
-
if (!
|
|
4857
|
+
if (!existsSync3(path))
|
|
4677
4858
|
return [];
|
|
4678
4859
|
const found = [];
|
|
4679
|
-
for (const line of
|
|
4860
|
+
for (const line of readFileSync4(path, "utf8").split(`
|
|
4680
4861
|
`)) {
|
|
4681
4862
|
if (line.trim() === "")
|
|
4682
4863
|
continue;
|
|
@@ -4692,7 +4873,7 @@ function withOf(skill, source, cwd, before) {
|
|
|
4692
4873
|
const name = skill.split(":").pop() ?? skill;
|
|
4693
4874
|
let need = null;
|
|
4694
4875
|
let latest = "";
|
|
4695
|
-
for (const row of rows(
|
|
4876
|
+
for (const row of rows(join5(arpHome(), "failures.jsonl"))) {
|
|
4696
4877
|
const { skill: rowSkill, source: rowSource, need: rowNeed, at } = row;
|
|
4697
4878
|
if (typeof rowSkill !== "string" || typeof rowNeed !== "string" || typeof at !== "string")
|
|
4698
4879
|
continue;
|
|
@@ -4710,11 +4891,11 @@ function withOf(skill, source, cwd, before) {
|
|
|
4710
4891
|
const directory = skillDirectory(name, cwd);
|
|
4711
4892
|
if (directory === null)
|
|
4712
4893
|
return null;
|
|
4713
|
-
return publishableNeed3(need,
|
|
4894
|
+
return publishableNeed3(need, readFileSync4(join5(directory, "SKILL.md"), "utf8"));
|
|
4714
4895
|
}
|
|
4715
4896
|
function record(input, asked, outcome, at) {
|
|
4716
4897
|
const search = foundBySearch(input.cwd, input.session, asked.skill);
|
|
4717
|
-
const words = input.transcript !== null &&
|
|
4898
|
+
const words = input.transcript !== null && existsSync3(input.transcript) ? lastUserWords(readFileSync4(input.transcript, "utf8")) : "";
|
|
4718
4899
|
const domain = search?.domain ?? contextOf(words, asked.skill);
|
|
4719
4900
|
const source = asked.source ?? search?.source ?? installedSource(asked.skill.split(":").pop() ?? asked.skill, input.cwd);
|
|
4720
4901
|
const named = outcome === "worked" ? withOf(asked.skill, source, input.cwd, at) : null;
|
|
@@ -4727,22 +4908,22 @@ function record(input, asked, outcome, at) {
|
|
|
4727
4908
|
outcome,
|
|
4728
4909
|
...named === null ? {} : { with: named }
|
|
4729
4910
|
};
|
|
4730
|
-
appendOwn(
|
|
4911
|
+
appendOwn(join5(arpHome(), "outcomes.jsonl"), `${JSON.stringify(line)}
|
|
4731
4912
|
`);
|
|
4732
4913
|
}
|
|
4733
|
-
function askOnSkill(session, skill, source, now = new Date) {
|
|
4914
|
+
function askOnSkill(session, skill, source, cwd = process.cwd(), now = new Date) {
|
|
4734
4915
|
if (isArpsOwn(skill))
|
|
4735
4916
|
return null;
|
|
4736
4917
|
try {
|
|
4737
4918
|
const home = arpHome();
|
|
4738
|
-
|
|
4739
|
-
const askedPath =
|
|
4919
|
+
mkdirSync4(home, { recursive: true });
|
|
4920
|
+
const askedPath = join5(home, "asked.jsonl");
|
|
4740
4921
|
if (rows(askedPath).some((row2) => row2["session"] === session && row2["skill"] === skill))
|
|
4741
4922
|
return null;
|
|
4742
4923
|
const row = { at: now.toISOString(), session, skill, source };
|
|
4743
4924
|
appendOwn(askedPath, `${JSON.stringify(row)}
|
|
4744
4925
|
`);
|
|
4745
|
-
return requestFor(skill);
|
|
4926
|
+
return requestFor(skill, offerShare(session, skill, source, cwd, now));
|
|
4746
4927
|
} catch {
|
|
4747
4928
|
return null;
|
|
4748
4929
|
}
|
|
@@ -4756,20 +4937,22 @@ async function stop(payload) {
|
|
|
4756
4937
|
function onStop(input, now = new Date) {
|
|
4757
4938
|
try {
|
|
4758
4939
|
const home = arpHome();
|
|
4759
|
-
const asked = rows(
|
|
4940
|
+
const asked = rows(join5(home, "asked.jsonl")).flatMap((row) => row["session"] === input.session && typeof row["skill"] === "string" ? [{
|
|
4760
4941
|
at: typeof row["at"] === "string" ? row["at"] : "",
|
|
4761
4942
|
session: input.session,
|
|
4762
4943
|
skill: row["skill"],
|
|
4763
4944
|
source: typeof row["source"] === "string" ? row["source"] : null
|
|
4764
4945
|
}] : []);
|
|
4765
|
-
const answered = new Set(rows(
|
|
4946
|
+
const answered = new Set(rows(join5(home, "outcomes.jsonl")).flatMap((row) => row["session"] === input.session && typeof row["skill"] === "string" ? [row["skill"]] : []));
|
|
4766
4947
|
const pending = asked.filter((row) => !answered.has(row.skill));
|
|
4767
4948
|
const at = now.toISOString();
|
|
4768
|
-
|
|
4949
|
+
const answers = answersIn2(input.last, pending.map((row) => row.skill));
|
|
4950
|
+
for (const [skill, answer] of answers) {
|
|
4769
4951
|
const row = pending.find((entry) => entry.skill === skill);
|
|
4770
4952
|
if (row !== undefined)
|
|
4771
4953
|
record(input, row, answer, at);
|
|
4772
4954
|
}
|
|
4955
|
+
onStopShare(input.session, input.last, answers, now);
|
|
4773
4956
|
} catch {}
|
|
4774
4957
|
}
|
|
4775
4958
|
|
|
@@ -4777,7 +4960,8 @@ function onStop(input, now = new Date) {
|
|
|
4777
4960
|
var ROUTES = {
|
|
4778
4961
|
PreToolUse: (payload) => preToolUse(payload),
|
|
4779
4962
|
PostToolUseFailure: (payload) => postToolUseFailure(payload),
|
|
4780
|
-
Stop: (payload) => stop(payload)
|
|
4963
|
+
Stop: (payload) => stop(payload),
|
|
4964
|
+
SessionEnd: (payload) => sessionEnd(payload)
|
|
4781
4965
|
};
|
|
4782
4966
|
async function route(handler, payload) {
|
|
4783
4967
|
let out = null;
|
|
@@ -4797,12 +4981,12 @@ async function route(handler, payload) {
|
|
|
4797
4981
|
});
|
|
4798
4982
|
}
|
|
4799
4983
|
function fetchedRefs(cwd) {
|
|
4800
|
-
const path = process.env["ARP_RECEIPTS"] ??
|
|
4801
|
-
if (!
|
|
4984
|
+
const path = process.env["ARP_RECEIPTS"] ?? join6(cwd, ".arp", "receipts.jsonl");
|
|
4985
|
+
if (!existsSync4(path))
|
|
4802
4986
|
return [];
|
|
4803
4987
|
let text2;
|
|
4804
4988
|
try {
|
|
4805
|
-
text2 =
|
|
4989
|
+
text2 = readFileSync5(path, "utf8");
|
|
4806
4990
|
} catch {
|
|
4807
4991
|
return [];
|
|
4808
4992
|
}
|
|
@@ -4882,7 +5066,7 @@ try {
|
|
|
4882
5066
|
process.exit(0);
|
|
4883
5067
|
}
|
|
4884
5068
|
if (process.argv.includes("--capture"))
|
|
4885
|
-
capture(parsed2,
|
|
5069
|
+
capture(parsed2, join6(homedir3(), ".arp", "captures"));
|
|
4886
5070
|
var event = eventOf(parsed2);
|
|
4887
5071
|
var handler = event === null ? undefined : ROUTES[event];
|
|
4888
5072
|
if (handler !== undefined)
|
|
@@ -4903,8 +5087,8 @@ if (what === null)
|
|
|
4903
5087
|
var classified = classifyCall(call);
|
|
4904
5088
|
if (classified === null)
|
|
4905
5089
|
process.exit(0);
|
|
4906
|
-
var own =
|
|
4907
|
-
var path = process.env["ARP_SESSION_LOG"] ??
|
|
5090
|
+
var own = join6(cwd, ".arp");
|
|
5091
|
+
var path = process.env["ARP_SESSION_LOG"] ?? join6(own, "session.jsonl");
|
|
4908
5092
|
var line = {
|
|
4909
5093
|
at: new Date().toISOString(),
|
|
4910
5094
|
session: call.session,
|
|
@@ -4917,18 +5101,18 @@ var line = {
|
|
|
4917
5101
|
response: responseOf(call, classified.outcome)
|
|
4918
5102
|
};
|
|
4919
5103
|
try {
|
|
4920
|
-
|
|
4921
|
-
if (
|
|
5104
|
+
mkdirSync5(dirname4(path), { recursive: true });
|
|
5105
|
+
if (dirname4(path) === own && lstatSync2(own).isSymbolicLink())
|
|
4922
5106
|
throw new Error(`${own} is a symbolic link`);
|
|
4923
|
-
const ignore =
|
|
4924
|
-
if (
|
|
4925
|
-
|
|
5107
|
+
const ignore = join6(own, ".gitignore");
|
|
5108
|
+
if (dirname4(path) === own && !existsSync4(ignore))
|
|
5109
|
+
writeFileSync3(ignore, `*
|
|
4926
5110
|
`, { flag: "wx" });
|
|
4927
5111
|
appendOwn(path, `${JSON.stringify(line)}
|
|
4928
5112
|
`);
|
|
4929
5113
|
} catch {}
|
|
4930
5114
|
if (what.kind === "skill" && call.event === "PostToolUse" && classified.outcome === "ok" && call.session !== null) {
|
|
4931
|
-
const request = askOnSkill(call.session, what.name, what.source);
|
|
5115
|
+
const request = askOnSkill(call.session, what.name, what.source, cwd);
|
|
4932
5116
|
if (request !== null)
|
|
4933
5117
|
process.stdout.write(`${requestOutput(request)}
|
|
4934
5118
|
`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@arp-protocol/cli",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.5",
|
|
4
4
|
"mcpName": "io.github.Wieedze/arp",
|
|
5
5
|
"description": "ARP's agent-side programs in one binary: the MCP server, the runtime hook that records what an agent used, and the opt-in hire node. Runs on Node 22 or later.",
|
|
6
6
|
"homepage": "https://github.com/intuition-box/ARP",
|
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
import {
|
|
3
|
-
decideShare,
|
|
4
|
-
installedFromReceipts,
|
|
5
|
-
installedFromSkillLock,
|
|
6
|
-
isSharingOn,
|
|
7
|
-
parseLocalFailures,
|
|
8
|
-
parseLocalOutcomes,
|
|
9
|
-
sharedLineKey
|
|
10
|
-
} from "./cli-wer26exb.js";
|
|
11
|
-
import"./cli-zehr6kdx.js";
|
|
12
|
-
import"./cli-0gsbnq5w.js";
|
|
13
|
-
import"./cli-fbwpcfvp.js";
|
|
14
|
-
import"./cli-mhzh9z8k.js";
|
|
15
|
-
import"./cli-d3dy7cxe.js";
|
|
16
|
-
import"./cli-3kbbwfbp.js";
|
|
17
|
-
import"./cli-g5zvr10v.js";
|
|
18
|
-
|
|
19
|
-
// src/share.ts
|
|
20
|
-
import { appendFileSync, existsSync, mkdirSync, readFileSync, writeFileSync } from "node:fs";
|
|
21
|
-
import { join } from "node:path";
|
|
22
|
-
var read = (path) => existsSync(path) ? readFileSync(path, "utf8") : null;
|
|
23
|
-
function shared(env) {
|
|
24
|
-
const keys = new Set;
|
|
25
|
-
for (const row of (read(join(env.arpHome, "shared-failures.jsonl")) ?? "").split(`
|
|
26
|
-
`)) {
|
|
27
|
-
if (row.trim() === "")
|
|
28
|
-
continue;
|
|
29
|
-
try {
|
|
30
|
-
keys.add(sharedLineKey(JSON.parse(row)));
|
|
31
|
-
} catch {
|
|
32
|
-
continue;
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
return keys;
|
|
36
|
-
}
|
|
37
|
-
function decide(env) {
|
|
38
|
-
const on = isSharingOn(read(join(env.arpHome, "sharing.json")));
|
|
39
|
-
const decision = decideShare({
|
|
40
|
-
on,
|
|
41
|
-
failures: parseLocalFailures(read(join(env.arpHome, "failures.jsonl")) ?? ""),
|
|
42
|
-
outcomes: parseLocalOutcomes(read(join(env.arpHome, "outcomes.jsonl")) ?? ""),
|
|
43
|
-
installed: [
|
|
44
|
-
...installedFromSkillLock(read(join(env.home, ".agents", ".skill-lock.json"))),
|
|
45
|
-
...installedFromSkillLock(read(join(env.cwd, "skills-lock.json"))),
|
|
46
|
-
...installedFromReceipts(read(join(env.arpHome, "receipts.jsonl"))),
|
|
47
|
-
...installedFromReceipts(read(join(env.cwd, ".arp", "receipts.jsonl")))
|
|
48
|
-
],
|
|
49
|
-
alreadyShared: shared(env)
|
|
50
|
-
});
|
|
51
|
-
return { ...decision, on };
|
|
52
|
-
}
|
|
53
|
-
function setSharing(env, on) {
|
|
54
|
-
mkdirSync(env.arpHome, { recursive: true });
|
|
55
|
-
writeFileSync(join(env.arpHome, "sharing.json"), `${JSON.stringify({ failures: on })}
|
|
56
|
-
`);
|
|
57
|
-
}
|
|
58
|
-
async function sendShared(env, write) {
|
|
59
|
-
const { on, lines } = decide(env);
|
|
60
|
-
if (!on)
|
|
61
|
-
return { sent: 0, failed: 0, firstError: null };
|
|
62
|
-
let sent = 0;
|
|
63
|
-
let failed = 0;
|
|
64
|
-
let firstError = null;
|
|
65
|
-
for (const line of lines) {
|
|
66
|
-
try {
|
|
67
|
-
await write(line);
|
|
68
|
-
appendFileSync(join(env.arpHome, "shared-failures.jsonl"), `${JSON.stringify(line)}
|
|
69
|
-
`);
|
|
70
|
-
sent += 1;
|
|
71
|
-
} catch (error) {
|
|
72
|
-
failed += 1;
|
|
73
|
-
firstError ??= error instanceof Error ? error.message : String(error);
|
|
74
|
-
}
|
|
75
|
-
}
|
|
76
|
-
return { sent, failed, firstError };
|
|
77
|
-
}
|
|
78
|
-
var WHY = {
|
|
79
|
-
sharing_off: "sharing is off",
|
|
80
|
-
no_public_source: "no known public source",
|
|
81
|
-
several_sources: "several sources with this name"
|
|
82
|
-
};
|
|
83
|
-
function describe(decision) {
|
|
84
|
-
const out = [`sharing is ${decision.on ? "on" : "off"}`];
|
|
85
|
-
if (decision.lines.length > 0) {
|
|
86
|
-
out.push("", "would be public on testnet 13579:");
|
|
87
|
-
for (const line of decision.lines) {
|
|
88
|
-
const tail = line.outcome === "failed" ? `failed ${line.reason}${line.need === undefined ? "" : ` needs ${line.need}`}` : `worked${line.need === undefined ? "" : ` with ${line.need}`}`;
|
|
89
|
-
out.push(` ${line.toolUrl} ${line.domain ?? "(no domain)"} ${tail}`);
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
if (decision.keptLocal.length > 0) {
|
|
93
|
-
out.push("", "stays on this machine:");
|
|
94
|
-
for (const row of decision.keptLocal)
|
|
95
|
-
out.push(` ${row.skill}: ${WHY[row.why]}`);
|
|
96
|
-
}
|
|
97
|
-
return `${out.join(`
|
|
98
|
-
`)}
|
|
99
|
-
`;
|
|
100
|
-
}
|
|
101
|
-
export {
|
|
102
|
-
setSharing,
|
|
103
|
-
sendShared,
|
|
104
|
-
describe,
|
|
105
|
-
decide
|
|
106
|
-
};
|