@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.
package/dist/hook.js ADDED
@@ -0,0 +1,4337 @@
1
+ // ../hook/src/append.ts
2
+ import { closeSync, constants, lstatSync, openSync, writeSync } from "node:fs";
3
+ import { dirname } from "node:path";
4
+ function appendOwn(path, text) {
5
+ if (lstatSync(dirname(path)).isSymbolicLink())
6
+ throw new Error(`${dirname(path)} is a symbolic link`);
7
+ const flags = constants.O_WRONLY | constants.O_APPEND | constants.O_CREAT | (constants.O_NOFOLLOW ?? 0);
8
+ const fd = openSync(path, flags, 384);
9
+ try {
10
+ writeSync(fd, text);
11
+ } finally {
12
+ closeSync(fd);
13
+ }
14
+ }
15
+
16
+ // ../hook/src/hook.ts
17
+ import { existsSync as existsSync3, lstatSync as lstatSync2, mkdirSync as mkdirSync4, readFileSync as readFileSync4, writeFileSync as writeFileSync2 } from "node:fs";
18
+ import { homedir as homedir3 } from "node:os";
19
+ import { dirname as dirname4, join as join5 } from "node:path";
20
+ // ../../packages/graphql/dist/http.js
21
+ var DEFAULT_TIMEOUT_MS = 1e4;
22
+ var DEFAULT_MAX_BODY_BYTES = 8 * 1024 * 1024;
23
+
24
+ class HttpError extends Error {
25
+ kind;
26
+ timeoutMs;
27
+ constructor(kind, message, timeoutMs, cause) {
28
+ super(message, cause === undefined ? undefined : { cause });
29
+ this.name = "HttpError";
30
+ this.kind = kind;
31
+ this.timeoutMs = timeoutMs;
32
+ }
33
+ }
34
+ async function readBodyText(response, options = {}) {
35
+ const maxBytes = options.maxBytes ?? DEFAULT_MAX_BODY_BYTES;
36
+ const timeoutMs = options.timeoutMs ?? 0;
37
+ const body = response.body;
38
+ if (body === null)
39
+ return "";
40
+ const reader = body.getReader();
41
+ const signal = options.signal;
42
+ let onAbort = null;
43
+ const aborted = signal === undefined ? null : new Promise((_, reject) => {
44
+ const fire = () => reject(new HttpError("timeout", `timed out after ${timeoutMs}ms reading the body`, timeoutMs));
45
+ onAbort = fire;
46
+ if (signal.aborted)
47
+ fire();
48
+ else
49
+ signal.addEventListener("abort", fire, { once: true });
50
+ });
51
+ aborted?.catch(() => {
52
+ return;
53
+ });
54
+ const decoder = new TextDecoder;
55
+ let total = 0;
56
+ let text = "";
57
+ try {
58
+ for (;; ) {
59
+ const chunk = await (aborted === null ? reader.read() : Promise.race([reader.read(), aborted]));
60
+ if (chunk.done)
61
+ break;
62
+ total += chunk.value.byteLength;
63
+ if (total > maxBytes) {
64
+ throw new HttpError("too-large", `body exceeds ${maxBytes} bytes`, timeoutMs);
65
+ }
66
+ text += decoder.decode(chunk.value, { stream: true });
67
+ }
68
+ return text + decoder.decode();
69
+ } catch (error) {
70
+ reader.cancel().catch(() => {
71
+ return;
72
+ });
73
+ if (error instanceof HttpError)
74
+ throw error;
75
+ throw new HttpError("network", error instanceof Error ? error.message : String(error), timeoutMs, error);
76
+ } finally {
77
+ if (signal !== undefined && onAbort !== null)
78
+ signal.removeEventListener("abort", onAbort);
79
+ }
80
+ }
81
+ async function fetchTextWithTimeout(fetchImpl, url, init, options) {
82
+ const { timeoutMs } = options;
83
+ const controller = new AbortController;
84
+ const timer = setTimeout(() => controller.abort(), timeoutMs);
85
+ try {
86
+ let response;
87
+ try {
88
+ response = await fetchImpl(url, { ...init, signal: controller.signal });
89
+ } catch (error) {
90
+ if (controller.signal.aborted) {
91
+ throw new HttpError("timeout", `timed out after ${timeoutMs}ms: ${url}`, timeoutMs);
92
+ }
93
+ throw new HttpError("network", error instanceof Error ? error.message : String(error), timeoutMs, error);
94
+ }
95
+ const text = await readBodyText(response, {
96
+ signal: controller.signal,
97
+ timeoutMs,
98
+ ...options.maxBytes === undefined ? {} : { maxBytes: options.maxBytes }
99
+ });
100
+ return { response, text };
101
+ } finally {
102
+ clearTimeout(timer);
103
+ }
104
+ }
105
+ function defaultFetch() {
106
+ if (typeof globalThis.fetch !== "function") {
107
+ throw new TypeError("no global fetch available — pass one via createErc8004Client({fetch})");
108
+ }
109
+ return (input, init) => globalThis.fetch(input, init);
110
+ }
111
+ // ../../packages/graphql/dist/json.js
112
+ function isRecord(value) {
113
+ return typeof value === "object" && value !== null && !Array.isArray(value);
114
+ }
115
+ function readRecord(source, key) {
116
+ if (!isRecord(source))
117
+ return null;
118
+ const child = source[key];
119
+ return isRecord(child) ? child : null;
120
+ }
121
+ function readString(source, key) {
122
+ if (!isRecord(source))
123
+ return null;
124
+ const value = source[key];
125
+ return typeof value === "string" ? value : null;
126
+ }
127
+ function readArray(source, key) {
128
+ if (!isRecord(source))
129
+ return [];
130
+ const value = source[key];
131
+ return Array.isArray(value) ? value : [];
132
+ }
133
+ // ../../packages/graphql/dist/client.js
134
+ class GraphqlError extends Error {
135
+ url;
136
+ httpStatus;
137
+ constructor(message, url, httpStatus, cause) {
138
+ super(message, cause === undefined ? undefined : { cause });
139
+ this.name = "GraphqlError";
140
+ this.url = url;
141
+ this.httpStatus = httpStatus;
142
+ }
143
+ }
144
+ function createGraphqlTransport(config) {
145
+ const timeoutMs = config.timeoutMs ?? DEFAULT_TIMEOUT_MS;
146
+ return {
147
+ async request(query, variables, options) {
148
+ let response;
149
+ let text;
150
+ try {
151
+ ({ response, text } = await fetchTextWithTimeout(config.fetch, config.url, {
152
+ method: "POST",
153
+ headers: {
154
+ "content-type": "application/json",
155
+ accept: "application/json"
156
+ },
157
+ body: JSON.stringify({ query, variables })
158
+ }, {
159
+ timeoutMs: options?.timeoutMs ?? timeoutMs,
160
+ ...config.maxBodyBytes === undefined ? {} : { maxBytes: config.maxBodyBytes }
161
+ }));
162
+ } catch (error) {
163
+ const message = error instanceof HttpError ? error.message : String(error);
164
+ throw new GraphqlError(message, config.url, null, error);
165
+ }
166
+ if (!response.ok) {
167
+ throw new GraphqlError(`HTTP ${response.status} ${response.statusText}`, config.url, response.status);
168
+ }
169
+ let body = null;
170
+ try {
171
+ body = JSON.parse(text);
172
+ } catch {
173
+ body = null;
174
+ }
175
+ if (!isRecord(body)) {
176
+ throw new GraphqlError("response body is not a JSON object", config.url, 200);
177
+ }
178
+ const errors = readArray(body, "errors");
179
+ if (errors.length > 0) {
180
+ const messages = errors.map((entry) => readString(entry, "message") ?? "unknown error").join("; ");
181
+ throw new GraphqlError(messages, config.url, 200);
182
+ }
183
+ const data = body["data"];
184
+ if (!isRecord(data)) {
185
+ throw new GraphqlError("response carries no data object", config.url, 200);
186
+ }
187
+ return data;
188
+ }
189
+ };
190
+ }
191
+ // ../../packages/graphql/dist/queries/agent.js
192
+ var THING = `value { thing { name description image url } }`;
193
+ var MARKET_SIDE = `
194
+ total_market_cap
195
+ total_assets
196
+ vaults(where: {curve_id: {_eq: $curveId}}, limit: 1) {
197
+ market_cap
198
+ total_assets
199
+ total_shares
200
+ current_share_price
201
+ position_count
202
+ }`;
203
+ var RESOLVE_AGENT_QUERY = `
204
+ query ResolveAgentByCaip($sameAsPredicateId: String!, $caipId: String!) {
205
+ triples(
206
+ where: {
207
+ predicate_id: {_eq: $sameAsPredicateId}
208
+ object: {value: {thing: {name: {_eq: $caipId}}}}
209
+ }
210
+ limit: 2
211
+ ) {
212
+ subject { term_id label data ${THING} }
213
+ }
214
+ }`;
215
+ var TRUST_SURFACE_QUERY = `
216
+ query AgentTrustSurface($subjectId: String!, $predicateIds: [String!], $curveId: numeric!, $limit: Int!) {
217
+ triples(
218
+ where: {subject_id: {_eq: $subjectId}, predicate_id: {_in: $predicateIds}}
219
+ order_by: {term: {total_market_cap: desc}}
220
+ limit: $limit
221
+ ) {
222
+ term_id
223
+ predicate { term_id label }
224
+ object { term_id label data ${THING} }
225
+ term {${MARKET_SIDE}
226
+ }
227
+ counter_term {${MARKET_SIDE}
228
+ }
229
+ }
230
+ }`;
231
+ var CAPABILITIES_QUERY = `
232
+ query AgentCapabilities($subjectId: String!, $predicateIds: [String!], $limit: Int!) {
233
+ triples(
234
+ where: {subject_id: {_eq: $subjectId}, predicate_id: {_in: $predicateIds}}
235
+ order_by: {term_id: asc}
236
+ limit: $limit
237
+ ) {
238
+ term_id
239
+ predicate { term_id label }
240
+ object { term_id label ${THING} }
241
+ }
242
+ }`;
243
+ var IDENTITY_SAMPLE_LIMIT = 4;
244
+ var CAPABILITY_SAMPLE_LIMIT = 8;
245
+ var COHORT_QUERY = `
246
+ query AgentCohort($where: triples_bool_exp!, $sameAsPredicateId: String!, $capabilityPredicateIds: [String!], $orderBy: [triples_order_by!]!, $limit: Int!, $offset: Int!) {
247
+ total: triples_aggregate(
248
+ where: $where
249
+ ) {
250
+ aggregate { count }
251
+ }
252
+ triples(
253
+ where: $where
254
+ order_by: $orderBy
255
+ limit: $limit
256
+ offset: $offset
257
+ ) {
258
+ subject {
259
+ term_id
260
+ label
261
+ ${THING}
262
+ as_subject_triples_aggregate { aggregate { count } }
263
+ term {
264
+ total_market_cap
265
+ vaults_aggregate { aggregate { count sum { position_count } } }
266
+ }
267
+ identityCount: as_subject_triples_aggregate(
268
+ where: {predicate_id: {_eq: $sameAsPredicateId}}
269
+ ) {
270
+ aggregate { count }
271
+ }
272
+ identity: as_subject_triples(
273
+ where: {predicate_id: {_eq: $sameAsPredicateId}}
274
+ limit: ${IDENTITY_SAMPLE_LIMIT}
275
+ ) {
276
+ object { label ${THING} }
277
+ }
278
+ capabilities: as_subject_triples(
279
+ where: {predicate_id: {_in: $capabilityPredicateIds}}
280
+ limit: ${CAPABILITY_SAMPLE_LIMIT}
281
+ ) {
282
+ predicate_id
283
+ object { term_id label }
284
+ }
285
+ }
286
+ }
287
+ }`;
288
+ // ../../packages/graphql/dist/queries/atom-standing.js
289
+ var VAULT_SIDE = `
290
+ total_market_cap
291
+ total_assets
292
+ vaults(where: {curve_id: {_eq: $curveId}}, limit: 1) {
293
+ market_cap
294
+ total_assets
295
+ total_shares
296
+ current_share_price
297
+ position_count
298
+ }`;
299
+ var ATOM_STANDING_QUERY = `
300
+ query AtomStanding($atomId: String!, $curveId: numeric!, $limit: Int!, $attestor: [String!]!) {
301
+ atom: atoms(where: {term_id: {_eq: $atomId}}, limit: 1) {
302
+ term_id
303
+ label
304
+ data
305
+ type
306
+ value { thing { url } }
307
+ term { ${VAULT_SIDE} }
308
+ }
309
+ triples(
310
+ where: {object_id: {_eq: $atomId}}
311
+ order_by: {term: {total_assets: desc}}
312
+ limit: $limit
313
+ ) {
314
+ term_id
315
+ predicate { term_id label }
316
+ subject { term_id label type }
317
+ term { ${VAULT_SIDE} }
318
+ counter_term { ${VAULT_SIDE} }
319
+ }
320
+ claims: triples(
321
+ where: {subject_id: {_eq: $atomId}}
322
+ order_by: {term: {total_assets: desc}}
323
+ limit: $limit
324
+ ) {
325
+ term_id
326
+ predicate { term_id label }
327
+ object { term_id label type }
328
+ term {
329
+ ${VAULT_SIDE}
330
+ vaults(where: {curve_id: {_eq: $curveId}}, limit: 1) {
331
+ positions(where: {account_id: {_in: $attestor}, shares: {_gt: "0"}}, limit: 1) { shares }
332
+ }
333
+ }
334
+ }
335
+ }`;
336
+ var LISTED_CAPABILITIES_FOR_QUERY = `query ListedCapabilitiesFor($subject: String!, $predicates: [String!]) {
337
+ atoms(where: {term_id: {_eq: $subject}}, limit: 1) {
338
+ capabilities: as_subject_triples(
339
+ where: {predicate_id: {_in: $predicates}}
340
+ limit: ${CAPABILITY_SAMPLE_LIMIT}
341
+ ) { object { term_id } }
342
+ }
343
+ }`;
344
+ // ../../packages/graphql/dist/queries/tool-listing.js
345
+ function toolListingQuery(sponsored) {
346
+ const variables = sponsored ? "$uses: String!, $sameAs: String!, $curveId: numeric!, $limit: Int!, $sponsor: String!" : "$uses: String!, $sameAs: String!, $curveId: numeric!, $limit: Int!";
347
+ const sponsoredCount = sponsored ? `
348
+ sponsored: deposits_aggregate(where: {sender_id: {_ilike: $sponsor}, receiver_id: {_nilike: $sponsor}}) { aggregate { count } }` : "";
349
+ return `
350
+ query ToolListing(${variables}) {
351
+ triples(
352
+ where: {
353
+ predicate_id: {_eq: $uses}
354
+ subject: {as_subject_triples: {predicate_id: {_eq: $sameAs}}}
355
+ }
356
+ limit: $limit
357
+ ) {
358
+ term_id
359
+ subject_id
360
+ object {
361
+ term_id
362
+ label
363
+ data
364
+ type
365
+ value { thing { url } }
366
+ }
367
+ term {
368
+ total_assets
369
+ vaults(where: {curve_id: {_eq: $curveId}}, limit: 1) { position_count total_assets }
370
+ deposits: deposits_aggregate { aggregate { count } }${sponsoredCount}
371
+ }
372
+ counter_term {
373
+ total_assets
374
+ vaults(where: {curve_id: {_eq: $curveId}}, limit: 1) { position_count total_assets }
375
+ }
376
+ }
377
+ }`;
378
+ }
379
+ var TOOL_LISTING_QUERY = toolListingQuery(false);
380
+ var TOOL_LISTING_SPONSORED_QUERY = toolListingQuery(true);
381
+ // ../../packages/graphql/dist/queries/pulse-usage.js
382
+ var PULSE_USES_QUERY = `query PulseUses($tools: [String!]!, $uses: String!, $limit: Int!) {
383
+ triples(where: {object_id: {_in: $tools}, predicate_id: {_eq: $uses}}, limit: $limit) {
384
+ term_id
385
+ object_id
386
+ creator_id
387
+ created_at
388
+ subject {
389
+ term_id
390
+ label
391
+ }
392
+ positions(where: {shares: {_gt: "0"}}) {
393
+ account_id
394
+ }
395
+ }
396
+ }`;
397
+ var PULSE_QUALIFIERS_QUERY = `query PulseQualifiers($edges: [String!]!, $predicates: [String!]!, $writers: [String!]!, $limit: Int!) {
398
+ triples(where: {subject_id: {_in: $edges}, predicate_id: {_in: $predicates}}, limit: $limit) {
399
+ term_id
400
+ subject_id
401
+ predicate_id
402
+ creator_id
403
+ created_at
404
+ object {
405
+ label
406
+ }
407
+ positions(where: {shares: {_gt: "0"}, account_id: {_in: $writers}}) {
408
+ account_id
409
+ }
410
+ }
411
+ }`;
412
+ var PULSE_ATOMS_QUERY = `query PulseAtoms($uris: [String!]!, $limit: Int!) {
413
+ atoms(where: {data: {_in: $uris}}, limit: $limit) {
414
+ term_id
415
+ data
416
+ }
417
+ }`;
418
+ // ../../packages/graphql/dist/queries/tool-usage.js
419
+ var VAULT_SIDE2 = `
420
+ total_market_cap
421
+ total_assets
422
+ vaults(where: {curve_id: {_eq: $curveId}}, limit: 1) {
423
+ market_cap
424
+ total_assets
425
+ total_shares
426
+ current_share_price
427
+ position_count
428
+ }`;
429
+ var TOOL_USAGE_QUERY = `
430
+ query ToolUsage($toolId: String!, $uses: String!, $curveId: numeric!) {
431
+ tool: atoms(where: {term_id: {_eq: $toolId}}, limit: 1) {
432
+ term_id
433
+ label
434
+ data
435
+ }
436
+ triples(where: {predicate_id: {_eq: $uses}, object_id: {_eq: $toolId}}, limit: 200) {
437
+ term_id
438
+ subject {
439
+ term_id
440
+ label
441
+ type
442
+ }
443
+ term { ${VAULT_SIDE2} }
444
+ counter_term { ${VAULT_SIDE2} }
445
+ }
446
+ }`;
447
+ var ATTESTED_TOOL_USAGE_QUERY = `
448
+ query AttestedToolUsage($toolId: String!, $uses: String!, $curveId: numeric!, $attestor: String!) {
449
+ tool: atoms(where: {term_id: {_eq: $toolId}}, limit: 1) {
450
+ term_id
451
+ label
452
+ data
453
+ }
454
+ triples(where: {
455
+ predicate_id: {_eq: $uses},
456
+ object_id: {_eq: $toolId},
457
+ term: {positions: {account_id: {_eq: $attestor}}}
458
+ }, limit: 200) {
459
+ term_id
460
+ subject {
461
+ term_id
462
+ label
463
+ type
464
+ }
465
+ term { ${VAULT_SIDE2} }
466
+ counter_term { ${VAULT_SIDE2} }
467
+ }
468
+ }`;
469
+ // ../../packages/graphql/dist/queries/x402-feed.js
470
+ var LEVEL = `term_id
471
+ subject_id
472
+ predicate_id
473
+ creator_id
474
+ created_at
475
+ subject {
476
+ term_id
477
+ label
478
+ }
479
+ object {
480
+ term_id
481
+ label
482
+ data
483
+ value {
484
+ thing {
485
+ url
486
+ }
487
+ }
488
+ }
489
+ positions(where: {shares: {_gt: "0"}}) {
490
+ account_id
491
+ }`;
492
+ var X402_PAYMENT_LEVELS_QUERY = `query X402PaymentLevels($paidWith: String!, $limit: Int!, $offset: Int!) {
493
+ triples(where: {predicate_id: {_eq: $paidWith}}, order_by: {term_id: asc}, limit: $limit, offset: $offset) {
494
+ ${LEVEL}
495
+ }
496
+ }`;
497
+ var X402_LEVELS_BY_ID_QUERY = `query X402LevelsById($ids: [String!]!, $limit: Int!) {
498
+ triples(where: {term_id: {_in: $ids}}, limit: $limit) {
499
+ ${LEVEL}
500
+ }
501
+ }`;
502
+ var X402_REASONS_QUERY = `query X402Reasons($ids: [String!]!, $because: String!, $limit: Int!) {
503
+ triples(where: {subject_id: {_in: $ids}, predicate_id: {_eq: $because}}, order_by: {term_id: asc}, limit: $limit) {
504
+ ${LEVEL}
505
+ }
506
+ }`;
507
+ // ../../packages/protocol/dist/declare/tool-thing.js
508
+ class InvalidToolUrlError extends Error {
509
+ input;
510
+ constructor(input, why) {
511
+ super(`${JSON.stringify(input)} is not a usable tool URL: ${why}`);
512
+ this.name = "InvalidToolUrlError";
513
+ this.input = input;
514
+ }
515
+ }
516
+ function normaliseToolUrl(input) {
517
+ const trimmed = input.trim();
518
+ if (trimmed.length === 0)
519
+ throw new InvalidToolUrlError(input, "empty");
520
+ const withScheme = /^[a-z][a-z0-9+.-]*:/i.test(trimmed) ? trimmed : `https://${trimmed}`;
521
+ let url;
522
+ try {
523
+ url = new URL(withScheme);
524
+ } catch {
525
+ throw new InvalidToolUrlError(input, "not parseable as a URL");
526
+ }
527
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
528
+ throw new InvalidToolUrlError(input, `scheme ${url.protocol} is not http or https`);
529
+ }
530
+ if (url.hostname.length === 0)
531
+ throw new InvalidToolUrlError(input, "no host");
532
+ const host = url.hostname.replace(/\.+$/, "").replace(/^(?:www\.)+/, "");
533
+ const path = url.pathname.replace(/(?:\.git|\/)+$/, "");
534
+ const params = [...new URLSearchParams(url.search).entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
535
+ const query = params.length === 0 ? "" : `?${new URLSearchParams(params).toString()}`;
536
+ const port = url.port === "" || url.port === "80" || url.port === "443" ? "" : `:${url.port}`;
537
+ return `https://${host}${port}${path}${query}`;
538
+ }
539
+ // ../../packages/protocol/dist/session.js
540
+ function refForInvocation(name, source, fetched) {
541
+ const bare = name.includes(":") ? name.split(":").pop() ?? name : name;
542
+ let matches = fetched.filter((row) => row.skill === bare);
543
+ if (source !== null && matches.length > 1) {
544
+ const narrowed = matches.filter((row) => source.includes(repoOf(row.url)));
545
+ if (narrowed.length > 0)
546
+ matches = narrowed;
547
+ }
548
+ const atoms = new Set(matches.map((row) => row.atom.toLowerCase()));
549
+ if (atoms.size !== 1)
550
+ return null;
551
+ return matches[0]?.atom ?? null;
552
+ }
553
+ function repoOf(url) {
554
+ const parts = /github\.com\/([^/?#]+)\/([^/?#]+)/.exec(url);
555
+ return parts === null ? url : `${parts[1]}/${parts[2]}`;
556
+ }
557
+ // ../../packages/protocol/dist/skill-requires.js
558
+ var LOGIN = /\b(auth login|log ?in|sign ?up|api[ _-]?key|access token)\b/i;
559
+ function frontmatter(markdown) {
560
+ const lines = markdown.split(`
561
+ `);
562
+ if (lines[0]?.trim() !== "---")
563
+ return { lines: [], bodyStart: 0 };
564
+ const end = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
565
+ return end === -1 ? { lines: [], bodyStart: 0 } : { lines: lines.slice(1, end), bodyStart: end + 1 };
566
+ }
567
+ function unquote(value) {
568
+ return value.trim().replace(/^["']|["']$/g, "");
569
+ }
570
+ function declaredBins(lines) {
571
+ const at = lines.findIndex((line) => /^\s*bins\s*:/.test(line));
572
+ if (at === -1)
573
+ return [];
574
+ const inline = lines[at]?.split(":").slice(1).join(":").trim() ?? "";
575
+ if (inline.startsWith("[")) {
576
+ return inline.replace(/^\[|\]$/g, "").split(",").map(unquote).filter((name) => name.length > 0);
577
+ }
578
+ const out = [];
579
+ for (const line of lines.slice(at + 1)) {
580
+ const item = /^\s*-\s*(.+)$/.exec(line);
581
+ if (item === null)
582
+ break;
583
+ out.push(unquote(item[1] ?? ""));
584
+ }
585
+ return out.filter((name) => name.length > 0);
586
+ }
587
+ function bashTools(lines) {
588
+ const line = lines.find((candidate) => /^\s*allowed-tools\s*:/.test(candidate));
589
+ if (line === undefined)
590
+ return [];
591
+ return [...line.matchAll(/Bash\(\s*([A-Za-z0-9._-]+)/g)].map((match) => match[1] ?? "").filter((name) => name.length > 0);
592
+ }
593
+ function declaredDescription(lines) {
594
+ const at = lines.findIndex((line) => /^description\s*:/.test(line));
595
+ if (at === -1)
596
+ return null;
597
+ const inline = lines[at]?.split(":").slice(1).join(":").trim() ?? "";
598
+ if (inline !== "" && !/^[>|][-+]?$/.test(inline))
599
+ return unquote(inline) || null;
600
+ const block = [];
601
+ for (const line of lines.slice(at + 1)) {
602
+ if (!/^\s+\S/.test(line))
603
+ break;
604
+ block.push(line.trim());
605
+ }
606
+ return block.length === 0 ? null : block.join(" ");
607
+ }
608
+ var COMMON = new Set(("awk bash break bun case cat cd chmod command continue cp curl cut date diff do done echo else end env " + "esac exit export false fi find for function git grep head if kill ln local ls mkdir mv node npm npx open pip pip3 pnpm printf pwd " + "python python3 read return rm sed set sh shift sleep sort source sudo tail tar tee test then time " + "touch tr true uniq unset unzip wait wc wget which while xargs yarn zip").split(" "));
609
+ var INSTALL = /\b(?:npm\s+(?:i|install)\s+(?:-g|--global)|pnpm\s+add\s+-g|yarn\s+global\s+add|brew\s+install|pipx\s+install|pip3?\s+install|cargo\s+install)\s+([@a-z0-9][@\w./-]*)/i;
610
+ var PROBE = /\b(?:command\s+-v|which)\s+([a-z][\w-]*)/i;
611
+ var COMMAND = /^[a-z][a-z0-9_-]*$/;
612
+ function commandsIn(shell, explicitOnly) {
613
+ const found = [];
614
+ for (const segment of shell.split(/&&|\|\||[|;]/)) {
615
+ const line = segment.trim().replace(/^\$\s+/, "");
616
+ if (line === "" || line.startsWith("#"))
617
+ continue;
618
+ const named = INSTALL.exec(line)?.[1] ?? PROBE.exec(line)?.[1];
619
+ if (named !== undefined) {
620
+ found.push(named);
621
+ continue;
622
+ }
623
+ if (explicitOnly)
624
+ continue;
625
+ const words = line.split(/\s+/).filter((word) => !/^[A-Za-z_][A-Za-z0-9_]*=/.test(word));
626
+ const first = words[0] === "sudo" ? words[1] : words[0];
627
+ if (first === undefined || !COMMAND.test(first))
628
+ continue;
629
+ found.push(first);
630
+ }
631
+ return found;
632
+ }
633
+ var SHELL_FENCE = /^(sh|bash|shell|zsh|console|terminal)$/i;
634
+ function shellLinesRun(lines) {
635
+ const run = [];
636
+ let heredocEnd = null;
637
+ let quote = null;
638
+ let continued = false;
639
+ for (const line of lines) {
640
+ if (heredocEnd !== null) {
641
+ if (line.trim() === heredocEnd)
642
+ heredocEnd = null;
643
+ continue;
644
+ }
645
+ if (quote === null && !continued)
646
+ run.push(line);
647
+ continued = line.trimEnd().endsWith("\\");
648
+ heredocEnd = /<<-?\s*['"]?([A-Za-z_]+)/.exec(line)?.[1] ?? null;
649
+ for (const char of line) {
650
+ if (quote === null && (char === '"' || char === "'"))
651
+ quote = char;
652
+ else if (char === quote)
653
+ quote = null;
654
+ }
655
+ }
656
+ return run;
657
+ }
658
+ function commandsRun(body, declared) {
659
+ const found = [];
660
+ let fence = null;
661
+ let fenced = [];
662
+ for (const line of body) {
663
+ const marker = /^\s*(?:```|~~~)\s*([\w-]*)/.exec(line);
664
+ if (marker !== null) {
665
+ if (fence === "shell") {
666
+ for (const run of shellLinesRun(fenced))
667
+ found.push(...commandsIn(run, false));
668
+ }
669
+ fenced = [];
670
+ fence = fence !== null ? null : SHELL_FENCE.test(marker[1] ?? "") ? "shell" : "other";
671
+ continue;
672
+ }
673
+ if (fence !== null) {
674
+ fenced.push(line);
675
+ continue;
676
+ }
677
+ for (const inline of line.matchAll(/`([^`]+)`/g))
678
+ found.push(...commandsIn(inline[1] ?? "", true));
679
+ }
680
+ return [...new Set(found)].filter((name) => !COMMON.has(name) && !declared.includes(name));
681
+ }
682
+ function requiresLine(lines) {
683
+ const name = lines.map((line) => /^\s*requires\s*:\s*(\S+)\s*$/.exec(line)?.[1]).find(Boolean);
684
+ return name === undefined ? [] : [unquote(name)];
685
+ }
686
+ function readRequires(markdown) {
687
+ const { lines, bodyStart } = frontmatter(markdown);
688
+ const cli = [...new Set([...declaredBins(lines), ...bashTools(lines), ...requiresLine(lines)])];
689
+ const description = declaredDescription(lines);
690
+ const body = markdown.split(`
691
+ `);
692
+ const runs = commandsRun(body.slice(bodyStart), cli);
693
+ for (let index = bodyStart;index < body.length; index += 1) {
694
+ const text = body[index] ?? "";
695
+ if (LOGIN.test(text)) {
696
+ return { cli, runs, login: { line: index + 1, text: text.trim().slice(0, 160) }, description };
697
+ }
698
+ }
699
+ return { cli, runs, login: null, description };
700
+ }
701
+ // ../../packages/protocol/dist/content-path.js
702
+ function skillRefFromUrl(url) {
703
+ let parsed;
704
+ try {
705
+ parsed = new URL(url.includes("://") ? url : `https://${url}`);
706
+ } catch {
707
+ return null;
708
+ }
709
+ if (parsed.hostname.replace(/^www\./, "") !== "github.com")
710
+ return null;
711
+ const skill = parsed.searchParams.get("skill");
712
+ if (skill === null || skill.length === 0)
713
+ return null;
714
+ const [owner, repo] = parsed.pathname.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\.git$/, "").split("/");
715
+ if (owner === undefined || repo === undefined)
716
+ return null;
717
+ if (owner.length === 0 || repo.length === 0)
718
+ return null;
719
+ return { repo: `${owner}/${repo}`, skill };
720
+ }
721
+
722
+ // ../../packages/protocol/dist/share-failures.js
723
+ function installedFromSkillLock(lock) {
724
+ if (lock === null)
725
+ return [];
726
+ try {
727
+ const parsed = JSON.parse(lock);
728
+ return Object.entries(parsed.skills ?? {}).flatMap(([skill, entry]) => entry?.sourceType === "github" && typeof entry.source === "string" ? [{ skill, source: entry.source }] : []);
729
+ } catch {
730
+ return [];
731
+ }
732
+ }
733
+ function installedFromReceipts(text) {
734
+ const found = [];
735
+ for (const line of (text ?? "").split(`
736
+ `)) {
737
+ if (line.trim() === "")
738
+ continue;
739
+ try {
740
+ const row = JSON.parse(line);
741
+ const url = typeof row.url === "string" ? row.url : row.receipt?.url;
742
+ const ref = typeof url === "string" ? skillRefFromUrl(url) : null;
743
+ if (ref !== null)
744
+ found.push({ skill: ref.skill, source: ref.repo });
745
+ } catch {
746
+ continue;
747
+ }
748
+ }
749
+ return found;
750
+ }
751
+ // ../hook/src/classify.ts
752
+ var CANCELLED = /\b(interrupted|cancel(l)?ed|aborted) by (the )?user\b|\buser (rejected|denied|declined)\b|\bpermission denied by user\b|\buser doesn't want to (proceed|take this action)\b/i;
753
+ var AUTH = /\b(unauthori[sz]ed|forbidden|invalid (api )?(key|token)|authentication|not authenticated|expired token)\b/i;
754
+ var TIMEOUT = /\b(timed? ?out|timeout|deadline exceeded|ETIMEDOUT)\b/i;
755
+ var UNREACHABLE = /\b(ENOTFOUND|EAI_AGAIN|ECONNREFUSED|ECONNRESET|EHOSTUNREACH|ENETUNREACH|getaddrinfo|certificate|TLS|SSL|socket hang up|connection refused|fetch failed)\b/i;
756
+ var PAYMENT = /\b(payment required|insufficient (funds|balance)|payment (failed|refused|rejected)|x402)\b/i;
757
+ var STATUS = /\b(40[123]|429|5\d\d)\b/;
758
+ function isRecord2(value) {
759
+ return typeof value === "object" && value !== null && !Array.isArray(value);
760
+ }
761
+ function failureText(call) {
762
+ const parts = [];
763
+ const push = (value) => {
764
+ if (typeof value === "string")
765
+ parts.push(value);
766
+ else if (isRecord2(value)) {
767
+ for (const key of ["error", "message", "reason"]) {
768
+ const text = value[key];
769
+ if (typeof text === "string")
770
+ parts.push(text);
771
+ }
772
+ if (Array.isArray(value.content)) {
773
+ for (const item of value.content) {
774
+ if (isRecord2(item) && typeof item.text === "string")
775
+ parts.push(item.text);
776
+ }
777
+ }
778
+ }
779
+ };
780
+ push(call.error);
781
+ push(call.response);
782
+ return parts.join(`
783
+ `).slice(0, 4000);
784
+ }
785
+ function statusOf(call) {
786
+ if (!isRecord2(call.response))
787
+ return null;
788
+ for (const key of ["status", "statusCode", "status_code"]) {
789
+ const value = call.response[key];
790
+ if (typeof value === "number" && Number.isInteger(value))
791
+ return value;
792
+ }
793
+ return null;
794
+ }
795
+ function flaggedError(response) {
796
+ return isRecord2(response) && (response.isError === true || response.is_error === true);
797
+ }
798
+ function classifyCall(call) {
799
+ if (call.interrupted)
800
+ return null;
801
+ const failed = call.event === "PostToolUseFailure" || call.error !== null || flaggedError(call.response);
802
+ const status = statusOf(call);
803
+ if (!failed && (status === null || status < 400))
804
+ return { outcome: "ok", code: null };
805
+ const text = failureText(call);
806
+ if (CANCELLED.test(text))
807
+ return null;
808
+ const found = STATUS.exec(text);
809
+ const match = status ?? (found === null ? null : Number(found[0]));
810
+ const code = match === null ? null : String(match);
811
+ if (match === 402 || PAYMENT.test(text))
812
+ return { outcome: "payment", code };
813
+ if (match === 401 || match === 403 || AUTH.test(text))
814
+ return { outcome: "auth", code };
815
+ if (TIMEOUT.test(text))
816
+ return { outcome: "timeout", code };
817
+ if (UNREACHABLE.test(text))
818
+ return { outcome: "unreachable", code };
819
+ return { outcome: "tool_error", code };
820
+ }
821
+
822
+ // ../hook/src/mcp-config.ts
823
+ import { readFileSync } from "node:fs";
824
+ import { homedir } from "node:os";
825
+ import { join } from "node:path";
826
+ function isRecord3(value) {
827
+ return typeof value === "object" && value !== null && !Array.isArray(value);
828
+ }
829
+ function readJson(path) {
830
+ try {
831
+ return JSON.parse(readFileSync(path, "utf8"));
832
+ } catch {
833
+ return;
834
+ }
835
+ }
836
+ function entryOf(raw) {
837
+ if (!isRecord3(raw))
838
+ return null;
839
+ if (typeof raw.url === "string" && raw.url.length > 0)
840
+ return { transport: "remote", url: raw.url };
841
+ if (typeof raw.command === "string" && raw.command.length > 0) {
842
+ const args = Array.isArray(raw.args) ? raw.args.filter((arg) => typeof arg === "string") : [];
843
+ return { transport: "local", command: raw.command, args };
844
+ }
845
+ return null;
846
+ }
847
+ function collect(into, servers) {
848
+ if (!isRecord3(servers))
849
+ return;
850
+ for (const [name, raw] of Object.entries(servers)) {
851
+ const entry = entryOf(raw);
852
+ if (entry !== null)
853
+ into.set(name, entry);
854
+ }
855
+ }
856
+ function readMcpServers({
857
+ cwd,
858
+ home = homedir()
859
+ }) {
860
+ const servers = new Map;
861
+ const user = readJson(join(home, ".claude.json"));
862
+ if (isRecord3(user)) {
863
+ collect(servers, user.mcpServers);
864
+ if (isRecord3(user.projects)) {
865
+ const project = user.projects[cwd];
866
+ if (isRecord3(project))
867
+ collect(servers, project.mcpServers);
868
+ }
869
+ }
870
+ const shared = readJson(join(cwd, ".mcp.json"));
871
+ if (isRecord3(shared))
872
+ collect(servers, shared.mcpServers);
873
+ return servers;
874
+ }
875
+ function packageArg(args) {
876
+ const first = args.find((arg) => !arg.startsWith("-"));
877
+ if (first === undefined)
878
+ return null;
879
+ const at = first.lastIndexOf("@");
880
+ return at > 0 ? first.slice(0, at) : first;
881
+ }
882
+ var NPM_LAUNCHERS = new Set(["npx", "bunx", "pnpx"]);
883
+ var PYPI_LAUNCHERS = new Set(["uvx", "pipx"]);
884
+ var LOCALHOST = new Set(["localhost", "127.0.0.1", "::1", "[::1]"]);
885
+ var SECRET_SEGMENT = /^(?=[A-Za-z0-9_-]*[A-Za-z])(?=[A-Za-z0-9_-]*\d)[A-Za-z0-9_-]{24,}$/;
886
+ function credentialFree(url) {
887
+ const segments = url.pathname.split("/").filter((segment) => segment.length > 0);
888
+ const path = segments.some((segment) => SECRET_SEGMENT.test(segment)) ? "" : url.pathname;
889
+ const port = url.port === "" ? "" : `:${url.port}`;
890
+ return `${url.protocol}//${url.hostname}${port}${path}`;
891
+ }
892
+ function serverUrlOf(entry) {
893
+ if (entry === undefined)
894
+ return null;
895
+ if (entry.transport === "remote") {
896
+ try {
897
+ const url = new URL(entry.url);
898
+ if (url.protocol !== "https:" && url.protocol !== "http:")
899
+ return null;
900
+ return LOCALHOST.has(url.hostname) ? null : credentialFree(url);
901
+ } catch {
902
+ return null;
903
+ }
904
+ }
905
+ const launcher = entry.command.split(/[\\/]/).pop() ?? entry.command;
906
+ const args = launcher === "pipx" && entry.args[0] === "run" ? entry.args.slice(1) : entry.args;
907
+ const pkg = packageArg(args);
908
+ if (pkg === null || pkg.startsWith(".") || pkg.startsWith("/"))
909
+ return null;
910
+ if (NPM_LAUNCHERS.has(launcher))
911
+ return `https://www.npmjs.com/package/${pkg}`;
912
+ if (PYPI_LAUNCHERS.has(launcher))
913
+ return `https://pypi.org/project/${pkg}`;
914
+ return null;
915
+ }
916
+
917
+ // ../hook/src/capture.ts
918
+ import { mkdirSync, writeFileSync } from "node:fs";
919
+ import { join as join2 } from "node:path";
920
+ var TOP_LEVEL_NAMES = new Set([
921
+ "hook_event_name",
922
+ "hookEventName",
923
+ "tool_name",
924
+ "toolName",
925
+ "tool_use_id",
926
+ "toolUseId",
927
+ "session_id",
928
+ "sessionId",
929
+ "conversation_id",
930
+ "generation_id",
931
+ "turn_id",
932
+ "model",
933
+ "model_id",
934
+ "permission_mode",
935
+ "permissionMode",
936
+ "timestamp",
937
+ "mcp_server_name",
938
+ "original_request_name"
939
+ ]);
940
+ var URL_KEYS = new Set(["mcp_server_url", "server_url", "serverUrl", "url"]);
941
+ var IDENTIFIER = /^[A-Za-z_][A-Za-z0-9_]{0,39}$/;
942
+ var SECRET_SHAPED = /^(?=.*\d)(?=.*[A-Za-z]).{20,}$/;
943
+ function keyOf(key) {
944
+ return IDENTIFIER.test(key) && !SECRET_SHAPED.test(key) ? key : `<key:${key.length}>`;
945
+ }
946
+ function hostOnly(value) {
947
+ try {
948
+ const url = new URL(value);
949
+ return `${url.protocol}//${url.hostname}<rest:${value.length}>`;
950
+ } catch {
951
+ return `<string:${value.length}>`;
952
+ }
953
+ }
954
+ function deep(value) {
955
+ if (typeof value === "string")
956
+ return `<string:${value.length}>`;
957
+ if (typeof value === "number")
958
+ return "<number>";
959
+ if (Array.isArray(value))
960
+ return value.map(deep);
961
+ if (typeof value === "object" && value !== null) {
962
+ return Object.fromEntries(Object.entries(value).map(([key, item]) => [keyOf(key), deep(item)]));
963
+ }
964
+ return value;
965
+ }
966
+ function redact(payload) {
967
+ if (typeof payload !== "object" || payload === null || Array.isArray(payload)) {
968
+ return deep(payload);
969
+ }
970
+ return Object.fromEntries(Object.entries(payload).map(([key, value]) => {
971
+ if (typeof value === "string") {
972
+ if (URL_KEYS.has(key))
973
+ return [keyOf(key), hostOnly(value)];
974
+ return [keyOf(key), TOP_LEVEL_NAMES.has(key) ? value : `<string:${value.length}>`];
975
+ }
976
+ if (typeof value === "number" || typeof value === "boolean" || value === null) {
977
+ return [keyOf(key), value];
978
+ }
979
+ return [keyOf(key), deep(value)];
980
+ }));
981
+ }
982
+ function capture(payload, dir, now = new Date) {
983
+ try {
984
+ const record = redact(payload);
985
+ const event = typeof record === "object" && record !== null && !Array.isArray(record) ? Object.entries(record).find(([key]) => key === "hook_event_name" || key === "hookEventName")?.[1] : undefined;
986
+ const name = `${now.toISOString().replace(/[:.]/g, "-")}-${String(event ?? "event").replace(/[^A-Za-z]/g, "")}.json`;
987
+ mkdirSync(dir, { recursive: true });
988
+ writeFileSync(join2(dir, name), `${JSON.stringify(record, null, 2)}
989
+ `);
990
+ } catch {}
991
+ }
992
+
993
+ // ../hook/src/payload.ts
994
+ function isRecord4(value) {
995
+ return typeof value === "object" && value !== null && !Array.isArray(value);
996
+ }
997
+ function str(value) {
998
+ return typeof value === "string" && value.length > 0 ? value : null;
999
+ }
1000
+ function ms(value) {
1001
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? Math.round(value) : null;
1002
+ }
1003
+ function first(raw, keys) {
1004
+ for (const key of keys)
1005
+ if (key in raw)
1006
+ return raw[key];
1007
+ return;
1008
+ }
1009
+ function eventOf(raw) {
1010
+ if (!isRecord4(raw))
1011
+ return null;
1012
+ return str(first(raw, ["hook_event_name", "hookEventName"]));
1013
+ }
1014
+ function toolCallOf(raw) {
1015
+ if (!isRecord4(raw))
1016
+ return null;
1017
+ const format = typeof raw.toolName === "string" && typeof raw.tool_name !== "string" ? "grok" : "claude";
1018
+ const camel = format === "grok";
1019
+ const tool = str(camel ? raw.toolName : raw.tool_name);
1020
+ if (tool === null)
1021
+ return null;
1022
+ const input = camel ? raw.toolInput : raw.tool_input;
1023
+ const responseKeys = camel ? ["toolResult", "tool_response"] : ["tool_response"];
1024
+ const hasResponse = responseKeys.some((key) => (key in raw) && raw[key] !== undefined);
1025
+ return {
1026
+ format,
1027
+ event: str(camel ? first(raw, ["hookEventName", "hook_event_name"]) : raw.hook_event_name),
1028
+ session: str(camel ? raw.sessionId : raw.session_id),
1029
+ id: str(camel ? raw.toolUseId : raw.tool_use_id),
1030
+ tool,
1031
+ input: isRecord4(input) ? input : undefined,
1032
+ hasResponse,
1033
+ response: hasResponse ? first(raw, responseKeys) : undefined,
1034
+ error: str(raw.error),
1035
+ interrupted: (camel ? first(raw, ["isInterrupt", "is_interrupt"]) : raw.is_interrupt) === true,
1036
+ ms: ms(camel ? first(raw, ["durationMs", "duration_ms"]) : raw.duration_ms),
1037
+ cwd: str(raw.cwd),
1038
+ transcript: str(raw.transcript_path)
1039
+ };
1040
+ }
1041
+
1042
+ // ../../packages/protocol/src/content-path.ts
1043
+ function skillRefFromUrl3(url) {
1044
+ let parsed;
1045
+ try {
1046
+ parsed = new URL(url.includes("://") ? url : `https://${url}`);
1047
+ } catch {
1048
+ return null;
1049
+ }
1050
+ if (parsed.hostname.replace(/^www\./, "") !== "github.com")
1051
+ return null;
1052
+ const skill = parsed.searchParams.get("skill");
1053
+ if (skill === null || skill.length === 0)
1054
+ return null;
1055
+ const [owner, repo] = parsed.pathname.replace(/^\/+/, "").replace(/\/+$/, "").replace(/\.git$/, "").split("/");
1056
+ if (owner === undefined || repo === undefined)
1057
+ return null;
1058
+ if (owner.length === 0 || repo.length === 0)
1059
+ return null;
1060
+ return { repo: `${owner}/${repo}`, skill };
1061
+ }
1062
+ function directoryOf2(path) {
1063
+ const parts = path.split("/");
1064
+ return parts.length < 2 ? "" : parts[parts.length - 2] ?? "";
1065
+ }
1066
+ function skillFilesIn2(listing) {
1067
+ return listing.filter((file) => (file.path.split("/").pop() ?? "").toLowerCase() === "skill.md");
1068
+ }
1069
+
1070
+ // ../../packages/protocol/src/skill-requires.ts
1071
+ var LOGIN2 = /\b(auth login|log ?in|sign ?up|api[ _-]?key|access token)\b/i;
1072
+ function frontmatter2(markdown) {
1073
+ const lines = markdown.split(`
1074
+ `);
1075
+ if (lines[0]?.trim() !== "---")
1076
+ return { lines: [], bodyStart: 0 };
1077
+ const end = lines.findIndex((line, index) => index > 0 && line.trim() === "---");
1078
+ return end === -1 ? { lines: [], bodyStart: 0 } : { lines: lines.slice(1, end), bodyStart: end + 1 };
1079
+ }
1080
+ function unquote2(value) {
1081
+ return value.trim().replace(/^["']|["']$/g, "");
1082
+ }
1083
+ function declaredBins2(lines) {
1084
+ const at = lines.findIndex((line) => /^\s*bins\s*:/.test(line));
1085
+ if (at === -1)
1086
+ return [];
1087
+ const inline = lines[at]?.split(":").slice(1).join(":").trim() ?? "";
1088
+ if (inline.startsWith("[")) {
1089
+ return inline.replace(/^\[|\]$/g, "").split(",").map(unquote2).filter((name) => name.length > 0);
1090
+ }
1091
+ const out = [];
1092
+ for (const line of lines.slice(at + 1)) {
1093
+ const item = /^\s*-\s*(.+)$/.exec(line);
1094
+ if (item === null)
1095
+ break;
1096
+ out.push(unquote2(item[1] ?? ""));
1097
+ }
1098
+ return out.filter((name) => name.length > 0);
1099
+ }
1100
+ function bashTools2(lines) {
1101
+ const line = lines.find((candidate) => /^\s*allowed-tools\s*:/.test(candidate));
1102
+ if (line === undefined)
1103
+ return [];
1104
+ return [...line.matchAll(/Bash\(\s*([A-Za-z0-9._-]+)/g)].map((match) => match[1] ?? "").filter((name) => name.length > 0);
1105
+ }
1106
+ function declaredDescription2(lines) {
1107
+ const at = lines.findIndex((line) => /^description\s*:/.test(line));
1108
+ if (at === -1)
1109
+ return null;
1110
+ const inline = lines[at]?.split(":").slice(1).join(":").trim() ?? "";
1111
+ if (inline !== "" && !/^[>|][-+]?$/.test(inline))
1112
+ return unquote2(inline) || null;
1113
+ const block = [];
1114
+ for (const line of lines.slice(at + 1)) {
1115
+ if (!/^\s+\S/.test(line))
1116
+ break;
1117
+ block.push(line.trim());
1118
+ }
1119
+ return block.length === 0 ? null : block.join(" ");
1120
+ }
1121
+ var COMMON2 = new Set(("awk bash break bun case cat cd chmod command continue cp curl cut date diff do done echo else end env " + "esac exit export false fi find for function git grep head if kill ln local ls mkdir mv node npm npx open pip pip3 pnpm printf pwd " + "python python3 read return rm sed set sh shift sleep sort source sudo tail tar tee test then time " + "touch tr true uniq unset unzip wait wc wget which while xargs yarn zip").split(" "));
1122
+ var INSTALL2 = /\b(?:npm\s+(?:i|install)\s+(?:-g|--global)|pnpm\s+add\s+-g|yarn\s+global\s+add|brew\s+install|pipx\s+install|pip3?\s+install|cargo\s+install)\s+([@a-z0-9][@\w./-]*)/i;
1123
+ var PROBE2 = /\b(?:command\s+-v|which)\s+([a-z][\w-]*)/i;
1124
+ var COMMAND2 = /^[a-z][a-z0-9_-]*$/;
1125
+ function commandsIn2(shell, explicitOnly) {
1126
+ const found = [];
1127
+ for (const segment of shell.split(/&&|\|\||[|;]/)) {
1128
+ const line = segment.trim().replace(/^\$\s+/, "");
1129
+ if (line === "" || line.startsWith("#"))
1130
+ continue;
1131
+ const named = INSTALL2.exec(line)?.[1] ?? PROBE2.exec(line)?.[1];
1132
+ if (named !== undefined) {
1133
+ found.push(named);
1134
+ continue;
1135
+ }
1136
+ if (explicitOnly)
1137
+ continue;
1138
+ const words = line.split(/\s+/).filter((word) => !/^[A-Za-z_][A-Za-z0-9_]*=/.test(word));
1139
+ const first2 = words[0] === "sudo" ? words[1] : words[0];
1140
+ if (first2 === undefined || !COMMAND2.test(first2))
1141
+ continue;
1142
+ found.push(first2);
1143
+ }
1144
+ return found;
1145
+ }
1146
+ var SHELL_FENCE2 = /^(sh|bash|shell|zsh|console|terminal)$/i;
1147
+ function shellLinesRun2(lines) {
1148
+ const run = [];
1149
+ let heredocEnd = null;
1150
+ let quote = null;
1151
+ let continued = false;
1152
+ for (const line of lines) {
1153
+ if (heredocEnd !== null) {
1154
+ if (line.trim() === heredocEnd)
1155
+ heredocEnd = null;
1156
+ continue;
1157
+ }
1158
+ if (quote === null && !continued)
1159
+ run.push(line);
1160
+ continued = line.trimEnd().endsWith("\\");
1161
+ heredocEnd = /<<-?\s*['"]?([A-Za-z_]+)/.exec(line)?.[1] ?? null;
1162
+ for (const char of line) {
1163
+ if (quote === null && (char === '"' || char === "'"))
1164
+ quote = char;
1165
+ else if (char === quote)
1166
+ quote = null;
1167
+ }
1168
+ }
1169
+ return run;
1170
+ }
1171
+ function commandsRun2(body, declared) {
1172
+ const found = [];
1173
+ let fence = null;
1174
+ let fenced = [];
1175
+ for (const line of body) {
1176
+ const marker = /^\s*(?:```|~~~)\s*([\w-]*)/.exec(line);
1177
+ if (marker !== null) {
1178
+ if (fence === "shell") {
1179
+ for (const run of shellLinesRun2(fenced))
1180
+ found.push(...commandsIn2(run, false));
1181
+ }
1182
+ fenced = [];
1183
+ fence = fence !== null ? null : SHELL_FENCE2.test(marker[1] ?? "") ? "shell" : "other";
1184
+ continue;
1185
+ }
1186
+ if (fence !== null) {
1187
+ fenced.push(line);
1188
+ continue;
1189
+ }
1190
+ for (const inline of line.matchAll(/`([^`]+)`/g))
1191
+ found.push(...commandsIn2(inline[1] ?? "", true));
1192
+ }
1193
+ return [...new Set(found)].filter((name) => !COMMON2.has(name) && !declared.includes(name));
1194
+ }
1195
+ function requiresLine2(lines) {
1196
+ const name = lines.map((line) => /^\s*requires\s*:\s*(\S+)\s*$/.exec(line)?.[1]).find(Boolean);
1197
+ return name === undefined ? [] : [unquote2(name)];
1198
+ }
1199
+ function readRequires2(markdown) {
1200
+ const { lines, bodyStart } = frontmatter2(markdown);
1201
+ const cli = [...new Set([...declaredBins2(lines), ...bashTools2(lines), ...requiresLine2(lines)])];
1202
+ const description = declaredDescription2(lines);
1203
+ const body = markdown.split(`
1204
+ `);
1205
+ const runs = commandsRun2(body.slice(bodyStart), cli);
1206
+ for (let index = bodyStart;index < body.length; index += 1) {
1207
+ const text = body[index] ?? "";
1208
+ if (LOGIN2.test(text)) {
1209
+ return { cli, runs, login: { line: index + 1, text: text.trim().slice(0, 160) }, description };
1210
+ }
1211
+ }
1212
+ return { cli, runs, login: null, description };
1213
+ }
1214
+
1215
+ // ../../packages/protocol/src/skill-contents.ts
1216
+ var CONTENTS_LIMITS2 = {
1217
+ files: 200,
1218
+ fileChars: 512 * 1024,
1219
+ items: 40,
1220
+ lineChars: 160
1221
+ };
1222
+ var SCRIPT = /\.(sh|bash|zsh|py|js|mjs|cjs|ts|rb|pl|ps1|php|lua)$/i;
1223
+ var MARKDOWN = /\.(md|mdx|markdown)$/i;
1224
+ var FENCE = /^\s*(?:```|~~~)/;
1225
+ function cap(text) {
1226
+ const flat = text.replace(/\s+/g, " ").trim();
1227
+ return flat.length > CONTENTS_LIMITS2.lineChars ? `${flat.slice(0, CONTENTS_LIMITS2.lineChars - 1)}…` : flat;
1228
+ }
1229
+ function compare(a, b) {
1230
+ return a < b ? -1 : a > b ? 1 : 0;
1231
+ }
1232
+ var BASE_SHELLS = new Set(["sh", "bash", "zsh", "dash"]);
1233
+ function interpreterOf(firstLine) {
1234
+ const match = /^#!\s*(\S+)(?:\s+(?:-\S+\s+)*(\S+))?/.exec(firstLine);
1235
+ if (match === null)
1236
+ return null;
1237
+ const binary = match[1]?.split("/").pop() ?? "";
1238
+ const name = binary === "env" ? match[2] ?? "" : binary;
1239
+ return /^[a-z][\w.-]*$/i.test(name) && !BASE_SHELLS.has(name) ? name : null;
1240
+ }
1241
+ var SCRIPT_PROBE = /(?:^|[;&|(!{]|\bif|\bthen|\$\()\s*(?:!\s*)?(?:command\s+-v|which|type\s+-p|hash)\s+([a-z][\w.+-]*)/g;
1242
+ var SYSTEM_INSTALL = /\b(?:brew|apt-get|apt|dnf|yum|apk|pacman|choco|winget|scoop|port)\s+(?:install|add|-S)\s+(?:-\S+\s+)*([a-z][\w.+-]*)/g;
1243
+ var COMMENT_LINE = /^\s*(?:#|\/\/|\*|--|;|rem\s)/i;
1244
+ var PYTHON_PROBE = /\bshutil\.which\(\s*["']([a-z][\w.+-]*)["']/g;
1245
+ function programsInScriptLine(line, shell) {
1246
+ if (COMMENT_LINE.test(line))
1247
+ return [];
1248
+ const matches = shell ? [...line.matchAll(SCRIPT_PROBE), ...line.matchAll(SYSTEM_INSTALL)] : [...line.matchAll(PYTHON_PROBE)];
1249
+ return matches.map((match) => match[1] ?? "").filter((name) => name !== "");
1250
+ }
1251
+ var PACKAGE_INSTALL = /\b(pip3?|pipx|uv\s+pip|uv\s+add|poetry\s+add|npm|pnpm|yarn|bun|gem|cargo)\s+(?:install|add|i)\b([^\n|;&#`)]*)/gi;
1252
+ function packagesIn(line) {
1253
+ const out = [];
1254
+ for (const match of line.matchAll(PACKAGE_INSTALL)) {
1255
+ const manager = (match[1] ?? "").replace(/\s+/g, " ").toLowerCase();
1256
+ for (const raw of (match[2] ?? "").trim().split(/\s+/)) {
1257
+ const word = raw.replace(/^["']|["']$/g, "");
1258
+ if (word === "" || word.startsWith("-") || word.startsWith(".") || /[:\\<>{}$]/.test(word))
1259
+ continue;
1260
+ if (/\.(txt|toml|json|cfg|lock|whl|tgz|tar\.gz|zip)$/i.test(word))
1261
+ continue;
1262
+ const name = word.replace(/[=<>!~[].*$/, "");
1263
+ if (/^(@[a-z0-9][\w.-]*\/)?[a-z0-9][\w.-]*(@[\w.^~-]+)?$/i.test(name))
1264
+ out.push({ manager, name });
1265
+ }
1266
+ }
1267
+ return out;
1268
+ }
1269
+ function requirementsIn(text) {
1270
+ return text.split(`
1271
+ `).map((line) => line.replace(/#.*/, "").trim()).filter((line) => line !== "" && !line.startsWith("-") && !/^(https?|git\+)/.test(line)).map((line) => /^[A-Za-z0-9][\w.-]*/.exec(line)?.[0] ?? "").filter((name) => name !== "");
1272
+ }
1273
+ var SHELL_VARIABLES = new Set(("HOME PATH PWD OLDPWD USER LOGNAME SHELL TERM LANG LC_ALL TMPDIR TMP TEMP HOSTNAME IFS PS1 PS2 " + "RANDOM SECONDS LINENO BASH_SOURCE BASH_VERSION FUNCNAME PIPESTATUS OPTARG OPTIND EUID UID PPID " + "REPLY EDITOR VISUAL PAGER DISPLAY XDG_CONFIG_HOME XDG_DATA_HOME XDG_CACHE_HOME CI NODE_ENV DEBUG").split(" "));
1274
+ var READS_IN_CODE = [
1275
+ /\bprocess\.env\.([A-Z][A-Z0-9_]+)/g,
1276
+ /\bprocess\.env\[\s*["']([A-Z][A-Z0-9_]+)["']\s*\]/g,
1277
+ /\bBun\.env\.([A-Z][A-Z0-9_]+)/g,
1278
+ /\bDeno\.env\.get\(\s*["']([A-Z][A-Z0-9_]+)["']/g,
1279
+ /\bimport\.meta\.env\.([A-Z][A-Z0-9_]+)/g,
1280
+ /\bos\.environ\[\s*["']([A-Z][A-Z0-9_]+)["']\s*\]/g,
1281
+ /\b(?:os\.environ\.get|os\.getenv|getenv|environ\.get)\(\s*["']([A-Z][A-Z0-9_]+)["']/g,
1282
+ /\bENV(?:\.fetch\(|\[)\s*["']([A-Z][A-Z0-9_]+)["']/g,
1283
+ /\$env:([A-Za-z][A-Za-z0-9_]+)/g
1284
+ ];
1285
+ var SHELL_READ = /\$\{?([A-Z][A-Z0-9_]{2,})\b/g;
1286
+ var SHELL_ASSIGN = /^\s*(?:export\s+|local\s+|readonly\s+|declare\s+(?:-\w+\s+)?)?([A-Z][A-Z0-9_]*)=/;
1287
+ var SHELL_LOOP = /\b(?:for|read(?:\s+-\w+)*)\s+([A-Z][A-Z0-9_]*)\b/g;
1288
+ var EXPORT_IN_PROSE = /\bexport\s+([A-Z][A-Z0-9_]{2,})=/g;
1289
+ var KEY_NAMED = /\b([A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*_(?:API_KEY|APIKEY|KEY|TOKEN|SECRET|PASSWORD))\b/g;
1290
+ function shellReads(lines) {
1291
+ const assigned = new Set;
1292
+ for (const line of lines) {
1293
+ const name = SHELL_ASSIGN.exec(line)?.[1];
1294
+ if (name !== undefined)
1295
+ assigned.add(name);
1296
+ for (const loop of line.matchAll(SHELL_LOOP))
1297
+ assigned.add(loop[1] ?? "");
1298
+ }
1299
+ return lines.flatMap((line) => [...line.matchAll(SHELL_READ)].map((match) => match[1] ?? "")).filter((name) => !assigned.has(name));
1300
+ }
1301
+ function isShell(path, text) {
1302
+ return /\.(sh|bash|zsh)$/i.test(path) || /^#!\s*\S*\/(?:env\s+)?(?:ba|z|da)?sh\b/.test(text);
1303
+ }
1304
+ function settingsIn(path, text, code) {
1305
+ const found = new Set;
1306
+ for (const pattern of READS_IN_CODE) {
1307
+ for (const match of text.matchAll(pattern))
1308
+ found.add((match[1] ?? "").toUpperCase());
1309
+ }
1310
+ if (MARKDOWN.test(path)) {
1311
+ for (const match of text.matchAll(EXPORT_IN_PROSE))
1312
+ found.add(match[1] ?? "");
1313
+ for (const match of text.matchAll(KEY_NAMED))
1314
+ found.add(match[1] ?? "");
1315
+ } else if (isShell(path, text)) {
1316
+ for (const name of shellReads(code))
1317
+ found.add(name);
1318
+ }
1319
+ return [...found].filter((name) => name.length > 0 && !SHELL_VARIABLES.has(name));
1320
+ }
1321
+ function codeOf(path, text, isScript) {
1322
+ const lines = text.split(`
1323
+ `);
1324
+ if (isScript)
1325
+ return lines;
1326
+ if (!MARKDOWN.test(path))
1327
+ return [];
1328
+ const out = [];
1329
+ let fenced = false;
1330
+ for (const line of lines) {
1331
+ if (FENCE.test(line)) {
1332
+ fenced = !fenced;
1333
+ continue;
1334
+ }
1335
+ if (fenced)
1336
+ out.push(line);
1337
+ else
1338
+ for (const inline of line.matchAll(/`([^`]+)`/g))
1339
+ out.push(inline[1] ?? "");
1340
+ }
1341
+ return out;
1342
+ }
1343
+ var FETCH_AND_RUN = [
1344
+ {
1345
+ kind: "pipe to a shell",
1346
+ pattern: /\b(?:curl|wget|iwr|irm|Invoke-WebRequest|Invoke-RestMethod)\b[^|\n]*\|\s*(?:sudo\s+(?:-\S+\s+)*)?(?:sh|bash|zsh|dash|python3?|node|perl|ruby|iex|Invoke-Expression)\b/i
1347
+ },
1348
+ {
1349
+ kind: "runs a downloaded script",
1350
+ pattern: /\b(?:sh|bash|zsh|source)\s+<\(\s*(?:curl|wget)\b|\b(?:sh|bash|zsh)\s+-c\s+["']?\$\(\s*(?:curl|wget)\b|\b(?:iex|Invoke-Expression)\b[^\n]*\b(?:irm|iwr|Invoke-WebRequest|Invoke-RestMethod|DownloadString)\b|\bdeno\s+run\b[^\n]*\bhttps?:\/\//i
1351
+ },
1352
+ {
1353
+ kind: "installs from a URL",
1354
+ pattern: /\b(?:pip3?|pipx|uv\s+pip|npm|pnpm|yarn|bun|gem)\s+(?:install|add|i)\b[^\n|;&]*\s(?:https?:\/\/|git\+|github:)/i
1355
+ },
1356
+ {
1357
+ kind: "runs a package fetched at run time",
1358
+ pattern: /\bnpx\s+(?:-y|--yes)\b|\b(?:pnpm|yarn)\s+dlx\s+\S|\buvx\s+[a-z]|\bpipx\s+run\s+[a-z]/i
1359
+ }
1360
+ ];
1361
+ var URL_HOST = /\bhttps?:\/\/([a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+)/gi;
1362
+ var PLACEHOLDER_HOST = /(^|\.)(example\.(com|org|net)|localhost|local|test|invalid|example|internal)$|^(127\.\d+\.\d+\.\d+|0\.0\.0\.0)$|^(www\.)?(your|my)-?(domain|site|server|host|app|api|company|website)\./;
1363
+ var FILE_LIKE_HOST = /\.(jpe?g|png|gif|webp|svg|mp[34]|wav|mov|webm|pdf|md|json|txt|html?|js|ts|py|sh)$/;
1364
+ function domainsIn(text) {
1365
+ const out = [];
1366
+ for (const match of text.matchAll(URL_HOST)) {
1367
+ const host = (match[1] ?? "").toLowerCase();
1368
+ if (!/\.[a-z]{2,}$/.test(host) && !/^\d+\.\d+\.\d+\.\d+$/.test(host))
1369
+ continue;
1370
+ if (PLACEHOLDER_HOST.test(host) || FILE_LIKE_HOST.test(host))
1371
+ continue;
1372
+ out.push(host);
1373
+ }
1374
+ return out;
1375
+ }
1376
+ var INVISIBLE = /[​-‍⁠-⁤᠎‪-‮⁦-⁩]|\uDB40[\uDC00-\uDDEF]/g;
1377
+ var PICTOGRAPH = /\p{Extended_Pictographic}/u;
1378
+ function codePoint(point) {
1379
+ return `U+${point.toString(16).toUpperCase().padStart(4, "0")}`;
1380
+ }
1381
+ function invisibleIn(line, lineIndex) {
1382
+ const counts = new Map;
1383
+ const spelled = [];
1384
+ for (const match of line.matchAll(INVISIBLE)) {
1385
+ const char = match[0];
1386
+ const at = match.index;
1387
+ if (lineIndex === 0 && at === 0 && char === "\uFEFF")
1388
+ continue;
1389
+ if (char === "‍") {
1390
+ const before = [...line.slice(0, at)].at(-1) ?? "";
1391
+ const after = [...line.slice(at + 1)][0] ?? "";
1392
+ if (PICTOGRAPH.test(before) && PICTOGRAPH.test(after))
1393
+ continue;
1394
+ }
1395
+ const point = char.codePointAt(0) ?? 0;
1396
+ if (point >= 917536 && point <= 917630)
1397
+ spelled.push(String.fromCharCode(point - 917504));
1398
+ const name = point >= 917504 && point <= 917631 ? "Unicode tag" : codePoint(point);
1399
+ counts.set(name, (counts.get(name) ?? 0) + 1);
1400
+ }
1401
+ if (counts.size === 0)
1402
+ return null;
1403
+ const listed = [...counts.entries()].map(([name, n]) => `${n} × ${name}`).join(", ");
1404
+ return spelled.length === 0 ? listed : `${listed}, spelling "${cap(spelled.join(""))}"`;
1405
+ }
1406
+ var BASE64_RUN = /[A-Za-z0-9+/]{100,}={0,2}/g;
1407
+ var DATA_URI = /data:([\w.+-]+\/[\w.+-]+)?(?:;[\w=-]+)*;base64,([A-Za-z0-9+/]{100,}={0,2})/g;
1408
+ var URL_TEXT = /\bhttps?:\/\/\S+/g;
1409
+ function encodedIn(line) {
1410
+ const out = [];
1411
+ const withoutUris = line.replace(DATA_URI, (_whole, type, body) => {
1412
+ out.push(`data URI${type === undefined ? "" : ` ${type}`}, ${body.length} characters of base64`);
1413
+ return " ";
1414
+ });
1415
+ for (const match of withoutUris.replace(URL_TEXT, " ").matchAll(BASE64_RUN)) {
1416
+ const run = match[0];
1417
+ if (/[A-Z]/.test(run) && /[a-z]/.test(run) && /[0-9]/.test(run))
1418
+ out.push(`${run.length} characters of base64`);
1419
+ }
1420
+ return out;
1421
+ }
1422
+ var IGNORE_INSTRUCTIONS = /\b(?:ignore|disregard|forget|override)\b[^.\n]{0,40}?\b(?:previous|prior|above|earlier|preceding|all|any|other|system|your)\b[^.\n]{0,25}?\b(?:instructions?|prompts?|rules|guidelines|directions)\b/i;
1423
+ var KEEP_FROM_PERSON = /\b(?:do not|don't|never)\s+(?:tell|inform|notify|alert|(?:mention|reveal)(?:\s+(?:this|it))?\s+to)\s+(?:the\s+)?(?:user|human|person|operator)\b|\bwithout\s+(?:telling|informing|notifying|alerting)\s+(?:the\s+)?(?:user|human|person|operator)\b/i;
1424
+ function unquoted(line) {
1425
+ return line.replace(/"[^"]*"|\u201C[^\u201D]*\u201D|\u300C[^\u300D]*\u300D|`[^`]*`/g, " ");
1426
+ }
1427
+ var COMMENT_WORDS = 4;
1428
+ function hiddenInMarkdown(path, text) {
1429
+ const out = [];
1430
+ const push = (kind, line, value) => out.push({ kind, file: path, line, text: value });
1431
+ let fenced = false;
1432
+ let comment = null;
1433
+ for (const [index, line] of text.split(`
1434
+ `).entries()) {
1435
+ const invisible = invisibleIn(line, index);
1436
+ if (invisible !== null)
1437
+ push("hidden characters", index + 1, invisible);
1438
+ for (const encoded of encodedIn(line))
1439
+ push("encoded block", index + 1, encoded);
1440
+ const visible = line.replace(INVISIBLE, "");
1441
+ if (IGNORE_INSTRUCTIONS.test(unquoted(visible)))
1442
+ push("says to ignore instructions", index + 1, cap(visible));
1443
+ if (KEEP_FROM_PERSON.test(unquoted(visible)))
1444
+ push("says not to tell the person", index + 1, cap(visible));
1445
+ if (comment === null && FENCE.test(line)) {
1446
+ fenced = !fenced;
1447
+ continue;
1448
+ }
1449
+ if (fenced)
1450
+ continue;
1451
+ let rest = visible;
1452
+ while (rest.length > 0) {
1453
+ if (comment === null) {
1454
+ const open = rest.indexOf("<!--");
1455
+ if (open === -1)
1456
+ break;
1457
+ comment = { start: index + 1, text: [] };
1458
+ rest = rest.slice(open + 4);
1459
+ }
1460
+ const close = rest.indexOf("-->");
1461
+ if (close === -1) {
1462
+ comment.text.push(rest);
1463
+ break;
1464
+ }
1465
+ comment.text.push(rest.slice(0, close));
1466
+ const inner = comment.text.join(" ").replace(/\s+/g, " ").trim();
1467
+ if (inner.split(" ").filter((word) => /[\p{L}\p{N}]/u.test(word)).length >= COMMENT_WORDS) {
1468
+ push("HTML comment", comment.start, cap(inner));
1469
+ }
1470
+ comment = null;
1471
+ rest = rest.slice(close + 3);
1472
+ }
1473
+ }
1474
+ if (comment !== null)
1475
+ push("HTML comment", comment.start, cap(`(never closed) ${comment.text.join(" ")}`));
1476
+ return out;
1477
+ }
1478
+ function bounded(name, items, cut) {
1479
+ if (items.length <= CONTENTS_LIMITS2.items)
1480
+ return [...items];
1481
+ cut.push(name);
1482
+ return items.slice(0, CONTENTS_LIMITS2.items);
1483
+ }
1484
+ function escapeRegExp(text) {
1485
+ return text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
1486
+ }
1487
+ function namesFile(markdown, path) {
1488
+ const base = path.slice(path.lastIndexOf("/") + 1);
1489
+ return markdown.includes(path) || new RegExp(`(^|[\\s/\`'"(])${escapeRegExp(base)}($|[\\s\`'")]|[.,:;](\\s|$))`, "m").test(markdown);
1490
+ }
1491
+ function readSkillContents2(input) {
1492
+ const sorted = [...input].sort((a, b) => compare(a.path, b.path));
1493
+ const skipped = [];
1494
+ const files = [];
1495
+ for (const file of sorted) {
1496
+ if (files.length >= CONTENTS_LIMITS2.files)
1497
+ skipped.push({ path: file.path, why: "over the file limit" });
1498
+ else if (file.text === null)
1499
+ skipped.push({ path: file.path, why: file.notFetched === true ? "not fetched" : "binary" });
1500
+ else if (file.text.length > CONTENTS_LIMITS2.fileChars)
1501
+ skipped.push({ path: file.path, why: "too large" });
1502
+ else
1503
+ files.push({ path: file.path, text: file.text.replace(/\r\n?/g, `
1504
+ `) });
1505
+ }
1506
+ const skillMd = files.find((file) => file.path === "SKILL.md")?.text ?? "";
1507
+ const programs = new Map;
1508
+ const add = (name, from) => {
1509
+ if (!programs.has(name))
1510
+ programs.set(name, from);
1511
+ };
1512
+ const requires = readRequires2(skillMd);
1513
+ for (const name of requires.cli)
1514
+ add(name, "declared");
1515
+ for (const name of requires.runs)
1516
+ add(name, "runs");
1517
+ const packages = new Map;
1518
+ const settings = new Set;
1519
+ const domains = new Set;
1520
+ const fetchAndRun = [];
1521
+ const hidden = [];
1522
+ const scripts = skipped.filter((file) => file.why === "not fetched" && SCRIPT.test(file.path)).map((file) => ({ path: file.path, namedInSkillMd: namesFile(skillMd, file.path) }));
1523
+ for (const file of files) {
1524
+ const lines = file.text.split(`
1525
+ `);
1526
+ const isScript = SCRIPT.test(file.path) || lines[0]?.startsWith("#!") === true;
1527
+ const code = codeOf(file.path, file.text, isScript);
1528
+ const shell = isShell(file.path, file.text);
1529
+ for (const line of code) {
1530
+ const installed = packagesIn(line);
1531
+ for (const pkg of installed)
1532
+ packages.set(`${pkg.manager} ${pkg.name}`, pkg);
1533
+ if (!isScript)
1534
+ continue;
1535
+ for (const name of programsInScriptLine(line, shell)) {
1536
+ if (!installed.some((pkg) => pkg.name === name))
1537
+ add(name, "script");
1538
+ }
1539
+ }
1540
+ if (isScript) {
1541
+ scripts.push({ path: file.path, namedInSkillMd: namesFile(skillMd, file.path) });
1542
+ const interpreter = interpreterOf(lines[0] ?? "");
1543
+ if (interpreter !== null)
1544
+ add(interpreter, "interpreter");
1545
+ }
1546
+ if (/(^|\/)requirements[\w.-]*\.txt$/i.test(file.path)) {
1547
+ for (const name of requirementsIn(file.text))
1548
+ packages.set(`pip ${name}`, { manager: "pip", name });
1549
+ }
1550
+ for (const setting of settingsIn(file.path, file.text, code))
1551
+ settings.add(setting);
1552
+ for (const host of domainsIn(file.text))
1553
+ domains.add(host);
1554
+ for (const [index, line] of lines.entries()) {
1555
+ const run = FETCH_AND_RUN.find(({ pattern }) => pattern.test(line));
1556
+ if (run !== undefined)
1557
+ fetchAndRun.push({ kind: run.kind, file: file.path, line: index + 1, text: cap(line) });
1558
+ }
1559
+ if (MARKDOWN.test(file.path))
1560
+ hidden.push(...hiddenInMarkdown(file.path, file.text));
1561
+ }
1562
+ const packageNames = new Set([...packages.values()].map((pkg) => pkg.name));
1563
+ for (const [name, from] of programs)
1564
+ if (from !== "declared" && packageNames.has(name))
1565
+ programs.delete(name);
1566
+ const cut = [];
1567
+ return {
1568
+ programs: bounded("programs", [...programs.entries()].map(([name, from]) => ({ name, from })).sort((a, b) => compare(a.name, b.name)), cut),
1569
+ packages: bounded("packages", [...packages.values()].sort((a, b) => compare(`${a.manager} ${a.name}`, `${b.manager} ${b.name}`)), cut),
1570
+ settings: bounded("settings", [...settings].sort(compare), cut),
1571
+ scripts: bounded("scripts", scripts.sort((a, b) => compare(a.path, b.path)), cut),
1572
+ fetchAndRun: bounded("fetchAndRun", fetchAndRun, cut),
1573
+ domains: bounded("domains", [...domains].sort(compare), cut),
1574
+ hidden: bounded("hidden", hidden, cut),
1575
+ read: {
1576
+ files: files.length,
1577
+ bytes: files.reduce((sum, file) => sum + new TextEncoder().encode(file.text).byteLength, 0),
1578
+ skipped
1579
+ },
1580
+ cut
1581
+ };
1582
+ }
1583
+ function contentsLines2(contents, perList = 6) {
1584
+ const list = (items, cut) => items.length === 0 ? "none found" : `${items.slice(0, perList).join(", ")}${items.length > perList || cut ? `, and ${Math.max(0, items.length - perList)}${cut ? "+" : ""} more` : ""}`;
1585
+ const at = (rows, name) => list(rows.map((row) => `${row.kind} at ${row.file}:${row.line} "${row.text}"`), contents.cut.includes(name));
1586
+ return [
1587
+ `Programs: ${list(contents.programs.map((p) => `${p.name} (${p.from})`), contents.cut.includes("programs"))}`,
1588
+ ...contents.packages.length === 0 ? [] : [`Packages: ${list(contents.packages.map((p) => `${p.manager} ${p.name}`), contents.cut.includes("packages"))}`],
1589
+ `Keys and settings it reads: ${list(contents.settings, contents.cut.includes("settings"))}`,
1590
+ `Scripts: ${list(contents.scripts.map((s) => s.namedInSkillMd ? `${s.path} (named in SKILL.md)` : s.path), contents.cut.includes("scripts"))}`,
1591
+ `Fetches and runs code: ${at(contents.fetchAndRun, "fetchAndRun")}`,
1592
+ `Domains named: ${list(contents.domains, contents.cut.includes("domains"))}`,
1593
+ `Hidden or encoded text: ${at(contents.hidden, "hidden")}`,
1594
+ ...contents.read.skipped.length === 0 ? [] : [`Not read: ${list(contents.read.skipped.map((s) => `${s.path} (${s.why})`), false)}`]
1595
+ ];
1596
+ }
1597
+
1598
+ // ../../packages/protocol/src/pulse.ts
1599
+ var MAX_SKILL_FILES_READ2 = 200;
1600
+ var MAX_SCRIPTS_READ = 5;
1601
+ var GITHUB_READ_TIMEOUT_MS = 1e4;
1602
+ var INSTALLER_ORDER = [
1603
+ "",
1604
+ "skills/",
1605
+ "skills/.curated/",
1606
+ "skills/.experimental/",
1607
+ "skills/.system/",
1608
+ ".agents/skills/",
1609
+ ".claude/skills/",
1610
+ ".cline/skills/",
1611
+ ".codebuddy/skills/",
1612
+ ".codex/skills/",
1613
+ ".commandcode/skills/",
1614
+ ".continue/skills/",
1615
+ ".factory/skills/",
1616
+ ".github/skills/",
1617
+ ".goose/skills/",
1618
+ ".grok/skills/",
1619
+ ".iflow/skills/",
1620
+ ".junie/skills/",
1621
+ ".kilo/skills/",
1622
+ ".kilocode/skills/",
1623
+ ".kimchi/skills/",
1624
+ ".kiro/skills/",
1625
+ ".minimax/skills/",
1626
+ ".mux/skills/",
1627
+ ".neovate/skills/",
1628
+ ".opencode/skills/",
1629
+ ".openhands/skills/",
1630
+ ".pi/skills/",
1631
+ ".posit/assistant/skills/",
1632
+ ".qoder/skills/",
1633
+ ".roo/skills/",
1634
+ ".trae/skills/",
1635
+ ".windsurf/skills/",
1636
+ ".zcode/skills/",
1637
+ ".zencoder/skills/"
1638
+ ];
1639
+ function installerRank(path) {
1640
+ let best = null;
1641
+ INSTALLER_ORDER.forEach((prefix, rank) => {
1642
+ if (best !== null || !path.startsWith(prefix))
1643
+ return;
1644
+ const depth = path.slice(prefix.length).split("/").length;
1645
+ if (prefix === "" ? depth <= 2 : depth <= 4)
1646
+ best = rank;
1647
+ });
1648
+ return best;
1649
+ }
1650
+ function normaliseName(name) {
1651
+ return name.trim().toLowerCase().replace(/[\s_]+/g, "-");
1652
+ }
1653
+ function frontmatterName2(markdown) {
1654
+ const lines = markdown.split(`
1655
+ `);
1656
+ if (lines[0]?.trim() !== "---")
1657
+ return null;
1658
+ for (const line of lines.slice(1)) {
1659
+ if (line.trim() === "---")
1660
+ return null;
1661
+ const match = /^name\s*:\s*(.+?)\s*$/.exec(line);
1662
+ if (match !== null)
1663
+ return (match[1] ?? "").replace(/^["']|["']$/g, "");
1664
+ }
1665
+ return null;
1666
+ }
1667
+ var KEY_NAME3 = /\b[A-Z][A-Z0-9_]*(?:API_KEY|APIKEY|_TOKEN|_SECRET)\b/g;
1668
+ var PAID_WORD = /\b(pricing|paid|subscription|credits?|billing|free tier|per minute)\b/gi;
1669
+ var HOST = /https?:\/\/([a-zA-Z0-9.-]+\.[a-zA-Z]{2,})/g;
1670
+ var NOT_A_SERVICE = /(^|\.)(github\.com|githubusercontent\.com|example\.(com|org|net))$/;
1671
+ var LOOKS_LIKE_A_FILE = /\.(jpe?g|png|gif|webp|mp[34]|wav|mov|webm|pdf|md|json|txt)$/;
1672
+ var SCRIPT2 = /\.(sh|bash|py|js|mjs|cjs|ts|rb|pl)$/i;
1673
+ var RUNS_FILE = /\b(?:node|bun|deno|tsx|python3?|bash|sh)\s+((?:~|\.{1,2})?\/?[\w.@-]+(?:\/[\w.@-]+)*\.(?:mjs|cjs|js|ts|py|sh))\b/g;
1674
+ var PLACEHOLDER = /(^|\/)(path|your|my|foo|example|script|file|input|output)(\/|\.|$)/i;
1675
+ function filesItRuns(markdown, repositoryFiles) {
1676
+ const named = [...markdown.matchAll(RUNS_FILE)].map((match) => match[1] ?? "");
1677
+ const found = new Set;
1678
+ for (const name of named) {
1679
+ if (name.startsWith("/") || name.startsWith("~") || PLACEHOLDER.test(name))
1680
+ continue;
1681
+ const tail = name.replace(/^(\.{1,2}\/)+/, "");
1682
+ const hit = repositoryFiles.find((file) => file.path === tail || file.path.endsWith(`/${tail}`));
1683
+ if (hit !== undefined)
1684
+ found.add(hit.path);
1685
+ }
1686
+ return [...found];
1687
+ }
1688
+ function absentFiles(markdown, repositoryFiles) {
1689
+ const named = [...markdown.matchAll(RUNS_FILE)].map((match) => match[1] ?? "");
1690
+ return [...new Set(named)].filter((name) => {
1691
+ if (name.startsWith("/") || name.startsWith("~") || PLACEHOLDER.test(name))
1692
+ return false;
1693
+ const tail = name.replace(/^(\.{1,2}\/)+/, "");
1694
+ return !repositoryFiles.some((file) => file.path === tail || file.path.endsWith(`/${tail}`));
1695
+ });
1696
+ }
1697
+ function readSkillFacts2(markdown, filesInDirectory, repositoryFiles = filesInDirectory) {
1698
+ const hosts = [...markdown.matchAll(HOST)].map((match) => (match[1] ?? "").toLowerCase()).filter((host) => !NOT_A_SERVICE.test(host) && !LOOKS_LIKE_A_FILE.test(host));
1699
+ return {
1700
+ files: filesInDirectory.length,
1701
+ bytes: filesInDirectory.reduce((total, file) => total + file.size, 0),
1702
+ scripts: filesInDirectory.filter((file) => SCRIPT2.test(file.path)).length,
1703
+ keys: [...new Set(markdown.match(KEY_NAME3) ?? [])],
1704
+ paidWords: [...new Set((markdown.match(PAID_WORD) ?? []).map((word) => word.toLowerCase()))],
1705
+ hosts: [...new Set(hosts)],
1706
+ runsAbsentFiles: absentFiles(markdown, repositoryFiles),
1707
+ keysInScriptsItRuns: [],
1708
+ requires: readRequires2(markdown),
1709
+ contains: readSkillContents2([{ path: "SKILL.md", text: markdown }])
1710
+ };
1711
+ }
1712
+ function parentOf(path) {
1713
+ const at = path.lastIndexOf("/");
1714
+ return at === -1 ? "" : path.slice(0, at);
1715
+ }
1716
+ async function locate(source, repo, skill, listing) {
1717
+ const wanted = normaliseName(skill);
1718
+ const candidates = listing.files.filter((file) => skillFilesIn2([file]).length === 1);
1719
+ const guessed = candidates.filter((file) => normaliseName(directoryOf2(file.path)) === wanted);
1720
+ const others = candidates.filter((file) => !guessed.includes(file));
1721
+ const read = async (files) => (await Promise.all(files.map(async (file) => ({ file, markdown: await source.file(repo, file.path) })))).filter((entry) => entry.markdown !== null && normaliseName(frontmatterName2(entry.markdown) ?? "") === wanted);
1722
+ let named = await read(guessed);
1723
+ if (named.length === 0) {
1724
+ if (others.length > MAX_SKILL_FILES_READ2) {
1725
+ return { status: "incomplete", reason: "too_many_skill_files" };
1726
+ }
1727
+ for (let at = 0;at < others.length && named.length === 0; at += 20) {
1728
+ named = await read(others.slice(at, at + 20));
1729
+ }
1730
+ if (named.length > 0) {
1731
+ const last = others.findIndex((file) => file === named.at(-1)?.file);
1732
+ named = [...named, ...await read(others.slice(last + 1))];
1733
+ }
1734
+ }
1735
+ if (named.length === 0) {
1736
+ if (listing.truncated)
1737
+ return { status: "incomplete", reason: "truncated_listing" };
1738
+ return { status: "absent", skillFiles: candidates.length };
1739
+ }
1740
+ const ranked = named.map((entry) => ({ ...entry, rank: installerRank(entry.file.path) })).sort((a, b) => (a.rank ?? Infinity) - (b.rank ?? Infinity));
1741
+ const [first2, ...rest] = ranked;
1742
+ if (first2 === undefined)
1743
+ return { status: "absent", skillFiles: candidates.length };
1744
+ const differs = rest.filter((entry) => entry.file.sha !== first2.file.sha);
1745
+ if (first2.rank === null && differs.length > 0) {
1746
+ return { status: "ambiguous", paths: ranked.map((entry) => entry.file.path) };
1747
+ }
1748
+ return {
1749
+ status: "found",
1750
+ file: first2.file,
1751
+ markdown: first2.markdown,
1752
+ alsoAt: rest.filter((entry) => entry.file.sha === first2.file.sha).map((entry) => entry.file.path),
1753
+ differsAt: differs.map((entry) => entry.file.path)
1754
+ };
1755
+ }
1756
+ function usualPaths(skill) {
1757
+ return [`skills/${skill}/SKILL.md`, `${skill}/SKILL.md`, `.claude/skills/${skill}/SKILL.md`, "SKILL.md"];
1758
+ }
1759
+ async function readFileOnly(result, source) {
1760
+ if (!/^[\w.-]+$/.test(result.skill) || /^\.+$/.test(result.skill))
1761
+ return null;
1762
+ const wanted = normaliseName(result.skill);
1763
+ for (const path of usualPaths(result.skill)) {
1764
+ const markdown = await source.file(result.source, path);
1765
+ if (markdown === null || normaliseName(frontmatterName2(markdown) ?? "") !== wanted)
1766
+ continue;
1767
+ const { keys, paidWords, hosts, requires, contains } = readSkillFacts2(markdown, []);
1768
+ return { ...result, status: "read_file_only", path, keys, paidWords, hosts, requires, contains };
1769
+ }
1770
+ return null;
1771
+ }
1772
+ async function readPulse2(result, source) {
1773
+ if (!/^(?!\.{1,2}\/)[\w.-]+\/(?!\.{1,2}$)[\w.-]+$/.test(result.source))
1774
+ return { ...result, status: "not_github" };
1775
+ const listing = await source.listing(result.source);
1776
+ if (listing === "rate_limited")
1777
+ return await readFileOnly(result, source) ?? { ...result, status: "rate_limited" };
1778
+ if (listing === "unreachable")
1779
+ return { ...result, status: "repository_unreachable" };
1780
+ const located = await locate(source, result.source, result.skill, listing);
1781
+ if (located.status === "absent")
1782
+ return { ...result, status: "absent", skillFiles: located.skillFiles };
1783
+ if (located.status === "ambiguous")
1784
+ return { ...result, status: "ambiguous", paths: located.paths };
1785
+ if (located.status === "incomplete")
1786
+ return { ...result, status: "incomplete", reason: located.reason };
1787
+ const directory = parentOf(located.file.path);
1788
+ const prefix = directory === "" ? "" : `${directory}/`;
1789
+ const inDirectory = listing.files.filter((file) => file.path.startsWith(prefix));
1790
+ const scripts = filesItRuns(located.markdown, listing.files).slice(0, MAX_SCRIPTS_READ);
1791
+ const scriptTexts = await Promise.all(scripts.map(async (file) => ({ file, text: await source.file(result.source, file) })));
1792
+ const keysInScriptsItRuns = scriptTexts.map(({ file, text }) => ({ file, keys: [...new Set(text?.match(KEY_NAME3) ?? [])] })).filter((entry) => entry.keys.length > 0);
1793
+ const relative = (path) => path.startsWith(prefix) ? path.slice(prefix.length) : path;
1794
+ const fetched = new Set(scriptTexts.filter((entry) => entry.text !== null).map((entry) => entry.file));
1795
+ const contains = readSkillContents2([
1796
+ { path: "SKILL.md", text: located.markdown },
1797
+ ...scriptTexts.flatMap(({ file, text }) => text === null ? [] : [{ path: relative(file), text }]),
1798
+ ...inDirectory.filter((file) => SCRIPT2.test(file.path) && !fetched.has(file.path)).map((file) => ({ path: relative(file.path), text: null, notFetched: true }))
1799
+ ]);
1800
+ return {
1801
+ ...result,
1802
+ status: "read",
1803
+ path: located.file.path,
1804
+ alsoAt: located.alsoAt,
1805
+ differsAt: located.differsAt,
1806
+ contentId: directory === "" ? listing.rootTreeId : listing.trees.get(directory) ?? located.file.sha,
1807
+ skillMdSha: located.file.sha,
1808
+ repository: await source.repository(result.source),
1809
+ ...listing.readAt === undefined ? {} : { listingReadAt: listing.readAt },
1810
+ ...readSkillFacts2(located.markdown, inDirectory, listing.files),
1811
+ keysInScriptsItRuns,
1812
+ contains
1813
+ };
1814
+ }
1815
+ function githubPulseSource2(options = {}) {
1816
+ const get = options.fetch ?? fetch;
1817
+ const timeoutMs = options.timeoutMs ?? GITHUB_READ_TIMEOUT_MS;
1818
+ const bounded2 = () => {
1819
+ const limit = AbortSignal.timeout(timeoutMs);
1820
+ return options.signal === undefined ? limit : AbortSignal.any([limit, options.signal]);
1821
+ };
1822
+ const headers = {
1823
+ accept: "application/vnd.github+json",
1824
+ "user-agent": "arp-pulse",
1825
+ ...options.token === undefined ? {} : { authorization: `Bearer ${options.token}` }
1826
+ };
1827
+ const listings = new Map;
1828
+ const repositories = new Map;
1829
+ const quota = { apiRequests: 0, limited: false, resetsAt: null };
1830
+ const noteLimit = (response) => {
1831
+ const hit = response.status === 429 || response.status === 403 && (response.headers.get("x-ratelimit-remaining") === "0" || response.headers.has("retry-after"));
1832
+ if (!hit)
1833
+ return false;
1834
+ quota.limited = true;
1835
+ const reset = Number(response.headers.get("x-ratelimit-reset"));
1836
+ if (Number.isFinite(reset) && reset > 0)
1837
+ quota.resetsAt = new Date(reset * 1000).toISOString();
1838
+ return true;
1839
+ };
1840
+ const readListing = async (repo) => {
1841
+ const cached = await options.cache?.get(repo).catch(() => null);
1842
+ if (cached !== null && cached !== undefined)
1843
+ return cached;
1844
+ if (quota.limited)
1845
+ return "rate_limited";
1846
+ quota.apiRequests += 1;
1847
+ const response = await get(`https://api.github.com/repos/${repo}/git/trees/HEAD?recursive=1`, { headers, signal: bounded2() });
1848
+ if (noteLimit(response))
1849
+ return "rate_limited";
1850
+ if (!response.ok)
1851
+ return "unreachable";
1852
+ const body = await response.json();
1853
+ const files = [];
1854
+ const trees = new Map;
1855
+ for (const entry of body.tree ?? []) {
1856
+ if (typeof entry.path !== "string" || typeof entry.sha !== "string")
1857
+ continue;
1858
+ if (entry.type === "tree")
1859
+ trees.set(entry.path, entry.sha);
1860
+ if (entry.type === "blob") {
1861
+ files.push({ path: entry.path, sha: entry.sha, size: typeof entry.size === "number" ? entry.size : 0 });
1862
+ }
1863
+ }
1864
+ const listing = {
1865
+ rootTreeId: typeof body.sha === "string" ? body.sha : "",
1866
+ files,
1867
+ trees,
1868
+ truncated: body.truncated === true
1869
+ };
1870
+ await options.cache?.set(repo, listing).catch(() => {
1871
+ return;
1872
+ });
1873
+ return listing;
1874
+ };
1875
+ const readRepository = async (repo) => {
1876
+ if (options.withRepository === false || quota.limited)
1877
+ return null;
1878
+ quota.apiRequests += 1;
1879
+ const response = await get(`https://api.github.com/repos/${repo}`, { headers, signal: bounded2() });
1880
+ noteLimit(response);
1881
+ if (!response.ok)
1882
+ return null;
1883
+ const body = await response.json();
1884
+ return {
1885
+ stars: typeof body.stargazers_count === "number" ? body.stargazers_count : 0,
1886
+ pushedAt: typeof body.pushed_at === "string" ? body.pushed_at : null,
1887
+ archived: body.archived === true
1888
+ };
1889
+ };
1890
+ const once = (cache, repo, read) => {
1891
+ const hit = cache.get(repo);
1892
+ if (hit !== undefined)
1893
+ return hit;
1894
+ const started = read(repo);
1895
+ cache.set(repo, started);
1896
+ return started;
1897
+ };
1898
+ return {
1899
+ listing: (repo) => once(listings, repo, readListing),
1900
+ repository: (repo) => once(repositories, repo, readRepository),
1901
+ file: async (repo, path) => {
1902
+ const encoded = path.split("/").map(encodeURIComponent).join("/");
1903
+ const response = await get(`https://raw.githubusercontent.com/${repo}/HEAD/${encoded}`, { signal: bounded2() });
1904
+ return response.ok ? response.text() : null;
1905
+ },
1906
+ quota: () => ({ ...quota })
1907
+ };
1908
+ }
1909
+
1910
+ // ../../packages/protocol/src/skill-install.ts
1911
+ var MAX_SKILLS_READ2 = 3;
1912
+ var ADD = new Set(["add", "a", "install", "i"]);
1913
+ var RUNNERS = new Set(["npx", "pnpx", "bunx"]);
1914
+ var DLX = { pnpm: ["dlx"], yarn: ["dlx"], npm: ["exec", "x"] };
1915
+ var SKILLS = /^skills(@[\w.^~<>=*-]+)?$/;
1916
+ var ENV_ASSIGNMENT = /^[A-Za-z_][A-Za-z0-9_]*=/;
1917
+ function shellWords(command) {
1918
+ const commands = [[]];
1919
+ let word = null;
1920
+ let quote = null;
1921
+ const end = () => {
1922
+ if (word !== null)
1923
+ commands[commands.length - 1]?.push(word);
1924
+ word = null;
1925
+ };
1926
+ for (let at = 0;at < command.length; at += 1) {
1927
+ const char = command[at] ?? "";
1928
+ if (quote !== null) {
1929
+ if (char === quote)
1930
+ quote = null;
1931
+ else if (char === "\\" && quote === '"' && at + 1 < command.length)
1932
+ word = (word ?? "") + command[at += 1];
1933
+ else
1934
+ word = (word ?? "") + char;
1935
+ } else if (char === "'" || char === '"') {
1936
+ quote = char;
1937
+ word ??= "";
1938
+ } else if (char === "\\" && at + 1 < command.length) {
1939
+ word = (word ?? "") + command[at += 1];
1940
+ } else if (/\s/.test(char) && char !== `
1941
+ `) {
1942
+ end();
1943
+ } else if (char === `
1944
+ ` || char === ";" || char === "&" || char === "|") {
1945
+ end();
1946
+ commands.push([]);
1947
+ } else {
1948
+ word = (word ?? "") + char;
1949
+ }
1950
+ }
1951
+ end();
1952
+ return commands.filter((words) => words.length > 0);
1953
+ }
1954
+ function addArguments(words) {
1955
+ let at = 0;
1956
+ while (at < words.length && ENV_ASSIGNMENT.test(words[at] ?? ""))
1957
+ at += 1;
1958
+ const first2 = words[at];
1959
+ if (first2 !== undefined && RUNNERS.has(first2))
1960
+ at += 1;
1961
+ else if (first2 !== undefined && DLX[first2]?.includes(words[at + 1] ?? "") === true)
1962
+ at += 2;
1963
+ while (at < words.length && (words[at] ?? "").startsWith("-"))
1964
+ at += 1;
1965
+ if (!SKILLS.test(words[at] ?? ""))
1966
+ return null;
1967
+ const subcommand = words[at + 1];
1968
+ return subcommand !== undefined && ADD.has(subcommand) ? words.slice(at + 2) : null;
1969
+ }
1970
+ function parseAdd(args) {
1971
+ const skills = [];
1972
+ let source = null;
1973
+ let all = false;
1974
+ let list = false;
1975
+ for (let at = 0;at < args.length; at += 1) {
1976
+ const arg = args[at] ?? "";
1977
+ if (arg === "--all")
1978
+ all = true;
1979
+ else if (arg === "-l" || arg === "--list")
1980
+ list = true;
1981
+ else if (arg === "-s" || arg === "--skill" || arg === "-a" || arg === "--agent" || arg === "--subagent") {
1982
+ while (at + 1 < args.length && !(args[at + 1] ?? "").startsWith("-")) {
1983
+ at += 1;
1984
+ if (arg === "-s" || arg === "--skill")
1985
+ skills.push(args[at] ?? "");
1986
+ }
1987
+ } else if (arg === "--metadata")
1988
+ at += 1;
1989
+ else if (!arg.startsWith("-") && source === null)
1990
+ source = arg;
1991
+ }
1992
+ return { source, skills, all, list };
1993
+ }
1994
+ var NAME = /^[\w.-]+$/;
1995
+ function github(repo, ref, subpath, named, all) {
1996
+ const [owner, name] = repo.split("/");
1997
+ const clean = `${owner}/${(name ?? "").replace(/\.git$/, "")}`;
1998
+ const path = subpath?.replace(/^\/+|\/+$/g, "") ?? "";
1999
+ return {
2000
+ kind: "github",
2001
+ repo: clean,
2002
+ ref,
2003
+ subpath: path === "" || path.split("/").includes("..") ? null : path,
2004
+ skills: all || named.length === 0 || named.includes("*") ? "all" : [...new Set(named)]
2005
+ };
2006
+ }
2007
+ function sourceOf(input, named, all) {
2008
+ const elsewhere = { kind: "elsewhere", source: input };
2009
+ if (/^(\.{1,2}(\/|$)|\/|~)/.test(input) || /^[A-Za-z]:[\\/]/.test(input))
2010
+ return elsewhere;
2011
+ const hash = input.indexOf("#");
2012
+ let rest = hash === -1 ? input : input.slice(0, hash);
2013
+ const fragment = hash === -1 ? "" : input.slice(hash + 1);
2014
+ const fragmentAt = fragment.indexOf("@");
2015
+ let ref = (fragmentAt === -1 ? fragment : fragment.slice(0, fragmentAt)) || null;
2016
+ const fragmentSkill = fragmentAt === -1 ? null : fragment.slice(fragmentAt + 1) || null;
2017
+ const withSkill = (names) => fragmentSkill === null ? names : [fragmentSkill];
2018
+ const prefixed = /^github:(.+)$/.exec(rest);
2019
+ if (prefixed?.[1] !== undefined)
2020
+ rest = prefixed[1];
2021
+ const tree = /^https?:\/\/(?:www\.)?github\.com\/([^/]+)\/([^/]+)\/tree\/([^/]+)(?:\/(.+))?$/.exec(rest);
2022
+ if (tree !== null) {
2023
+ ref = tree[3] ?? ref;
2024
+ return github(`${tree[1]}/${tree[2]}`, ref, tree[4] ?? null, withSkill(named), all);
2025
+ }
2026
+ const url = /^https?:\/\/(?:www\.)?github\.com\/([^/]+)\/([^/]+?)\/?$/.exec(rest);
2027
+ if (url !== null)
2028
+ return github(`${url[1]}/${url[2]}`, ref, null, withSkill(named), all);
2029
+ if (rest.includes(":"))
2030
+ return elsewhere;
2031
+ const at = /^([^/]+)\/([^/@]+)@(.+)$/.exec(rest);
2032
+ if (at !== null)
2033
+ return github(`${at[1]}/${at[2]}`, ref, null, [fragmentSkill ?? at[3] ?? ""], false);
2034
+ const shorthand = /^([^/]+)\/([^/]+?)(?:\/(.+?))?\/?$/.exec(rest);
2035
+ if (shorthand !== null && NAME.test(shorthand[1] ?? "") && NAME.test(shorthand[2] ?? "")) {
2036
+ return github(`${shorthand[1]}/${shorthand[2]}`, ref, shorthand[3] ?? null, withSkill(named), all);
2037
+ }
2038
+ return elsewhere;
2039
+ }
2040
+ function skillInstallOf2(command) {
2041
+ for (const words of shellWords(command)) {
2042
+ const args = addArguments(words);
2043
+ if (args === null)
2044
+ continue;
2045
+ const add = parseAdd(args);
2046
+ if (add.list || add.source === null)
2047
+ continue;
2048
+ return sourceOf(add.source, add.skills, add.all);
2049
+ }
2050
+ return null;
2051
+ }
2052
+ async function namesUnder(install, source) {
2053
+ const listing = await source.listing(install.repo);
2054
+ if (listing === "rate_limited" || listing === "unreachable")
2055
+ return listing;
2056
+ const prefix = install.subpath === null ? "" : `${install.subpath}/`;
2057
+ const files = skillFilesIn2(listing.files).filter((file) => file.path.startsWith(prefix)).sort((a, b) => a.path.split("/").length - b.path.split("/").length || a.path.localeCompare(b.path));
2058
+ const names = await Promise.all(files.slice(0, MAX_SKILLS_READ2).map(async (file) => {
2059
+ const markdown = await source.file(install.repo, file.path);
2060
+ const parts = file.path.split("/");
2061
+ return (markdown === null ? null : frontmatterName2(markdown)) ?? parts.at(-2) ?? install.repo.split("/")[1] ?? "";
2062
+ }));
2063
+ return { names, total: files.length };
2064
+ }
2065
+ async function readSkillInstall2(install, source, deadline) {
2066
+ if (install.kind === "elsewhere")
2067
+ return install;
2068
+ const late = deadline.then(() => "late");
2069
+ let names;
2070
+ let total;
2071
+ if (install.skills === "all") {
2072
+ const found = await Promise.race([
2073
+ namesUnder(install, source).catch(() => "unreachable"),
2074
+ late
2075
+ ]);
2076
+ if (found === "late")
2077
+ return {
2078
+ kind: "github",
2079
+ install,
2080
+ readings: [],
2081
+ notRead: 0,
2082
+ listing: "no answer in time"
2083
+ };
2084
+ if (found === "rate_limited" || found === "unreachable") {
2085
+ return { kind: "github", install, readings: [], notRead: 0, listing: found };
2086
+ }
2087
+ ({ names, total } = found);
2088
+ } else {
2089
+ names = install.skills.slice(0, MAX_SKILLS_READ2);
2090
+ total = install.skills.length;
2091
+ }
2092
+ const readings = await Promise.all(names.map(async (skill) => {
2093
+ const pulse = readPulse2({ source: install.repo, skill, installs: null, installsText: null, url: null }, source).then((read) => ({ skill, pulse: read })).catch(() => ({ skill, pulse: null, why: "read failed" }));
2094
+ const settled = await Promise.race([pulse, late]);
2095
+ return settled === "late" ? { skill, pulse: null, why: "no answer in time" } : settled;
2096
+ }));
2097
+ return {
2098
+ kind: "github",
2099
+ install,
2100
+ readings,
2101
+ notRead: Math.max(0, total - names.length),
2102
+ listing: null
2103
+ };
2104
+ }
2105
+ var plural = (count, word) => `${count} ${word}${count === 1 ? "" : "s"}`;
2106
+ function readingLines(repo, reading) {
2107
+ const head = `${repo} · ${reading.skill}`;
2108
+ const { pulse } = reading;
2109
+ if (pulse === null)
2110
+ return [
2111
+ `${head}: not read (${reading.why === "no answer in time" ? "GitHub did not answer in time" : "the read failed"})`
2112
+ ];
2113
+ switch (pulse.status) {
2114
+ case "read": {
2115
+ const facts = [
2116
+ `${pulse.path}`,
2117
+ plural(pulse.files, "file"),
2118
+ ...pulse.repository === null ? [] : [
2119
+ plural(pulse.repository.stars, "star"),
2120
+ ...pulse.repository.pushedAt === null ? [] : [`last push ${pulse.repository.pushedAt.slice(0, 10)}`],
2121
+ ...pulse.repository.archived ? ["archived"] : []
2122
+ ]
2123
+ ];
2124
+ return [
2125
+ `${head} (${facts.join(", ")})`,
2126
+ ...contentsLines2(pulse.contains).map((line) => ` ${line}`),
2127
+ ...pulse.differsAt.length === 0 ? [] : [` Other files carry this name and differ: ${pulse.differsAt.join(", ")}`]
2128
+ ];
2129
+ }
2130
+ case "read_file_only":
2131
+ return [
2132
+ `${head} (${pulse.path}; GitHub's hourly limit was reached, so SKILL.md alone was read, not its scripts)`,
2133
+ ...contentsLines2(pulse.contains).map((line) => ` ${line}`)
2134
+ ];
2135
+ case "absent":
2136
+ return [
2137
+ `${head}: no SKILL.md in the repository names it (${plural(pulse.skillFiles, "skill file")} read)`
2138
+ ];
2139
+ case "ambiguous":
2140
+ return [
2141
+ `${head}: several files carry this name and differ, and which one installs is not knowable here: ${pulse.paths.join(", ")}`
2142
+ ];
2143
+ case "incomplete":
2144
+ return [
2145
+ `${head}: not read (${pulse.reason === "truncated_listing" ? "GitHub cut the repository's file list" : "too many skill files to search"})`
2146
+ ];
2147
+ case "rate_limited":
2148
+ return [`${head}: not read (GitHub's hourly limit; GITHUB_TOKEN raises it)`];
2149
+ case "repository_unreachable":
2150
+ return [`${head}: not read (the repository did not answer)`];
2151
+ case "not_github":
2152
+ return [`${head}: not read (not a GitHub repository)`];
2153
+ }
2154
+ }
2155
+ function skillInstallReport2(read) {
2156
+ const title = "ARP read this skill before the install (what its own files contain; facts, not a verdict):";
2157
+ if (read.kind === "elsewhere") {
2158
+ return `${title}
2159
+ ${read.source}: not read (ARP reads GitHub sources only)`;
2160
+ }
2161
+ const { install } = read;
2162
+ const lines = [title];
2163
+ if (read.listing !== null) {
2164
+ const why = read.listing === "rate_limited" ? "GitHub's hourly limit; GITHUB_TOKEN raises it" : read.listing === "no answer in time" ? "GitHub did not answer in time" : "the repository did not answer";
2165
+ lines.push(`${install.repo}${install.subpath === null ? "" : `/${install.subpath}`}: not read (${why})`);
2166
+ } else if (read.readings.length === 0) {
2167
+ lines.push(`${install.repo}${install.subpath === null ? "" : `/${install.subpath}`}: no SKILL.md found`);
2168
+ }
2169
+ for (const reading of read.readings)
2170
+ lines.push(...readingLines(install.repo, reading));
2171
+ if (read.notRead > 0)
2172
+ lines.push(`${plural(read.notRead, "more skill")} in this install not read (ARP reads ${MAX_SKILLS_READ2})`);
2173
+ if (install.ref !== null)
2174
+ lines.push(`Read at the default branch's HEAD; the command names ${install.ref}.`);
2175
+ return lines.join(`
2176
+ `);
2177
+ }
2178
+
2179
+ // ../hook/src/pre-install.ts
2180
+ var GITHUB_BUDGET_MS = 6000;
2181
+ var OUTPUT_CAP = 9500;
2182
+ var FOR_THE_AGENT = "This is what the skill's own files contain, read by ARP's hook before the install ran. " + "They are facts, not a verdict, and nothing was blocked. The person was shown the same lines.";
2183
+ function capped(text) {
2184
+ return text.length <= OUTPUT_CAP ? text : `${text.slice(0, OUTPUT_CAP)}
2185
+ … (cut)`;
2186
+ }
2187
+ async function preToolUse(raw, options = {}) {
2188
+ const call = toolCallOf(raw);
2189
+ if (call === null || call.tool !== "Bash")
2190
+ return null;
2191
+ const command = call.input?.["command"];
2192
+ if (typeof command !== "string")
2193
+ return null;
2194
+ const install = skillInstallOf2(command);
2195
+ if (install === null)
2196
+ return null;
2197
+ const env = options.env ?? process.env;
2198
+ const token = (env["GITHUB_TOKEN"] ?? env["GH_TOKEN"])?.trim() || undefined;
2199
+ const budgetMs = options.budgetMs ?? GITHUB_BUDGET_MS;
2200
+ const deadline = new Promise((resolve) => setTimeout(resolve, budgetMs));
2201
+ const source = githubPulseSource2({
2202
+ ...options.fetch === undefined ? {} : { fetch: options.fetch },
2203
+ ...token === undefined ? {} : { token },
2204
+ timeoutMs: budgetMs + 500,
2205
+ signal: AbortSignal.timeout(budgetMs + 500)
2206
+ });
2207
+ const report = capped(skillInstallReport2(await readSkillInstall2(install, source, deadline)));
2208
+ return JSON.stringify({
2209
+ systemMessage: report,
2210
+ hookSpecificOutput: {
2211
+ hookEventName: "PreToolUse",
2212
+ additionalContext: `${report}
2213
+
2214
+ ${FOR_THE_AGENT}`
2215
+ }
2216
+ });
2217
+ }
2218
+
2219
+ // ../hook/src/failure-answer.ts
2220
+ import { createHash } from "node:crypto";
2221
+
2222
+ // ../../packages/protocol/src/declare/line-need.ts
2223
+ var NEEDS_LABEL3 = "needs";
2224
+ var WITH_LABEL3 = "with";
2225
+ var PROGRAM_NAME3 = /^[a-z0-9][a-z0-9._+-]{0,39}$/;
2226
+ var KEY_NAME4 = /^[A-Z][A-Z0-9_]{2,63}$/;
2227
+ function needKindOf3(name) {
2228
+ if (PROGRAM_NAME3.test(name))
2229
+ return "program";
2230
+ if (KEY_NAME4.test(name))
2231
+ return "key";
2232
+ return null;
2233
+ }
2234
+ function needKindOfReason3(reason) {
2235
+ if (reason === "missing-program")
2236
+ return "program";
2237
+ if (reason === "missing-key")
2238
+ return "key";
2239
+ return null;
2240
+ }
2241
+ var escaped = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
2242
+ function namedInSkill3(name, markdown) {
2243
+ const kind = needKindOf3(name);
2244
+ if (kind === null)
2245
+ return false;
2246
+ const pattern = new RegExp(`(?<![A-Za-z0-9_+.-])${escaped(name)}(?![A-Za-z0-9_+-])(?!\\.[A-Za-z0-9])`, kind === "program" ? "i" : "");
2247
+ return pattern.test(markdown);
2248
+ }
2249
+ function publishableNeed3(name, markdown, kind) {
2250
+ const shape = needKindOf3(name);
2251
+ if (shape === null || kind !== undefined && shape !== kind)
2252
+ return null;
2253
+ return namedInSkill3(name, markdown) ? name : null;
2254
+ }
2255
+
2256
+ // ../../packages/protocol/src/declare/thing-cid.ts
2257
+ function thingDocument2(thing) {
2258
+ return JSON.stringify({
2259
+ "@context": "https://schema.org",
2260
+ "@type": "Thing",
2261
+ description: thing.description,
2262
+ image: thing.image,
2263
+ name: thing.name,
2264
+ url: thing.url
2265
+ });
2266
+ }
2267
+ function base32(bytes) {
2268
+ const alphabet = "abcdefghijklmnopqrstuvwxyz234567";
2269
+ let bits = 0;
2270
+ let value = 0;
2271
+ let out = "";
2272
+ for (const byte of bytes) {
2273
+ value = value << 8 | byte;
2274
+ bits += 8;
2275
+ while (bits >= 5) {
2276
+ out += alphabet[value >>> bits - 5 & 31];
2277
+ bits -= 5;
2278
+ }
2279
+ }
2280
+ if (bits > 0)
2281
+ out += alphabet[value << 5 - bits & 31];
2282
+ return out;
2283
+ }
2284
+ function thingUriOfDigest(digest) {
2285
+ const cid = new Uint8Array(4 + digest.length);
2286
+ cid.set([1, 85, 18, 32]);
2287
+ cid.set(digest, 4);
2288
+ return `ipfs://b${base32(cid)}`;
2289
+ }
2290
+
2291
+ // ../../packages/protocol/src/declare/tool-thing.ts
2292
+ class InvalidToolUrlError2 extends Error {
2293
+ input;
2294
+ constructor(input, why) {
2295
+ super(`${JSON.stringify(input)} is not a usable tool URL: ${why}`);
2296
+ this.name = "InvalidToolUrlError";
2297
+ this.input = input;
2298
+ }
2299
+ }
2300
+ var TOOL_THING_DESCRIPTION2 = "A tool identified by its URL, so every declaration of its use lands on one atom.";
2301
+ function normaliseToolUrl2(input) {
2302
+ const trimmed = input.trim();
2303
+ if (trimmed.length === 0)
2304
+ throw new InvalidToolUrlError2(input, "empty");
2305
+ const withScheme = /^[a-z][a-z0-9+.-]*:/i.test(trimmed) ? trimmed : `https://${trimmed}`;
2306
+ let url;
2307
+ try {
2308
+ url = new URL(withScheme);
2309
+ } catch {
2310
+ throw new InvalidToolUrlError2(input, "not parseable as a URL");
2311
+ }
2312
+ if (url.protocol !== "http:" && url.protocol !== "https:") {
2313
+ throw new InvalidToolUrlError2(input, `scheme ${url.protocol} is not http or https`);
2314
+ }
2315
+ if (url.hostname.length === 0)
2316
+ throw new InvalidToolUrlError2(input, "no host");
2317
+ const host = url.hostname.replace(/\.+$/, "").replace(/^(?:www\.)+/, "");
2318
+ const path = url.pathname.replace(/(?:\.git|\/)+$/, "");
2319
+ const params = [...new URLSearchParams(url.search).entries()].sort(([a], [b]) => a < b ? -1 : a > b ? 1 : 0);
2320
+ const query = params.length === 0 ? "" : `?${new URLSearchParams(params).toString()}`;
2321
+ const port = url.port === "" || url.port === "80" || url.port === "443" ? "" : `:${url.port}`;
2322
+ return `https://${host}${port}${path}${query}`;
2323
+ }
2324
+ function toolThing2(url) {
2325
+ const normalised = normaliseToolUrl2(url);
2326
+ return {
2327
+ name: normalised.slice("https://".length),
2328
+ description: TOOL_THING_DESCRIPTION2,
2329
+ image: "",
2330
+ url: normalised
2331
+ };
2332
+ }
2333
+
2334
+ // ../../packages/protocol/src/declare/usage-words.ts
2335
+ var USAGE_OUTCOMES3 = ["worked", "failed"];
2336
+ var HAS_OUTCOME_LABEL3 = "has outcome";
2337
+ var USAGE_REASONS3 = ["missing-key", "missing-program", "missing-file", "not-the-right-tool", "no-delivery"];
2338
+ var BECAUSE_LABEL3 = "because";
2339
+
2340
+ // ../../packages/protocol/src/sources/intuition/terms.ts
2341
+ var USES2 = "0x5c0bde1cc696456c0268248c4656acdf9621fdb39e605bc99b0a83dc8ff6e800";
2342
+
2343
+ // ../../packages/protocol/src/pulse-usage.ts
2344
+ var DEFAULT_LIMIT = 250;
2345
+ var rowsOf = (data) => Array.isArray(data["triples"]) ? data["triples"].filter(isRecord) : [];
2346
+ async function findToolAtoms2(uris, config) {
2347
+ const out = new Map;
2348
+ if (uris.length === 0)
2349
+ return out;
2350
+ const transport = config.transport ?? createGraphqlTransport({
2351
+ url: config.graphqlUrl,
2352
+ fetch: config.fetch ?? defaultFetch(),
2353
+ timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS
2354
+ });
2355
+ const data = await transport.request(PULSE_ATOMS_QUERY, { uris: [...uris], limit: uris.length });
2356
+ const rows = Array.isArray(data["atoms"]) ? data["atoms"].filter(isRecord) : [];
2357
+ for (const row of rows) {
2358
+ const id = readString(row, "term_id");
2359
+ const uri = readString(row, "data");
2360
+ if (id !== null && uri !== null)
2361
+ out.set(uri, id);
2362
+ }
2363
+ return out;
2364
+ }
2365
+ async function getPulseUsage2(toolAtomIds, config) {
2366
+ const transport = config.transport ?? createGraphqlTransport({
2367
+ url: config.graphqlUrl,
2368
+ fetch: config.fetch ?? defaultFetch(),
2369
+ timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS
2370
+ });
2371
+ const limit = Math.min(config.limit ?? DEFAULT_LIMIT, DEFAULT_LIMIT);
2372
+ const key = (id) => id.toLowerCase();
2373
+ const empty = () => ({
2374
+ declarations: [],
2375
+ agents: 0,
2376
+ wallets: 0,
2377
+ byDomain: {},
2378
+ byOutcome: {},
2379
+ byReason: {},
2380
+ byNeed: {},
2381
+ byWith: {},
2382
+ byOthers: [],
2383
+ truncated: false
2384
+ });
2385
+ const out = new Map(toolAtomIds.map((id) => [key(id), empty()]));
2386
+ if (toolAtomIds.length === 0)
2387
+ return out;
2388
+ const edgeRows = rowsOf(await transport.request(PULSE_USES_QUERY, { tools: [...toolAtomIds], uses: USES2, limit }));
2389
+ const edges = new Map;
2390
+ const NESTED_CAP = 100;
2391
+ let truncated = edgeRows.length >= limit;
2392
+ for (const row of edgeRows) {
2393
+ const tripleId = readString(row, "term_id");
2394
+ const tool = readString(row, "object_id");
2395
+ const writer = readString(row, "creator_id");
2396
+ const subject = readRecord(row, "subject");
2397
+ const atomId = subject === null ? null : readString(subject, "term_id");
2398
+ if (tripleId === null || tool === null || writer === null || subject === null || atomId === null)
2399
+ continue;
2400
+ const edgeHolders = (Array.isArray(row["positions"]) ? row["positions"].filter(isRecord) : []).map((holder) => readString(holder, "account_id")).filter((account) => account !== null);
2401
+ const declaration = (wallet, declaredAt) => ({
2402
+ tripleId,
2403
+ agent: { atomId, label: readString(subject, "label") },
2404
+ writer: wallet,
2405
+ holders: edgeHolders,
2406
+ declaredAt,
2407
+ domains: [],
2408
+ outcomes: [],
2409
+ lines: []
2410
+ });
2411
+ const declarers = new Map([[key(writer), declaration(writer, readString(row, "created_at"))]]);
2412
+ const holders = Array.isArray(row["positions"]) ? row["positions"].filter(isRecord) : [];
2413
+ if (holders.length >= NESTED_CAP)
2414
+ truncated = true;
2415
+ for (const holder of holders) {
2416
+ const wallet = readString(holder, "account_id");
2417
+ if (wallet !== null && !declarers.has(key(wallet)))
2418
+ declarers.set(key(wallet), declaration(wallet, null));
2419
+ }
2420
+ edges.set(key(tripleId), { tool: key(tool), declarers });
2421
+ }
2422
+ const payers = new Set(config.payers.map(key));
2423
+ const writers = [...new Set([...edges.values()].flatMap((edge) => [...edge.declarers.values()].map((row) => row.writer)))];
2424
+ const qualifiers = async (subjects, predicates) => subjects.length === 0 ? [] : rowsOf(await transport.request(PULSE_QUALIFIERS_QUERY, { edges: subjects, predicates, writers, limit }));
2425
+ const pass = (rows) => {
2426
+ truncated = truncated || rows.length >= limit;
2427
+ return rows;
2428
+ };
2429
+ const standing = (row, edge, below) => {
2430
+ const holders = Array.isArray(row["positions"]) ? row["positions"].filter(isRecord) : [];
2431
+ if (holders.length >= NESTED_CAP)
2432
+ truncated = true;
2433
+ const wallets = [readString(row, "creator_id"), ...holders.map((holder) => readString(holder, "account_id"))];
2434
+ return new Set(wallets.filter((wallet) => wallet !== null).map(key).filter((wallet) => edge.declarers.has(wallet) && !payers.has(wallet) && (below === undefined || below.has(wallet))));
2435
+ };
2436
+ const parts = (row) => {
2437
+ const object = readRecord(row, "object");
2438
+ return {
2439
+ termId: readString(row, "term_id"),
2440
+ subjectId: readString(row, "subject_id"),
2441
+ predicateId: readString(row, "predicate_id"),
2442
+ writer: readString(row, "creator_id"),
2443
+ value: object === null ? null : readString(object, "label")
2444
+ };
2445
+ };
2446
+ const isOutcome = (value) => USAGE_OUTCOMES3.some((word) => word === value);
2447
+ const isReason = (value) => USAGE_REASONS3.some((word) => word === value);
2448
+ const contexts = new Map;
2449
+ const outcomes = new Map;
2450
+ const others = (edge, row, predicate) => out.get(edge.tool)?.byOthers.push({
2451
+ tripleId: row.termId ?? "",
2452
+ writer: row.writer ?? "",
2453
+ predicate,
2454
+ value: row.value ?? ""
2455
+ });
2456
+ const onEdge = pass(await qualifiers([...edges.keys()], [config.inContextOf, config.hasOutcome]));
2457
+ for (const row of onEdge) {
2458
+ const line = parts(row);
2459
+ const edge = line.subjectId === null ? undefined : edges.get(key(line.subjectId));
2460
+ if (edge === undefined || line.predicateId === null || line.writer === null || line.value === null || line.termId === null)
2461
+ continue;
2462
+ const isOutcomeLine = key(line.predicateId) === key(config.hasOutcome);
2463
+ if (isOutcomeLine && !isOutcome(line.value))
2464
+ continue;
2465
+ const wallets = standing(row, edge);
2466
+ if (wallets.size === 0) {
2467
+ others(edge, line, isOutcomeLine ? "outcome" : "context");
2468
+ } else if (isOutcomeLine && isOutcome(line.value)) {
2469
+ outcomes.set(key(line.termId), { edge, domain: null, form: "sibling", outcome: line.value, wallets, reasons: new Map, named: new Map });
2470
+ } else {
2471
+ contexts.set(key(line.termId), { edge, domain: line.value, wallets });
2472
+ }
2473
+ }
2474
+ const onContext = pass(await qualifiers([...contexts.keys()], [config.hasOutcome]));
2475
+ for (const row of onContext) {
2476
+ const line = parts(row);
2477
+ const context = line.subjectId === null ? undefined : contexts.get(key(line.subjectId));
2478
+ if (context === undefined || line.value === null || line.termId === null || !isOutcome(line.value))
2479
+ continue;
2480
+ const wallets = standing(row, context.edge, context.wallets);
2481
+ if (wallets.size === 0) {
2482
+ others(context.edge, line, "outcome");
2483
+ } else {
2484
+ outcomes.set(key(line.termId), { edge: context.edge, domain: context.domain, form: "nested", outcome: line.value, wallets, reasons: new Map, named: new Map });
2485
+ }
2486
+ }
2487
+ const reading = (predicate) => predicate !== undefined;
2488
+ const failures = [...outcomes.entries()].filter(([, found]) => found.outcome === "failed").map(([id]) => id);
2489
+ const worked = [...outcomes.entries()].filter(([, found]) => found.outcome === "worked").map(([id]) => id);
2490
+ const withId = config.with;
2491
+ const onOutcome = pass(await qualifiers(reading(withId) ? [...failures, ...worked] : failures, [config.because, ...reading(withId) ? [withId] : []]));
2492
+ const reasonTerms = new Map;
2493
+ const addName = (found, wallets, name) => {
2494
+ for (const wallet of wallets) {
2495
+ const given = found.named.get(wallet) ?? [];
2496
+ if (!given.includes(name))
2497
+ given.push(name);
2498
+ found.named.set(wallet, given);
2499
+ }
2500
+ };
2501
+ for (const row of onOutcome) {
2502
+ const line = parts(row);
2503
+ const found = line.subjectId === null ? undefined : outcomes.get(key(line.subjectId));
2504
+ if (found === undefined || line.value === null || line.predicateId === null)
2505
+ continue;
2506
+ if (withId !== undefined && key(line.predicateId) === key(withId)) {
2507
+ if (found.outcome !== "worked" || needKindOf3(line.value) === null)
2508
+ continue;
2509
+ const wallets2 = standing(row, found.edge, found.wallets);
2510
+ if (wallets2.size === 0)
2511
+ others(found.edge, line, "with");
2512
+ addName(found, wallets2, line.value);
2513
+ continue;
2514
+ }
2515
+ if (found.outcome !== "failed" || !isReason(line.value))
2516
+ continue;
2517
+ const wallets = standing(row, found.edge, found.wallets);
2518
+ if (wallets.size === 0)
2519
+ others(found.edge, line, "reason");
2520
+ for (const wallet of wallets) {
2521
+ const given = found.reasons.get(wallet) ?? [];
2522
+ if (!given.includes(line.value))
2523
+ given.push(line.value);
2524
+ found.reasons.set(wallet, given);
2525
+ }
2526
+ if (line.termId !== null && wallets.size > 0 && needKindOfReason3(line.value) !== null) {
2527
+ reasonTerms.set(key(line.termId), { found, reason: line.value, wallets });
2528
+ }
2529
+ }
2530
+ const needsId = config.needs;
2531
+ if (reading(needsId)) {
2532
+ const onReason = pass(await qualifiers([...reasonTerms.keys()], [needsId]));
2533
+ for (const row of onReason) {
2534
+ const line = parts(row);
2535
+ const reason = line.subjectId === null ? undefined : reasonTerms.get(key(line.subjectId));
2536
+ if (reason === undefined || line.value === null)
2537
+ continue;
2538
+ const kind = needKindOf3(line.value);
2539
+ if (kind === null || kind !== needKindOfReason3(reason.reason))
2540
+ continue;
2541
+ const wallets = standing(row, reason.found.edge, reason.wallets);
2542
+ if (wallets.size === 0)
2543
+ others(reason.found.edge, line, "needs");
2544
+ addName(reason.found, wallets, line.value);
2545
+ }
2546
+ }
2547
+ for (const { edge, domain, wallets } of contexts.values()) {
2548
+ for (const wallet of wallets)
2549
+ edge.declarers.get(wallet)?.domains.push(domain);
2550
+ }
2551
+ const ordered = [...outcomes.values()].sort((a, b) => Number(b.form === "nested") - Number(a.form === "nested"));
2552
+ for (const found of ordered) {
2553
+ for (const wallet of found.wallets) {
2554
+ const declaration = found.edge.declarers.get(wallet);
2555
+ if (declaration === undefined)
2556
+ continue;
2557
+ const reasons = found.reasons.get(wallet) ?? [];
2558
+ const named = found.named.get(wallet) ?? [];
2559
+ const field = found.outcome === "failed" ? "needs" : "with";
2560
+ if (!declaration.outcomes.includes(found.outcome))
2561
+ declaration.outcomes.push(found.outcome);
2562
+ const domains = found.form === "nested" ? [found.domain] : declaration.domains.length > 0 ? declaration.domains : [null];
2563
+ for (const domain of domains) {
2564
+ const same = declaration.lines.find((line) => line.domain === domain && line.outcome === found.outcome);
2565
+ if (same === undefined) {
2566
+ declaration.lines.push({ domain, outcome: found.outcome, reasons, form: found.form, ...named.length === 0 ? {} : { [field]: named } });
2567
+ } else {
2568
+ same.reasons = [...new Set([...same.reasons, ...reasons])];
2569
+ if (named.length > 0)
2570
+ same[field] = [...new Set([...same[field] ?? [], ...named])];
2571
+ }
2572
+ }
2573
+ }
2574
+ }
2575
+ for (const { tool, declarers } of edges.values()) {
2576
+ const rows = [...declarers.values()].filter((row, at) => at === 0 || row.domains.length > 0 || row.lines.length > 0);
2577
+ out.get(tool)?.declarations.push(...rows);
2578
+ }
2579
+ for (const usage of out.values()) {
2580
+ usage.truncated = truncated;
2581
+ usage.agents = new Set(usage.declarations.map((declaration) => key(declaration.agent.atomId))).size;
2582
+ usage.wallets = new Set(usage.declarations.map((declaration) => key(declaration.writer)).filter((wallet) => !payers.has(wallet))).size;
2583
+ for (const declaration of usage.declarations) {
2584
+ for (const domain of declaration.domains)
2585
+ usage.byDomain[domain] = (usage.byDomain[domain] ?? 0) + 1;
2586
+ for (const outcome of declaration.outcomes)
2587
+ usage.byOutcome[outcome] = (usage.byOutcome[outcome] ?? 0) + 1;
2588
+ for (const reason of new Set(declaration.lines.flatMap((line) => line.reasons))) {
2589
+ usage.byReason[reason] = (usage.byReason[reason] ?? 0) + 1;
2590
+ }
2591
+ const byNeed = usage.byNeed ??= {};
2592
+ for (const name of new Set(declaration.lines.flatMap((line) => line.needs ?? [])))
2593
+ byNeed[name] = (byNeed[name] ?? 0) + 1;
2594
+ const byWith = usage.byWith ??= {};
2595
+ for (const name of new Set(declaration.lines.flatMap((line) => line.with ?? [])))
2596
+ byWith[name] = (byWith[name] ?? 0) + 1;
2597
+ }
2598
+ }
2599
+ return out;
2600
+ }
2601
+
2602
+ // ../../packages/protocol/src/failure-lines.ts
2603
+ function skillUrlOf2(source, skill) {
2604
+ if (!/^[\w.-]+\/[\w.-]+$/.test(source))
2605
+ return null;
2606
+ const name = skill.split(":").pop() ?? skill;
2607
+ const url = `https://github.com/${source}?skill=${encodeURIComponent(name)}`;
2608
+ return skillRefFromUrl3(url) === null ? null : url;
2609
+ }
2610
+ function skillAtom(url, sha256) {
2611
+ const thing = toolThing2(url);
2612
+ return { uri: thingUriOfDigest(sha256(thingDocument2(thing))), label: thing.name };
2613
+ }
2614
+ async function readSkillLines(atomUri, config) {
2615
+ const words = [HAS_OUTCOME_LABEL3, BECAUSE_LABEL3, NEEDS_LABEL3, WITH_LABEL3];
2616
+ const atoms = await findToolAtoms2([atomUri, ...words], config);
2617
+ const tool = atoms.get(atomUri);
2618
+ const hasOutcome = atoms.get(HAS_OUTCOME_LABEL3);
2619
+ const because = atoms.get(BECAUSE_LABEL3);
2620
+ if (tool === undefined || hasOutcome === undefined || because === undefined)
2621
+ return null;
2622
+ const needs = atoms.get(NEEDS_LABEL3);
2623
+ const withId = atoms.get(WITH_LABEL3);
2624
+ const usage = await getPulseUsage2([tool], {
2625
+ ...config,
2626
+ hasOutcome,
2627
+ because,
2628
+ ...needs === undefined ? {} : { needs },
2629
+ ...withId === undefined ? {} : { with: withId }
2630
+ });
2631
+ return usage.get(tool.toLowerCase()) ?? null;
2632
+ }
2633
+ function counted(counts) {
2634
+ return [...counts.entries()].sort(([a, x], [b, y]) => y.size - x.size || a.localeCompare(b)).map(([name, wallets]) => `${name} (${wallets.size})`).join(", ");
2635
+ }
2636
+ var plural2 = (n) => `${n} wallet${n === 1 ? "" : "s"}`;
2637
+ function linesSentence(usage, label, where) {
2638
+ if (usage === null)
2639
+ return null;
2640
+ const parts = [];
2641
+ for (const outcome of ["failed", "worked"]) {
2642
+ const wallets = new Set;
2643
+ const because = new Map;
2644
+ const named = new Map;
2645
+ const add = (to, name, wallet) => to.set(name, (to.get(name) ?? new Set).add(wallet));
2646
+ for (const row of usage.declarations) {
2647
+ const wallet = row.writer.toLowerCase();
2648
+ for (const line of row.lines) {
2649
+ if (line.outcome !== outcome)
2650
+ continue;
2651
+ wallets.add(wallet);
2652
+ for (const reason of line.reasons)
2653
+ add(because, reason, wallet);
2654
+ for (const name of (outcome === "failed" ? line.needs : line.with) ?? [])
2655
+ add(named, name, wallet);
2656
+ }
2657
+ }
2658
+ if (wallets.size === 0)
2659
+ continue;
2660
+ const detail = [
2661
+ ...because.size === 0 ? [] : [`because ${counted(because)}`],
2662
+ ...named.size === 0 ? [] : [`${outcome === "failed" ? "needs" : "with"} ${counted(named)}`]
2663
+ ];
2664
+ parts.push([`${usage.truncated ? "at least " : ""}${plural2(wallets.size)} wrote ${outcome}`, ...detail].join(" · "));
2665
+ }
2666
+ if (parts.length === 0)
2667
+ return null;
2668
+ return `ARP, lines agents wrote on ${label} (${where}): ${parts.join("; ")}.`;
2669
+ }
2670
+ // ../../data/deployments/13579.json
2671
+ var _13579_default = {
2672
+ chain: {
2673
+ name: "Intuition Testnet",
2674
+ chainId: 13579,
2675
+ chainIdHex: "0x350b",
2676
+ nativeCurrency: {
2677
+ name: "Test Trust",
2678
+ symbol: "tTRUST",
2679
+ decimals: 18
2680
+ },
2681
+ rpcUrl: "https://testnet.rpc.intuition.systems/http",
2682
+ explorerUrl: "https://testnet.explorer.intuition.systems",
2683
+ graphqlUrl: "https://testnet.intuition.sh/v1/graphql",
2684
+ _source: [
2685
+ "Intuition skill: .claude/skills/intuition/SKILL.md (table at line 149, Viem chain config at line 184)",
2686
+ "MetaMask deployments: ~/Project/metamask-smart-accounts-kit/packages/delegation-deployments/src/index.ts (CHAIN_ID.intuitionTestnet = 0x350b)"
2687
+ ]
2688
+ },
2689
+ intuition: {
2690
+ _source: ".claude/skills/intuition/SKILL.md line 152",
2691
+ multiVault: "0x2Ece8D4dEdcB9918A398528f3fa4688b1d2CAB91"
2692
+ },
2693
+ metamaskDelegationFramework: {
2694
+ version: "1.3.0",
2695
+ _source: "MetaMask deployments package (~/Project/metamask-smart-accounts-kit/packages/delegation-deployments/src/contractAddresses.ts → DEPLOYMENTS_1_3_0). All addresses are deterministic CREATE2 — same value on every chain MetaMask supports. Intuition Testnet (chainId 0x350b) is explicitly mapped to DEPLOYMENTS_1_3_0 at packages/delegation-deployments/src/index.ts line 148.",
2696
+ delegationManager: "0xdb9B1e94B5b69Df7e401DDbedE43491141047dB3",
2697
+ entryPoint: "0x0000000071727De22E5E9d8BAf0edAc6f37da032",
2698
+ simpleFactory: "0x69Aa2f9fe1572F1B640E1bbc512f5c3a734fc77c",
2699
+ implementations: {
2700
+ hybridDeleGator: "0x48dBe696A4D990079e039489bA2053B36E8FFEC4",
2701
+ multiSigDeleGator: "0x56a9EdB16a0105eb5a4C54f4C062e2868844f3A7",
2702
+ eip7702StatelessDeleGator: "0x63c0c19a282a1B52b07dD5a65b58948A07DAE32B"
2703
+ },
2704
+ enforcers: {
2705
+ _note: "Standard caveat enforcers. ARP composes its custom DomainScopeEnforcer + TrustStakeCapEnforcer alongside a subset of these.",
2706
+ allowedCalldata: "0xc2b0d624c1c4319760C96503BA27C347F3260f55",
2707
+ allowedMethods: "0x2c21fD0Cb9DC8445CB3fb0DC5E7Bb0Aca01842B5",
2708
+ allowedTargets: "0x7F20f61b1f09b08D970938F6fa563634d65c4EeB",
2709
+ approvalRevocation: "0xe264F1f09A19505a1ca1a86D5b01E8bFdb64324A",
2710
+ blockNumber: "0x5d9818dF0AE3f66e9c3D0c5029DAF99d1823ca6c",
2711
+ deployed: "0x24ff2AA430D53a8CD6788018E902E098083dcCd2",
2712
+ erc20BalanceChange: "0xcdF6aB796408598Cea671d79506d7D48E97a5437",
2713
+ erc20TransferAmount: "0xf100b0819427117EcF76Ed94B358B1A5b5C6D2Fc",
2714
+ erc20PeriodTransfer: "0x474e3Ae7E169e940607cC624Da8A15Eb120139aB",
2715
+ erc20Streaming: "0x56c97aE02f233B29fa03502Ecc0457266d9be00e",
2716
+ erc721BalanceChange: "0x8aFdf96eDBbe7e1eD3f5Cd89C7E084841e12A09e",
2717
+ erc721Transfer: "0x3790e6B7233f779b09DA74C72b6e94813925b9aF",
2718
+ erc1155BalanceChange: "0x63c322732695cAFbbD488Fc6937A0A7B66fC001A",
2719
+ exactCalldataBatch: "0x982FD5C86BBF425d7d1451f974192d4525113DfD",
2720
+ exactCalldata: "0x99F2e9bF15ce5eC84685604836F71aB835DBBdED",
2721
+ exactExecutionBatch: "0x1e141e455d08721Dd5BCDA1BaA6Ea5633Afd5017",
2722
+ exactExecution: "0x146713078D39eCC1F5338309c28405ccf85Abfbb",
2723
+ id: "0xC8B5D93463c893401094cc70e66A206fb5987997",
2724
+ logicalOrWrapper: "0xE1302607a3251AF54c3a6e69318d6aa07F5eB46c",
2725
+ limitedCalls: "0x04658B29F6b82ed55274221a06Fc97D318E25416",
2726
+ nativeBalanceChange: "0xbD7B277507723490Cd50b12EaaFe87C616be6880",
2727
+ argsEqualityCheck: "0x44B8C6ae3C304213c3e298495e12497Ed3E56E41",
2728
+ nativeTokenPayment: "0x4803a326ddED6dDBc60e659e5ed12d85c7582811",
2729
+ nativeTokenTransferAmount: "0xF71af580b9c3078fbc2BBF16FbB8EEd82b330320",
2730
+ nativeTokenStreaming: "0xD10b97905a320b13a0608f7E9cC506b56747df19",
2731
+ nativeTokenPeriodTransfer: "0x9BC0FAf4Aca5AE429F4c06aEEaC517520CB16BD9",
2732
+ nonce: "0xDE4f2FAC4B3D87A1d9953Ca5FC09FCa7F366254f",
2733
+ ownershipTransfer: "0x7EEf9734E7092032B5C56310Eb9BbD1f4A524681",
2734
+ redeemer: "0xE144b0b2618071B4E56f746313528a669c7E65c5",
2735
+ specificActionERC20TransferBatch: "0x6649b61c873F6F9686A1E1ae9ee98aC380c7bA13",
2736
+ timestamp: "0x1046bb45C8d673d4ea75321280DB34899413c069",
2737
+ valueLte: "0x92Bf12322527cAA612fd31a0e810472BBB106A8F",
2738
+ multiTokenPeriod: "0xFB2f1a9BD76d3701B730E5d69C3219D42D80eBb7"
2739
+ }
2740
+ },
2741
+ arp: {
2742
+ endpointBinding: {
2743
+ _note: "Task 39c, ADR 0094/0095. The two predicates the endpoint binding is written with: (agent identity atom) has endpoint (endpoint atom), and (pinned binding document) in context of (that triple). Both READ FROM THE GRAPH, neither minted by ARP: scripts/measure/endpoint-predicate.ts, run 2026-10-30, found `has endpoint` (Thing, 6 triples) and `in context of` (Thing, 29 triples) on testnet 13579, and none of `reachable at`, `is reachable at`, `served at`, `hosted at`. `in context of` differs from mainnet's 0x892054b0… (scripts/measure/nested-triples.ts), so never copy it across chains.",
2744
+ measuredAt: "2026-10-30",
2745
+ hasEndpoint: "0xa4488686eb3702e4e972a971ea008d6832a7f935b942366f1091566d1993a5f1",
2746
+ inContextOf: "0x61a88b9c372c0d164d2caf66947b67ed0fcb4c457178a271b6b3dc39fb1f8862"
2747
+ },
2748
+ _note: "Written by scripts/deploy/deploy.sh --broadcast. Addresses are EOA-nonce-derived (CREATE). deploy.sh skips a contract whose address here already has code unless --force, and on a redeploy keeps the replaced address under <name>V<n>. ModuleRegistry and DomainScopeEnforcer were removed from src/ in 59ac83a; their entries are the record.",
2749
+ deployer: "0xE596096F4176b682E300d73963e7B04B383C1AA1",
2750
+ deployedAt: "2026-06-01T13:30:00Z",
2751
+ moduleRegistry: "0xc9a2f66775828017e984E8be077fA2d17e0A41F4",
2752
+ moduleRegistryV1: "0x777C28eCb4688D647B535098d11fB87A9746334f",
2753
+ _moduleRegistryNote: "Redeployed 2026-06-03 with schemaURI uniqueness (ADR 0013). V1 address kept for historical reference; orphan (UI reads V2).",
2754
+ domainScopeEnforcer: "0x516B82E29e3Ca46Ca810FC2EEf348932b198f7f9",
2755
+ trustStakeCapEnforcer: "0x19e07280F1483Aa9aCDb1a7F8C61bfd20c7879Bc",
2756
+ identityRegistry: "0xC165A2AD2E540A4069E02834009161E2b4490d5A",
2757
+ sponsor: "0x77939A4c276f3E549276CEB3A09CDa1fF58b7ec9",
2758
+ sponsorV1: "0xE596096F4176b682E300d73963e7B04B383C1AA1",
2759
+ _sponsorNote: "The address ARP's sponsoring service sends from on 13579 (apps/sponsor, ADR 0092, 0094). Since 2026-11-09 a key of its own, for the hosted service (task 78, ADR 0149): sponsorV1 is the deployer's key, which sent for it before and also holds mainnet funds. Not a contract: an EOA whose key is a file mounted into the service's container, never read by an agent. Before 2026-11-09: The address ARP's sponsoring service sends from on 13579 (apps/sponsor, ADR 0092, 0094): its GET / answered this on 2026-11-02. /tools counts every deposit it sent in Usage: the proof-gated ones, the edge creations it paid for, and, because the address is also ARP's deployer, 3 deposits written before the service existed (scripts/measure/sponsor-deposit-provenance.ts, 2026-11-03). Not a contract: an EOA whose key is in a 0600 file the agent never reads.",
2760
+ deployedTxs: {
2761
+ moduleRegistry: "0x6ee4f4d76dd55c69ea434f8c3c204cb6149df1c588910b1792db1650681fbc2e",
2762
+ moduleRegistryV1: "0x02abe9a0c598df131995bc40927a4e0be0b86e7bdbfe747cfdf37fb19b069634",
2763
+ domainScopeEnforcer: "0x6ca2c4e680b45eaa37147c2458bd38d756e6ffabb560755657cc9caf893df272",
2764
+ trustStakeCapEnforcer: "0x8dd54ea3eeba14645531c501c3f1b8ec95e6a95788825e00fbe239ff32263159",
2765
+ identityRegistry: "0x60b1f6ff7dbdcbca6864794eb9c5cf1e3ba94770daac6d2e77a4df00d726900c",
2766
+ trustStakeCapEnforcerV1: "0x80e36828202a9c7606b92146076ed123155a94cfda3a2ab53013bd27be71764f"
2767
+ },
2768
+ explorerLinks: {
2769
+ moduleRegistry: "https://testnet.explorer.intuition.systems/address/0xc9a2f66775828017e984E8be077fA2d17e0A41F4",
2770
+ moduleRegistryV1: "https://testnet.explorer.intuition.systems/address/0x777C28eCb4688D647B535098d11fB87A9746334f",
2771
+ domainScopeEnforcer: "https://testnet.explorer.intuition.systems/address/0x516B82E29e3Ca46Ca810FC2EEf348932b198f7f9",
2772
+ trustStakeCapEnforcer: "https://testnet.explorer.intuition.systems/address/0x19e07280F1483Aa9aCDb1a7F8C61bfd20c7879Bc",
2773
+ identityRegistry: "https://testnet.explorer.intuition.systems/address/0xC165A2AD2E540A4069E02834009161E2b4490d5A",
2774
+ trustStakeCapEnforcerV1: "https://testnet.explorer.intuition.systems/address/0x7BB56819E9a413B8B4668C5cAF5C494c41dC0F8E"
2775
+ },
2776
+ modules: [
2777
+ {
2778
+ id: "1",
2779
+ name: "Solidity Audit",
2780
+ domain: "solidity-audit",
2781
+ schemaURI: "ipfs://bafkreiembmtprqzufrdkvig74lskv6iazuatblm4hwmtxkf5a3v67mkdkm",
2782
+ creator: "0xE596096F4176b682E300d73963e7B04B383C1AA1",
2783
+ tx: "0xbd97979b197e4423293180e36d69f72e8eb07d2bb11bdfb2940ec918d6f6af3c"
2784
+ }
2785
+ ],
2786
+ intuitionAtoms: [
2787
+ {
2788
+ atomId: "0xde8890fca8dde322ca57bce0e20dfeb23be67332f9101305ebe72facdee032dc",
2789
+ uri: "ipfs://bafkreiembmtprqzufrdkvig74lskv6iazuatblm4hwmtxkf5a3v67mkdkm",
2790
+ tx: "0x97db7629c6c973d43c0c62325754d750ee262853bdbd87496b4b82c1ea3d0ac7"
2791
+ }
2792
+ ],
2793
+ rigAgents: {
2794
+ _note: "Task 24. ERC-8004 agents on ARP's own testnet registry, minted 2026-10-19 on chain 13579. SIGNED BY THE AGENT SESSION using the operator's PRIVATE_KEY from .env, on the user's explicit authorisation — not by a human at a keyboard. See ADR 0037. security.md scopes its automation prohibition to mainnet, so this is permitted and was previously unwritten. Agents 1 and 2 were left with an EMPTY tokenURI deliberately: no-token-uri is 23% of the real cohort (32/140, scripts/measure/cohort-endpoints.ts), so they exercise a branch the three new agents cannot. Permanent: the ids are taken and setAgentURI leaves the superseded URI in the mint transaction's calldata.",
2795
+ registry: "0xC165A2AD2E540A4069E02834009161E2b4490d5A",
2796
+ agents: {
2797
+ "3": {
2798
+ slug: "rig-confirmed",
2799
+ exercises: "confirmed/serves-declared-protocol + tools/list recovery",
2800
+ endpoint: "http://localhost:3002/mcp",
2801
+ _endpointNote: "ARP's own MCP server, local by default. ARP_MCP_ENDPOINT regenerates the file and setAgentURI can update the agent — but that escape hatch is a rehearsal prop: portability.md rule 4 says any step that works because ARP can write to the registry is not a step, and on mainnet ARP owns no registry. The real fix is a public endpoint.",
2802
+ tx: "0xce4fee69c692ddf57d4537b23479d78384a9e2d06b733b532e419055ed50a086",
2803
+ documentSha256_16: "478ac85cd6b2357f",
2804
+ _documentShaNote: "sha256 of the data: URI, first 16 hex. Lets repo-vs-chain drift be detected: the fixtures in scripts/seed/rig-registration-files.ts are the source of truth for three permanent mints, and an edit to FILES would otherwise diverge silently. Checked by scripts/verify/verify-rig-claims.ts against a gate report. ONLY REPRODUCIBLE WITH ARP_MCP_ENDPOINT UNSET: OWN_ENDPOINT reads the environment and the document is hashed after substitution, so anyone with it exported sees a false DRIFT."
2805
+ },
2806
+ "4": {
2807
+ slug: "rig-dead",
2808
+ exercises: "confirmed/dead",
2809
+ endpoint: "http://192.0.2.1/mcp",
2810
+ _endpointNote: "TEST-NET-1, RFC 5737 — reserved and never routable, so it always times out. A .invalid hostname was tried first and gave inconclusive/transport-error, because a DNS failure is indistinguishable from our own network being down.",
2811
+ tx: "0x87bf71cf0ce55db7f82ca617b8601ee87f870e67018b1097a311ed2d61cc7378",
2812
+ uriUpdatedTx: "0x8f5950a61fca19b6a3f69b26f6c4159e29833689ed4b1623d8610206bfe87100",
2813
+ documentSha256_16: "6db8b769dd551e98"
2814
+ },
2815
+ "5": {
2816
+ slug: "rig-unprobeable",
2817
+ exercises: "not-checkable ×2 — templated and non-http-identifier. Never a defect.",
2818
+ tx: "0x859aff609fa10dba635ffd12d0b60b598c7c3174238f61962edb4b5eee1a0efd",
2819
+ documentSha256_16: "f61a9d7f6637958e"
2820
+ }
2821
+ },
2822
+ gate: {
2823
+ command: "bun run scripts/verify/verify-cohort.ts --target intuition-testnet --ids 1,2,3,4,5 --tools --out /tmp/gate.json && bun run scripts/verify/verify-rig-claims.ts /tmp/gate.json",
2824
+ ranAt: "2026-10-19",
2825
+ result: "5 agents: 2 with no tokenURI (40%), 3 read. 4 endpoints: 2 confirmed (serves-declared-protocol, dead), 2 not-checkable (templated, non-http-identifier), 0 inconclusive, 1 capability list recovered (arp_tool_reputation).",
2826
+ _requires: "apps/mcp/src/server.ts listening on :3002, or agent 3 reports inconclusive. The confirmed branch is therefore reproducible only on a host running that server — a known limit of this gate until ARP has a public endpoint.",
2827
+ _widerThanSpecced: "--ids 1,2,3,4,5 rather than 3,4,5. Including the two empty-tokenURI agents exercises a fifth branch for two extra requests.",
2828
+ _claimsCheck: "verify-rig-claims.ts asserts each fixture's `exercises` prose against the outcome the probe observed, and the document hashes against this file. The unit suite CANNOT close that class: confirmed and inconclusive are both probeable before a request is sent, and the mutation that actually shipped lived exactly there."
2829
+ }
2830
+ },
2831
+ trustStakeCapEnforcerV1: "0x7BB56819E9a413B8B4668C5cAF5C494c41dC0F8E",
2832
+ delegationRegister: {
2833
+ _note: "Task 37c, ADR 0092 item 7. The two predicates a published delegation is written with: (delegator CAIP-10) delegate to (delegate CAIP-10), and (pinned document) in context of (that triple). Both READ FROM THE GRAPH, neither minted by ARP: on testnet 13579 on 2026-11-03 exactly one atom carries each label, a Thing, `delegate to` in 10 triples and `in context of` in 29. `in context of` is the one endpointBinding uses. Never copy either across chains.",
2834
+ measuredAt: "2026-11-03",
2835
+ delegateTo: "0xb56980d42a3b03455bf41ea20fe04ae223fca0b9e688994dc661414e81e6433b",
2836
+ inContextOf: "0x61a88b9c372c0d164d2caf66947b67ed0fcb4c457178a271b6b3dc39fb1f8862"
2837
+ }
2838
+ }
2839
+ };
2840
+
2841
+ // ../hook/src/skill-failure.ts
2842
+ import { existsSync, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "node:fs";
2843
+ import { homedir as homedir2 } from "node:os";
2844
+ import { dirname as dirname2, join as join3 } from "node:path";
2845
+
2846
+ // ../../packages/protocol/src/declare/label.ts
2847
+ function normaliseCategoryLabel2(raw) {
2848
+ return raw.normalize("NFKC").normalize("NFD").replace(/[̀-ͯ]/g, "").toLowerCase().trim().replace(/\s+/g, " ");
2849
+ }
2850
+
2851
+ // ../../packages/protocol/src/domain-words.ts
2852
+ function tokens(text) {
2853
+ return normaliseCategoryLabel2(text).split(/[^a-z0-9]+/).filter((t) => t.length > 1);
2854
+ }
2855
+ function domainInText2(text, words) {
2856
+ const padded = ` ${tokens(text).join(" ")} `;
2857
+ const hit = (phrase) => padded.includes(` ${tokens(phrase).join(" ")} `);
2858
+ const label = [...words.labels].filter((l) => tokens(l).length > 0 && hit(l)).sort((a, b) => b.length - a.length)[0];
2859
+ if (label !== undefined)
2860
+ return label;
2861
+ const alias = Object.keys(words.aliases).filter((a) => words.labels.includes(words.aliases[a]) && hit(a)).sort((a, b) => b.length - a.length)[0];
2862
+ return alias === undefined ? null : words.aliases[alias];
2863
+ }
2864
+ // ../../data/catalogue/domain-aliases.json
2865
+ var domain_aliases_default = {
2866
+ _note: "Words a person or an agent uses, mapped to a node of ARP's domain tree (OASF 1.1.0 names, plus ARP's own `design`), task 84. Read locally by the MCP server, the CLI and the hook: the words never leave the machine (the user, 2026-11-09), except for a caller who chooses ARP's hosted read-only endpoint, which receives its words and keeps none (ADR 0161). Every target is checked against data/catalogue/oasf-1.1.0-skills.json by packages/protocol/test/domain-words.test.ts. ARP's old category words map to the one node that held them; the split ones (method, quality) have no alias, and a refusal suggests nodes instead.",
2867
+ oasfVersion: "1.1.0",
2868
+ aliases: {
2869
+ ads: "advertising",
2870
+ advertising: "advertising",
2871
+ agent: "agent application building",
2872
+ agents: "agent orchestration",
2873
+ android: "mobile development",
2874
+ animation: "web animation",
2875
+ api: "api development",
2876
+ audio: "audio & speech processing",
2877
+ automation: "tool use and automation",
2878
+ backend: "backend development",
2879
+ blockchain: "blockchain and web3",
2880
+ brand: "branding",
2881
+ browser: "browser automation",
2882
+ captions: "video editing",
2883
+ chart: "chart generation",
2884
+ charts: "chart generation",
2885
+ chat: "team messaging",
2886
+ collaboration: "collaboration and communication",
2887
+ commit: "commit authoring",
2888
+ copywriting: "copywriting",
2889
+ crawl: "web crawling",
2890
+ cro: "conversion optimization",
2891
+ dashboard: "dashboard building",
2892
+ database: "databases",
2893
+ debug: "code debugging",
2894
+ debugging: "code debugging",
2895
+ deck: "presentation authoring",
2896
+ deploy: "deployment and release management",
2897
+ development: "software engineering",
2898
+ docker: "containerization",
2899
+ docs: "technical writing",
2900
+ document: "document authoring",
2901
+ documentation: "project documentation",
2902
+ docx: "document authoring",
2903
+ editing: "video editing",
2904
+ email: "email marketing",
2905
+ excel: "spreadsheet authoring",
2906
+ frontend: "frontend development",
2907
+ git: "git workflow",
2908
+ illustration: "image generation",
2909
+ image: "computer vision",
2910
+ infrastructure: "devops and cloud infrastructure",
2911
+ ios: "mobile development",
2912
+ issues: "issue tracking",
2913
+ kubernetes: "container orchestration",
2914
+ landing: "conversion optimization",
2915
+ layout: "design",
2916
+ logo: "branding",
2917
+ logs: "logging and log analysis",
2918
+ marketing: "content, writing and marketing",
2919
+ mcp: "agent tool building",
2920
+ meeting: "meeting intelligence",
2921
+ meetings: "meeting intelligence",
2922
+ mobile: "mobile development",
2923
+ monitoring: "monitoring and alerting",
2924
+ montage: "video editing",
2925
+ music: "text to audio",
2926
+ newsletter: "email marketing",
2927
+ notes: "note-taking",
2928
+ payment: "payments integration",
2929
+ pdf: "pdf manipulation",
2930
+ pentest: "penetration testing",
2931
+ postgres: "relational database operations",
2932
+ powerpoint: "presentation authoring",
2933
+ pptx: "presentation authoring",
2934
+ pr: "pull request management",
2935
+ prd: "requirements and prd authoring",
2936
+ presentation: "presentation authoring",
2937
+ prompt: "prompt design",
2938
+ rag: "retrieval-augmented generation",
2939
+ research: "research and scholarship",
2940
+ review: "code review",
2941
+ scrape: "web scraping",
2942
+ scraping: "web data acquisition",
2943
+ search: "web search research",
2944
+ security: "cybersecurity",
2945
+ seo: "search engine optimization",
2946
+ slide: "presentation authoring",
2947
+ slides: "presentation authoring",
2948
+ "smart contract": "smart contract development",
2949
+ social: "social media marketing",
2950
+ solidity: "smart contract development",
2951
+ spec: "requirements and prd authoring",
2952
+ spreadsheet: "spreadsheet authoring",
2953
+ sql: "relational database operations",
2954
+ subtitles: "video editing",
2955
+ summarize: "text summarization",
2956
+ summary: "text summarization",
2957
+ tdd: "software testing",
2958
+ test: "software testing",
2959
+ testing: "software testing",
2960
+ tests: "software testing",
2961
+ thumbnail: "image generation",
2962
+ tickets: "issue tracking",
2963
+ trading: "defi and crypto trading",
2964
+ transcription: "automatic speech recognition",
2965
+ translate: "translation",
2966
+ tts: "text to speech",
2967
+ typography: "design",
2968
+ ui: "design",
2969
+ ux: "design",
2970
+ voice: "text to speech",
2971
+ wallet: "crypto wallet operations",
2972
+ website: "web development",
2973
+ writing: "content writing",
2974
+ xlsx: "spreadsheet authoring"
2975
+ }
2976
+ };
2977
+ // ../../data/catalogue/skill-nodes-13579.json
2978
+ var skill_nodes_13579_default = {
2979
+ _note: "For the hook's failure record, which reads no network (task 84): the nodes of ARP's testnet tree as written by task 79 (data/catalogue/oasf-tree-13579.json), and the node each skill name is filed at, when the name is filed at one node only. Built by scripts/build/build-skill-nodes.ts from data/catalogue/oasf-skill-tags-proposal-13579.json, rows not reviewed out.",
2980
+ chainId: 13579,
2981
+ oasfVersion: "1.1.0",
2982
+ nodes: [
2983
+ "ad copywriting",
2984
+ "ad creative production",
2985
+ "advertising",
2986
+ "agent application building",
2987
+ "agent evaluation",
2988
+ "agent orchestration",
2989
+ "agent tool building",
2990
+ "agentic workflow orchestration",
2991
+ "ai agent development",
2992
+ "ai safety and guardrails",
2993
+ "ai/ml engineering",
2994
+ "answer engine optimization",
2995
+ "api development",
2996
+ "api schema understanding",
2997
+ "app store release",
2998
+ "architecture patterns",
2999
+ "architecture review",
3000
+ "article and blog writing",
3001
+ "audio & speech processing",
3002
+ "audio generation",
3003
+ "audio to audio",
3004
+ "authentication implementation",
3005
+ "authorization and access control",
3006
+ "benchmark execution",
3007
+ "branding",
3008
+ "browser automation",
3009
+ "build, packaging and dev tooling",
3010
+ "business and professional",
3011
+ "business and professional writing",
3012
+ "business operations",
3013
+ "business strategy",
3014
+ "calendar and scheduling",
3015
+ "campaign planning",
3016
+ "ci/cd configuration",
3017
+ "ci/cd pipelines",
3018
+ "cli and terminal app development",
3019
+ "cloud architecture design",
3020
+ "cloud cost optimization",
3021
+ "cloud networking",
3022
+ "cloud platform operations",
3023
+ "cloud resource management",
3024
+ "code comprehension",
3025
+ "code debugging",
3026
+ "code generation",
3027
+ "code migration and modernization",
3028
+ "code quality and maintenance",
3029
+ "code refactoring and optimization",
3030
+ "code review",
3031
+ "collaboration and communication",
3032
+ "commit authoring",
3033
+ "competitive analysis",
3034
+ "competitive intelligence",
3035
+ "compliance assessment",
3036
+ "computer vision",
3037
+ "configuration management",
3038
+ "container orchestration",
3039
+ "container workload management",
3040
+ "containerization",
3041
+ "content strategy",
3042
+ "content writing",
3043
+ "content, writing and marketing",
3044
+ "context window management",
3045
+ "controllable image generation",
3046
+ "conversion optimization",
3047
+ "copy editing",
3048
+ "copywriting",
3049
+ "crm management",
3050
+ "cross-platform mobile development",
3051
+ "customer support and success",
3052
+ "cybersecurity",
3053
+ "data analytics",
3054
+ "data engineering and analytics",
3055
+ "data modeling",
3056
+ "data modeling and design",
3057
+ "data pipelines",
3058
+ "data visualization",
3059
+ "data warehousing",
3060
+ "databases",
3061
+ "deep learning training",
3062
+ "deep research",
3063
+ "dependency management",
3064
+ "deployment and release management",
3065
+ "deployment orchestration",
3066
+ "design",
3067
+ "dev environment setup",
3068
+ "devops and cloud infrastructure",
3069
+ "document authoring",
3070
+ "document collaboration",
3071
+ "document or database question answering",
3072
+ "document processing",
3073
+ "editing and proofreading",
3074
+ "email campaign creation",
3075
+ "email management",
3076
+ "email marketing",
3077
+ "employee lifecycle",
3078
+ "end-to-end and ui testing",
3079
+ "error handling implementation",
3080
+ "experiment tracking",
3081
+ "face swapping",
3082
+ "frontend development",
3083
+ "full-stack development",
3084
+ "game development",
3085
+ "git workflow",
3086
+ "governance, compliance and ethics",
3087
+ "graph database operations",
3088
+ "growth strategy",
3089
+ "human resources",
3090
+ "iac authoring",
3091
+ "identity administration",
3092
+ "identity and access management",
3093
+ "image editing",
3094
+ "image generation",
3095
+ "image inpainting",
3096
+ "image outpainting",
3097
+ "image to image",
3098
+ "image to video",
3099
+ "incident response",
3100
+ "inference and serving",
3101
+ "infrastructure as code",
3102
+ "instructed image editing",
3103
+ "interactive visualization",
3104
+ "issue tracking",
3105
+ "knowledge base management",
3106
+ "knowledge management",
3107
+ "landing page and sales copy",
3108
+ "language generation",
3109
+ "language processing",
3110
+ "lead generation",
3111
+ "llm evaluation",
3112
+ "llm observability",
3113
+ "llm tracing and instrumentation",
3114
+ "logging and log analysis",
3115
+ "logical reasoning",
3116
+ "market and competitive intelligence",
3117
+ "market research",
3118
+ "marketing copywriting",
3119
+ "marketing strategy",
3120
+ "meeting intelligence",
3121
+ "ml experimentation and lifecycle",
3122
+ "mobile development",
3123
+ "model and agent evaluation",
3124
+ "model fine-tuning",
3125
+ "model serving",
3126
+ "model training and fine-tuning",
3127
+ "monitoring and alerting",
3128
+ "multi-agent coordination",
3129
+ "native mobile development",
3130
+ "network configuration",
3131
+ "nosql database operations",
3132
+ "note-taking",
3133
+ "observability",
3134
+ "observability instrumentation",
3135
+ "office productivity",
3136
+ "orm and data access",
3137
+ "paid ads management",
3138
+ "paper analysis",
3139
+ "pdf manipulation",
3140
+ "performance monitoring",
3141
+ "postmortem authoring",
3142
+ "presentation authoring",
3143
+ "problem solving",
3144
+ "process operations",
3145
+ "product analytics",
3146
+ "product management",
3147
+ "product marketing and gtm",
3148
+ "product strategy",
3149
+ "production llm monitoring",
3150
+ "project and task management",
3151
+ "project scaffolding",
3152
+ "prompt design",
3153
+ "prompt engineering",
3154
+ "prompt optimization",
3155
+ "pull request management",
3156
+ "quality evaluation",
3157
+ "reasoning and planning",
3158
+ "relational database operations",
3159
+ "release management",
3160
+ "requirements and prd authoring",
3161
+ "research and scholarship",
3162
+ "research ideation",
3163
+ "research, knowledge and productivity",
3164
+ "responsible ai governance",
3165
+ "retention management",
3166
+ "retrieval-augmented generation",
3167
+ "roadmapping and prioritization",
3168
+ "role assignment",
3169
+ "root-cause debugging",
3170
+ "runtime guardrails",
3171
+ "sales and crm",
3172
+ "sales enablement",
3173
+ "sales outreach",
3174
+ "script integration",
3175
+ "search engine optimization",
3176
+ "security hardening",
3177
+ "security operations",
3178
+ "seo auditing",
3179
+ "seo content optimization",
3180
+ "serverless and edge computing",
3181
+ "serverless function development",
3182
+ "site reliability engineering",
3183
+ "social content creation",
3184
+ "social media management",
3185
+ "social media marketing",
3186
+ "software architecture and design",
3187
+ "software engineering",
3188
+ "software testing",
3189
+ "specialized application development",
3190
+ "spreadsheet authoring",
3191
+ "static analysis and linting",
3192
+ "stream processing",
3193
+ "structured data markup",
3194
+ "styling and responsive layout",
3195
+ "support operations",
3196
+ "system design",
3197
+ "talking avatar generation",
3198
+ "task decomposition",
3199
+ "task management",
3200
+ "team messaging",
3201
+ "technical writing",
3202
+ "test strategy and tdd",
3203
+ "text paraphrasing",
3204
+ "text style transfer",
3205
+ "text to audio",
3206
+ "text to code",
3207
+ "text to image",
3208
+ "text to video",
3209
+ "third-party integration",
3210
+ "threat detection",
3211
+ "tool use and automation",
3212
+ "tool use planning",
3213
+ "trace analysis and debugging",
3214
+ "ux writing and microcopy",
3215
+ "version control and collaboration",
3216
+ "video",
3217
+ "video editing",
3218
+ "vulnerability analysis",
3219
+ "vulnerability management",
3220
+ "web accessibility",
3221
+ "web animation",
3222
+ "web development",
3223
+ "web search",
3224
+ "web search research",
3225
+ "workflow automation"
3226
+ ],
3227
+ skills: {
3228
+ "ab-test-setup": "product analytics",
3229
+ "ab-testing": "product analytics",
3230
+ "academy-guide": "support operations",
3231
+ "ace-step": "text to audio",
3232
+ "ad-creative": "ad copywriting",
3233
+ adapt: "styling and responsive layout",
3234
+ ads: "paid ads management",
3235
+ "agent-browser": "browser automation",
3236
+ "agent-tools": "script integration",
3237
+ "agents-sdk": "agent application building",
3238
+ "ai-avatar-video": "talking avatar generation",
3239
+ "ai-image-generation": "text to image",
3240
+ "ai-music": "text to audio",
3241
+ "ai-paper-reproduction": "research and scholarship",
3242
+ "ai-research-explore": "research ideation",
3243
+ "ai-research-reproduction": "research and scholarship",
3244
+ "ai-seo": "answer engine optimization",
3245
+ "ai-video-generation": "text to video",
3246
+ "airunway-aks-setup": "model serving",
3247
+ "algorithmic-art": "image generation",
3248
+ analytics: "product analytics",
3249
+ "analytics-tracking": "product analytics",
3250
+ "analyze-project": "code comprehension",
3251
+ "analyze-test-run": "software testing",
3252
+ animate: "web animation",
3253
+ "animate-expo": "web animation",
3254
+ "animation-performance": "web animation",
3255
+ "animation-vocabulary": "web animation",
3256
+ animejs: "web animation",
3257
+ "app-store-screenshots": "app store release",
3258
+ "appinsights-instrumentation": "observability instrumentation",
3259
+ "apple-design": "design",
3260
+ arrange: "design",
3261
+ "ask-matt": "tool use planning",
3262
+ "ask-sonner": "frontend development",
3263
+ aso: "seo auditing",
3264
+ "aso-audit": "seo auditing",
3265
+ attribution: "product analytics",
3266
+ audit: "web accessibility",
3267
+ "azure-ai": "cloud platform operations",
3268
+ "azure-aigateway": "runtime guardrails",
3269
+ "azure-app-onboard": "deployment orchestration",
3270
+ "azure-app-onboard-prereq": "deployment orchestration",
3271
+ "azure-cloud-migrate": "code migration and modernization",
3272
+ "azure-compliance": "compliance assessment",
3273
+ "azure-compute": "cloud resource management",
3274
+ "azure-cost": "cloud cost optimization",
3275
+ "azure-cost-optimization": "cloud cost optimization",
3276
+ "azure-deploy": "deployment orchestration",
3277
+ "azure-diagnostics": "incident response",
3278
+ "azure-enterprise-infra-planner": "cloud architecture design",
3279
+ "azure-hosted-copilot-sdk": "agent application building",
3280
+ "azure-kubernetes": "container workload management",
3281
+ "azure-kusto": "logging and log analysis",
3282
+ "azure-kusto-graph": "graph database operations",
3283
+ "azure-kusto-irql": "threat detection",
3284
+ "azure-kusto-irql-graph": "interactive visualization",
3285
+ "azure-messaging": "code debugging",
3286
+ "azure-observability": "observability",
3287
+ "azure-postgres": "relational database operations",
3288
+ "azure-prepare": "iac authoring",
3289
+ "azure-quotas": "cloud resource management",
3290
+ "azure-rbac": "authorization and access control",
3291
+ "azure-reliability": "site reliability engineering",
3292
+ "azure-resource-lookup": "cloud resource management",
3293
+ "azure-resource-visualizer": "cloud architecture design",
3294
+ "azure-storage": "cloud resource management",
3295
+ "azure-upgrade": "code migration and modernization",
3296
+ "azure-validate": "ci/cd configuration",
3297
+ basin: "data warehousing",
3298
+ "batch-grill-me": "problem solving",
3299
+ bolder: "design",
3300
+ brainstorming: "reasoning and planning",
3301
+ "brand-guidelines": "branding",
3302
+ "break-ui": "end-to-end and ui testing",
3303
+ "building-ai-agent-on-cloudflare": "agent application building",
3304
+ "building-mcp-server-on-cloudflare": "agent tool building",
3305
+ "canopy-part-title": "video editing",
3306
+ "canvas-design": "image generation",
3307
+ "captions-overlay": "video editing",
3308
+ cavecrew: "role assignment",
3309
+ caveman: "text style transfer",
3310
+ "caveman-commit": "commit authoring",
3311
+ "caveman-compress": "context window management",
3312
+ "caveman-discover": "llm tracing and instrumentation",
3313
+ "caveman-es": "text style transfer",
3314
+ "caveman-evidence-review": "trace analysis and debugging",
3315
+ "caveman-explore": "code comprehension",
3316
+ "caveman-help": "text style transfer",
3317
+ "caveman-learn": "prompt optimization",
3318
+ "caveman-manage": "release management",
3319
+ "caveman-optimize": "llm evaluation",
3320
+ "caveman-review": "code review",
3321
+ "caveman-setup": "llm tracing and instrumentation",
3322
+ "caveman-stats": "production llm monitoring",
3323
+ "cf-cli": "cloud resource management",
3324
+ "changelog-video": "video editing",
3325
+ "character-design-sheet": "controllable image generation",
3326
+ "chief-of-staff": "agentic workflow orchestration",
3327
+ "churn-prevention": "retention management",
3328
+ clarify: "ux writing and microcopy",
3329
+ "claude-api": "third-party integration",
3330
+ "claude-design-hyperframes": "video editing",
3331
+ "claude-handoff": "multi-agent coordination",
3332
+ cloudflare: "cloud architecture design",
3333
+ "cloudflare-email-service": "third-party integration",
3334
+ "cloudflare-one": "network configuration",
3335
+ "cloudflare-one-migrations": "network configuration",
3336
+ "co-marketing": "campaign planning",
3337
+ "code-review": "code review",
3338
+ "code-slice-hero": "video editing",
3339
+ "codebase-design": "architecture patterns",
3340
+ "codex-pet": "image to image",
3341
+ "cold-email": "sales outreach",
3342
+ colorize: "design",
3343
+ "community-marketing": "growth strategy",
3344
+ "competitor-alternatives": "landing page and sales copy",
3345
+ "competitor-profiling": "competitive intelligence",
3346
+ "competitor-teardown": "competitive analysis",
3347
+ competitors: "landing page and sales copy",
3348
+ compress: "context window management",
3349
+ "content-strategy": "content strategy",
3350
+ "contribute-catalog": "video editing",
3351
+ "controlnet-pose": "image to video",
3352
+ "conversion-tracking": "product analytics",
3353
+ "copy-editing": "copy editing",
3354
+ copywriting: "marketing copywriting",
3355
+ critique: "design",
3356
+ cro: "conversion optimization",
3357
+ "css-animations": "web animation",
3358
+ "cuboid-carousel": "video editing",
3359
+ "customer-research": "market research",
3360
+ "cut-the-curve": "video editing",
3361
+ "decision-mapping": "task decomposition",
3362
+ delight: "design",
3363
+ "deploy-to-vercel": "deployment orchestration",
3364
+ "design-an-interface": "system design",
3365
+ "design-mobile-apps": "design",
3366
+ "design-taste-frontend": "design",
3367
+ "design-taste-frontend-v1": "design",
3368
+ "design-taste-frontend-v2-experimental": "design",
3369
+ "developing-genkit-dart": "agent application building",
3370
+ "developing-genkit-go": "agent application building",
3371
+ "developing-genkit-js": "agent application building",
3372
+ "developing-genkit-python": "agent application building",
3373
+ diagnose: "root-cause debugging",
3374
+ "diagnosing-bugs": "root-cause debugging",
3375
+ "diagnosing-superpowers": "trace analysis and debugging",
3376
+ "directory-submissions": "search engine optimization",
3377
+ "discernment-nudge": "responsible ai governance",
3378
+ "discover-azure-skills": "tool use planning",
3379
+ "dispatching-parallel-agents": "multi-agent coordination",
3380
+ distill: "design",
3381
+ "doc-coauthoring": "technical writing",
3382
+ docx: "document authoring",
3383
+ "domain-modeling": "data modeling",
3384
+ "durable-objects": "serverless function development",
3385
+ "edit-article": "editing and proofreading",
3386
+ "elevenlabs-music-generation": "text to audio",
3387
+ "email-sequence": "email campaign creation",
3388
+ emails: "email campaign creation",
3389
+ "embedded-captions": "video editing",
3390
+ "emil-design-eng": "design",
3391
+ "entra-agent-id": "identity administration",
3392
+ "entra-app-registration": "authentication implementation",
3393
+ "env-and-assets-bootstrap": "dev environment setup",
3394
+ events: "campaign planning",
3395
+ "executing-plans": "task management",
3396
+ "explore-code": "deep learning training",
3397
+ "explore-run": "experiment tracking",
3398
+ "extension-to-functions-codebase": "code migration and modernization",
3399
+ extract: "design",
3400
+ "face-swap": "face swapping",
3401
+ "faceless-explainer": "text to video",
3402
+ figma: "video editing",
3403
+ "file-test-bug": "issue tracking",
3404
+ "find-animation-opportunities": "web animation",
3405
+ "find-skills": "tool use planning",
3406
+ "finishing-a-development-branch": "git workflow",
3407
+ "firebase-ai-logic": "third-party integration",
3408
+ "firebase-ai-logic-basics": "third-party integration",
3409
+ "firebase-app-hosting-basics": "deployment orchestration",
3410
+ "firebase-auth-basics": "authentication implementation",
3411
+ "firebase-basics": "dev environment setup",
3412
+ "firebase-crashlytics": "monitoring and alerting",
3413
+ "firebase-data-connect": "relational database operations",
3414
+ "firebase-firestore": "nosql database operations",
3415
+ "firebase-firestore-basics": "nosql database operations",
3416
+ "firebase-firestore-enterprise-native-mode": "nosql database operations",
3417
+ "firebase-firestore-standard": "nosql database operations",
3418
+ "firebase-hosting-basics": "deployment orchestration",
3419
+ "firebase-local-env-setup": "dev environment setup",
3420
+ "firebase-remote-config-basics": "configuration management",
3421
+ "firebase-security-rules-auditor": "vulnerability analysis",
3422
+ "firestore-rules-creation": "authorization and access control",
3423
+ "firestore-security-rules-auditor": "vulnerability analysis",
3424
+ "flux-2-klein": "text to image",
3425
+ "flux-kontext": "instructed image editing",
3426
+ "form-cro": "conversion optimization",
3427
+ "free-tool-strategy": "growth strategy",
3428
+ "free-tools": "growth strategy",
3429
+ "frontend-design": "design",
3430
+ "frost-sequence-camera-orbit": "video editing",
3431
+ "full-output-enforcement": "prompt design",
3432
+ "gateway-workers": "serverless function development",
3433
+ "general-video": "video editing",
3434
+ "git-guardrails-claude-code": "git workflow",
3435
+ "glass-shard-title": "video editing",
3436
+ "google-agents-cli-adk-code": "agent application building",
3437
+ "google-agents-cli-deploy": "deployment orchestration",
3438
+ "google-agents-cli-eval": "agent evaluation",
3439
+ "google-agents-cli-observability": "llm tracing and instrumentation",
3440
+ "google-agents-cli-publish": "release management",
3441
+ "google-agents-cli-scaffold": "project scaffolding",
3442
+ "google-agents-cli-workflow": "agent application building",
3443
+ "gpt-image": "text to image",
3444
+ "gpt-image-2": "text to image",
3445
+ "gpt-image-edit": "instructed image editing",
3446
+ "gpt-taste": "design",
3447
+ "graphic-overlays": "video editing",
3448
+ "grill-me": "problem solving",
3449
+ "grill-with-docs": "problem solving",
3450
+ grilling: "problem solving",
3451
+ gsap: "web animation",
3452
+ handoff: "context window management",
3453
+ happyhorse: "text to video",
3454
+ "happyhorse-1-0": "text to video",
3455
+ harden: "error handling implementation",
3456
+ "higgsfield-brandkit": "branding",
3457
+ "higgsfield-faceless-video": "text to video",
3458
+ "higgsfield-game-generation": "game development",
3459
+ "higgsfield-generate": "text to image",
3460
+ "higgsfield-marketplace-cards": "ad creative production",
3461
+ "higgsfield-product-photoshoot": "text to image",
3462
+ "higgsfield-soul-id": "model fine-tuning",
3463
+ "higgsfield-websites": "full-stack development",
3464
+ "higgsfield-youtube-thumbnail": "text to image",
3465
+ "high-end-visual-design": "design",
3466
+ hyperframes: "video",
3467
+ "hyperframes-animation": "web animation",
3468
+ "hyperframes-audio": "audio to audio",
3469
+ "hyperframes-cli": "video editing",
3470
+ "hyperframes-core": "video editing",
3471
+ "hyperframes-creative": "video editing",
3472
+ "hyperframes-keyframes": "video editing",
3473
+ "hyperframes-media": "audio generation",
3474
+ "hyperframes-read-first": "video",
3475
+ "hyperframes-registry": "video editing",
3476
+ "hyperframes-studio": "video editing",
3477
+ image: "image generation",
3478
+ "image-edit": "instructed image editing",
3479
+ "image-inpainting": "image inpainting",
3480
+ "image-outpainting": "image outpainting",
3481
+ "image-taste-frontend": "design",
3482
+ "image-to-video": "image to video",
3483
+ impeccable: "design",
3484
+ implement: "text to code",
3485
+ "implement-spec": "text to code",
3486
+ "improve-animations": "web animation",
3487
+ "improve-codebase-architecture": "architecture review",
3488
+ "industrial-brutalist-ui": "design",
3489
+ "influencer-marketing": "campaign planning",
3490
+ "infsh-cli": "script integration",
3491
+ "internal-comms": "business and professional writing",
3492
+ "investigate-first": "root-cause debugging",
3493
+ k2: "stream processing",
3494
+ "kling-3-0": "text to video",
3495
+ "landing-page-design": "conversion optimization",
3496
+ "lark-approval": "process operations",
3497
+ "lark-apps": "full-stack development",
3498
+ "lark-attendance": "employee lifecycle",
3499
+ "lark-base": "spreadsheet authoring",
3500
+ "lark-calendar": "calendar and scheduling",
3501
+ "lark-contact": "team messaging",
3502
+ "lark-doc": "document collaboration",
3503
+ "lark-drive": "document collaboration",
3504
+ "lark-event": "workflow automation",
3505
+ "lark-im": "team messaging",
3506
+ "lark-mail": "email management",
3507
+ "lark-markdown": "document collaboration",
3508
+ "lark-meeting": "meeting intelligence",
3509
+ "lark-minutes": "meeting intelligence",
3510
+ "lark-note": "meeting intelligence",
3511
+ "lark-okr": "roadmapping and prioritization",
3512
+ "lark-openapi-explorer": "api schema understanding",
3513
+ "lark-shared": "authentication implementation",
3514
+ "lark-sheets": "spreadsheet authoring",
3515
+ "lark-skill-maker": "agent tool building",
3516
+ "lark-slides": "presentation authoring",
3517
+ "lark-task": "task management",
3518
+ "lark-vc": "meeting intelligence",
3519
+ "lark-vc-agent": "meeting intelligence",
3520
+ "lark-whiteboard": "document collaboration",
3521
+ "lark-whiteboard-cli": "document collaboration",
3522
+ "lark-wiki": "knowledge base management",
3523
+ "lark-workflow-meeting-summary": "meeting intelligence",
3524
+ "lark-workflow-standup-report": "task management",
3525
+ launch: "product marketing and gtm",
3526
+ "launch-strategy": "product marketing and gtm",
3527
+ layout: "design",
3528
+ "lead-magnets": "lead generation",
3529
+ "lean-build": "text to code",
3530
+ "link-building": "search engine optimization",
3531
+ lipsync: "talking avatar generation",
3532
+ "loop-me": "requirements and prd authoring",
3533
+ lottie: "web animation",
3534
+ "markdown-token-optimizer": "context window management",
3535
+ "marketing-council": "marketing strategy",
3536
+ "marketing-ideas": "growth strategy",
3537
+ "marketing-loops": "workflow automation",
3538
+ "marketing-plan": "marketing strategy",
3539
+ "marketing-psychology": "marketing strategy",
3540
+ "mcp-builder": "agent tool building",
3541
+ "media-use": "video",
3542
+ mediabunny: "video",
3543
+ megacave: "text style transfer",
3544
+ "microsoft-foundry": "agent application building",
3545
+ "migrate-to-shoehorn": "code migration and modernization",
3546
+ migration: "code migration and modernization",
3547
+ "minimal-run-and-audit": "benchmark execution",
3548
+ "minimalist-ui": "design",
3549
+ "mobile-native": "styling and responsive layout",
3550
+ "motion-doctrine": "video editing",
3551
+ "motion-graphics": "video editing",
3552
+ "music-to-video": "video editing",
3553
+ "nano-banana-2": "text to image",
3554
+ "nano-banana-edit": "instructed image editing",
3555
+ "nextjs-on-cloudflare": "deployment orchestration",
3556
+ normalize: "design",
3557
+ "obsidian-vault": "note-taking",
3558
+ offers: "product marketing and gtm",
3559
+ onboard: "design",
3560
+ onboarding: "conversion optimization",
3561
+ "onboarding-cro": "conversion optimization",
3562
+ optimize: "code refactoring and optimization",
3563
+ "orbit-card": "video editing",
3564
+ overdrive: "web animation",
3565
+ "oversized-cursor": "video editing",
3566
+ "p-image": "text to image",
3567
+ "p-video": "text to video",
3568
+ "p-video-avatar": "talking avatar generation",
3569
+ "page-cro": "conversion optimization",
3570
+ "paid-ads": "paid ads management",
3571
+ "paper-context-resolver": "paper analysis",
3572
+ "paywall-upgrade-cro": "conversion optimization",
3573
+ paywalls: "conversion optimization",
3574
+ pdf: "pdf manipulation",
3575
+ "pick-ui-library": "frontend development",
3576
+ polish: "design",
3577
+ "popup-cro": "conversion optimization",
3578
+ popups: "conversion optimization",
3579
+ pptx: "presentation authoring",
3580
+ pr: "pull request management",
3581
+ "pr-to-video": "video editing",
3582
+ pricing: "product strategy",
3583
+ "pricing-strategy": "product strategy",
3584
+ "prisma-cli": "orm and data access",
3585
+ "prisma-client-api": "orm and data access",
3586
+ "prisma-compute": "deployment orchestration",
3587
+ "prisma-database-setup": "orm and data access",
3588
+ "prisma-driver-adapter-implementation": "orm and data access",
3589
+ "prisma-mongodb-upgrade": "code migration and modernization",
3590
+ "prisma-orm-setup": "orm and data access",
3591
+ "prisma-postgres": "relational database operations",
3592
+ "prisma-postgres-setup": "relational database operations",
3593
+ "prisma-upgrade-v7": "code migration and modernization",
3594
+ "product-hunt-launch": "product marketing and gtm",
3595
+ "product-launch-video": "ad creative production",
3596
+ "product-marketing": "product marketing and gtm",
3597
+ "product-marketing-context": "product marketing and gtm",
3598
+ "product-photography": "text to image",
3599
+ "programmatic-seo": "seo content optimization",
3600
+ prospecting: "lead generation",
3601
+ "public-relations": "marketing strategy",
3602
+ "python-appservice-deploy": "deployment orchestration",
3603
+ "python-executor": "script integration",
3604
+ qa: "issue tracking",
3605
+ quieter: "design",
3606
+ "receiving-code-review": "code review",
3607
+ "reddit-automation": "social content creation",
3608
+ "redesign-existing-projects": "design",
3609
+ "referral-program": "growth strategy",
3610
+ referrals: "growth strategy",
3611
+ relight: "instructed image editing",
3612
+ "remotion-best-practices": "video",
3613
+ "remotion-captions": "video editing",
3614
+ "remotion-create": "video",
3615
+ "remotion-docs": "document or database question answering",
3616
+ "remotion-interactivity": "video",
3617
+ "remotion-maps": "video",
3618
+ "remotion-markup": "video",
3619
+ "remotion-multimedia": "video",
3620
+ "remotion-render": "video",
3621
+ "remotion-saas": "full-stack development",
3622
+ "remotion-studio": "video",
3623
+ "remotion-to-hyperframes": "code migration and modernization",
3624
+ "remotion-upgrade": "dependency management",
3625
+ "remove-animations": "web animation",
3626
+ "repo-intake-and-plan": "code comprehension",
3627
+ "request-refactor-plan": "code refactoring and optimization",
3628
+ "requesting-code-review": "code review",
3629
+ research: "deep research",
3630
+ "resolving-merge-conflicts": "git workflow",
3631
+ retro: "postmortem authoring",
3632
+ review: "code review",
3633
+ "review-animations": "web animation",
3634
+ revops: "crm management",
3635
+ "run-train": "deep learning training",
3636
+ "runcomfy-cli": "script integration",
3637
+ "safe-debug": "root-cause debugging",
3638
+ "safe-refactor": "code refactoring and optimization",
3639
+ "sales-enablement": "sales enablement",
3640
+ "sandbox-migrate-to-next": "code migration and modernization",
3641
+ "sandbox-next": "containerization",
3642
+ "sandbox-sdk": "containerization",
3643
+ "sandbox-stable": "containerization",
3644
+ "scaffold-exercises": "project scaffolding",
3645
+ schema: "structured data markup",
3646
+ "schema-markup": "structured data markup",
3647
+ "seam-craft": "video editing",
3648
+ seedance: "text to video",
3649
+ "seedance-v2": "text to video",
3650
+ sensei: "agent tool building",
3651
+ "seo-audit": "seo auditing",
3652
+ "setup-matt-pocock-skills": "dev environment setup",
3653
+ "setup-pre-commit": "dev environment setup",
3654
+ "setup-ts-deep-modules": "static analysis and linting",
3655
+ shape: "design",
3656
+ signup: "conversion optimization",
3657
+ "signup-flow-cro": "conversion optimization",
3658
+ "site-architecture": "search engine optimization",
3659
+ "skill-authoring": "agent tool building",
3660
+ "skill-creator": "agent tool building",
3661
+ "slack-gif-creator": "image generation",
3662
+ slideshow: "presentation authoring",
3663
+ sms: "email marketing",
3664
+ social: "social media management",
3665
+ "social-content": "social content creation",
3666
+ "stitch-design-taste": "design",
3667
+ "storyboard-creation": "video",
3668
+ "subagent-driven-development": "agentic workflow orchestration",
3669
+ "surgical-patch": "root-cause debugging",
3670
+ "systematic-debugging": "root-cause debugging",
3671
+ tailwind: "styling and responsive layout",
3672
+ "talking-head-recut": "video editing",
3673
+ tdd: "test strategy and tdd",
3674
+ teach: "research and scholarship",
3675
+ "template-skill": "agent tool building",
3676
+ "test-driven-development": "test strategy and tdd",
3677
+ "theme-factory": "design",
3678
+ three: "web animation",
3679
+ "to-issues": "issue tracking",
3680
+ "to-prd": "requirements and prd authoring",
3681
+ "to-questionnaire": "reasoning and planning",
3682
+ "to-spec": "requirements and prd authoring",
3683
+ "to-tickets": "issue tracking",
3684
+ triage: "issue tracking",
3685
+ "turnstile-spin": "security hardening",
3686
+ "twitter-automation": "social media management",
3687
+ typegpu: "web animation",
3688
+ typeset: "design",
3689
+ "ubiquitous-language": "data modeling",
3690
+ ultracave: "text style transfer",
3691
+ "using-git-worktrees": "git workflow",
3692
+ "using-superpowers": "tool use planning",
3693
+ "vercel-cli-with-tokens": "deployment orchestration",
3694
+ "vercel-composition-patterns": "frontend development",
3695
+ "vercel-deploy": "deployment orchestration",
3696
+ "vercel-optimize": "cloud cost optimization",
3697
+ "vercel-react-best-practices": "code refactoring and optimization",
3698
+ "vercel-react-native-skills": "cross-platform mobile development",
3699
+ "vercel-react-view-transitions": "web animation",
3700
+ "verification-before-completion": "quality evaluation",
3701
+ "verify-and-stop": "software testing",
3702
+ video: "video",
3703
+ "video-ad-specs": "ad creative production",
3704
+ "video-edit": "video editing",
3705
+ "video-extend": "video editing",
3706
+ "video-inpainting": "video editing",
3707
+ "video-outpainting": "video editing",
3708
+ waapi: "web animation",
3709
+ "wait-what": "text paraphrasing",
3710
+ "wan-2-7": "text to video",
3711
+ wayfinder: "task decomposition",
3712
+ "web-artifacts-builder": "frontend development",
3713
+ "web-design-guidelines": "design",
3714
+ "web-perf": "code refactoring and optimization",
3715
+ "web-search": "web search research",
3716
+ "webapp-testing": "end-to-end and ui testing",
3717
+ "website-to-hyperframes": "video editing",
3718
+ "website-to-video": "video editing",
3719
+ "wireframe-portal-title": "video editing",
3720
+ wizard: "cli and terminal app development",
3721
+ "workers-best-practices": "serverless function development",
3722
+ "workers-profiling": "performance monitoring",
3723
+ wrangler: "deployment orchestration",
3724
+ "write-a-skill": "agent tool building",
3725
+ "write-swift": "native mobile development",
3726
+ "writing-beats": "content writing",
3727
+ "writing-for-agents": "technical writing",
3728
+ "writing-fragments": "content writing",
3729
+ "writing-great-skills": "agent tool building",
3730
+ "writing-guidelines": "copy editing",
3731
+ "writing-plans": "task decomposition",
3732
+ "writing-shape": "article and blog writing",
3733
+ "writing-skills": "agent tool building",
3734
+ "xcode-project-setup": "dependency management",
3735
+ xlsx: "spreadsheet authoring",
3736
+ "youtube-thumbnail-design": "image generation",
3737
+ "zoom-out": "code comprehension"
3738
+ }
3739
+ };
3740
+
3741
+ // ../hook/src/skill-failure.ts
3742
+ var MISSING_KEY = /\b(api[ _-]?key|access[ _-]?token|credentials?)\b.{0,40}\b(missing|not set|not found|required|invalid|expired)\b|(?<!\bnot )\b(missing|no|invalid|expired)\b.{0,20}\b(api[ _-]?key|access[ _-]?token|credentials?)\b|\b(HTTP|status)(\/[\d.]+| code)?[ :=]*(401|403)\b|\b(401|403) (unauthori[sz]ed|forbidden)\b|\bunauthori[sz]ed\b|not authenticated|not logged in/i;
3743
+ var MISSING_KEY_VARIABLE = /\b[A-Z0-9_]*(API_KEY|TOKEN|SECRET)\b.{0,30}\b(not set|missing|required|unset)\b/;
3744
+ var MISSING_PROGRAM = /command not found|executable file not found|\bnot installed\b|No module named|spawn \S+ ENOENT|Cannot find module/i;
3745
+ var MISSING_FILE = /No such file or directory|\bENOENT\b|file not found|\b(file|path|directory|folder)\b(?!\.).{0,80}\bdoes not exist\b/i;
3746
+ function failureReason(text) {
3747
+ if (MISSING_PROGRAM.test(text))
3748
+ return "missing-program";
3749
+ if (MISSING_KEY.test(text) || MISSING_KEY_VARIABLE.test(text))
3750
+ return "missing-key";
3751
+ if (MISSING_FILE.test(text))
3752
+ return "missing-file";
3753
+ return null;
3754
+ }
3755
+ var PROGRAM_IN_ERROR = [
3756
+ /command not found: ([^\s'"`]+)/gi,
3757
+ /(?:^|[\s:])([^\s:'"`]+): (?:command )?not found\b/gim,
3758
+ /\bexec(?:utable)?:? "?([^\s"]+)"?: executable file not found/gi,
3759
+ /\bspawn ([^\s'"`]+) ENOENT\b/gi,
3760
+ /No module named '?([A-Za-z0-9_.-]+)'?/g,
3761
+ /Cannot find module '([^']+)'/g,
3762
+ /(?:^|\s)'?([^\s'"`]+)'? is not installed\b/gim
3763
+ ];
3764
+ var KEY_IN_ERROR = [
3765
+ /\b([A-Z][A-Z0-9_]{2,63})\b[^=\n]{0,30}\b(?:not set|missing|required|unset|is empty)\b/g,
3766
+ /\b(?:set|export|provide|missing|define)\s+(?:the\s+)?(?:environment variable\s+)?\$?([A-Z][A-Z0-9_]{2,63})\b/gi,
3767
+ /\$?\b([A-Z][A-Z0-9_]*(?:API_KEY|TOKEN|SECRET|ACCESS_KEY)[A-Z0-9_]*)\b/g
3768
+ ];
3769
+ function needOf(reason, text, markdown) {
3770
+ const kind = reason === "missing-program" ? "program" : reason === "missing-key" ? "key" : null;
3771
+ if (kind === null)
3772
+ return null;
3773
+ for (const pattern of kind === "program" ? PROGRAM_IN_ERROR : KEY_IN_ERROR) {
3774
+ for (const match of text.matchAll(pattern)) {
3775
+ const named = match[1] ?? "";
3776
+ const name = kind === "program" ? (named.split("/").pop() ?? "").toLowerCase() : named;
3777
+ if (!/[a-z]/i.test(name))
3778
+ continue;
3779
+ const kept = publishableNeed3(name, markdown, kind);
3780
+ if (kept !== null)
3781
+ return kept;
3782
+ }
3783
+ }
3784
+ return null;
3785
+ }
3786
+ var RUNNERS2 = new Set(["bash", "bun", "bunx", "node", "npx", "python", "python3", "sh", "uv", "uvx", "zsh"]);
3787
+ function programsOf(command) {
3788
+ const found = [];
3789
+ for (const part of command.split(/&&|\|\||[;|\n]/)) {
3790
+ const words = part.trim().split(/\s+/).filter((word) => !/^[A-Za-z_][A-Za-z0-9_]*=/.test(word));
3791
+ const first2 = words[0];
3792
+ if (first2 === undefined || first2 === "")
3793
+ continue;
3794
+ const program = first2.split("/").pop() ?? first2;
3795
+ if (!RUNNERS2.has(program)) {
3796
+ found.push(program);
3797
+ continue;
3798
+ }
3799
+ const target = words.slice(1).find((word) => !word.startsWith("-") && word !== "run");
3800
+ if (target !== undefined)
3801
+ found.push(target.split("/").pop() ?? target);
3802
+ }
3803
+ return found;
3804
+ }
3805
+ var escaped2 = (text) => text.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
3806
+ function askedBySkill(command, markdown, directory) {
3807
+ if (new RegExp(`${escaped2(directory)}(?=[/\\s'"]|$)`).test(command))
3808
+ return true;
3809
+ const { cli, runs } = readRequires(markdown);
3810
+ const named = new Set([...cli, ...runs]);
3811
+ return programsOf(command).some((program) => named.has(program) || program.includes(".") && new RegExp(`(?:^|[\\s\`'"/(])${escaped2(program)}(?=[\\s\`'")]|$)`, "m").test(markdown));
3812
+ }
3813
+ var NODES = skill_nodes_13579_default.nodes;
3814
+ var WORDS = { labels: NODES, aliases: domain_aliases_default.aliases };
3815
+ var SKILL_NODE = skill_nodes_13579_default.skills;
3816
+ function lastUserWords(transcript) {
3817
+ let words = "";
3818
+ for (const line of transcript.split(`
3819
+ `)) {
3820
+ if (!line.includes('"user"'))
3821
+ continue;
3822
+ try {
3823
+ const entry = JSON.parse(line);
3824
+ if (entry.type !== "user" || entry.isMeta === true)
3825
+ continue;
3826
+ const content = entry.message?.content;
3827
+ const text = typeof content === "string" ? content : Array.isArray(content) ? content.map((block) => block?.type === "text" && typeof block.text === "string" ? block.text : "").join(" ") : "";
3828
+ if (text.trim() !== "" && !text.trimStart().startsWith("<"))
3829
+ words = text;
3830
+ } catch {
3831
+ continue;
3832
+ }
3833
+ }
3834
+ return words;
3835
+ }
3836
+ function contextOf(words, skill) {
3837
+ return domainInText2(words, WORDS) ?? SKILL_NODE[skill.split(":").pop() ?? skill] ?? null;
3838
+ }
3839
+ function answerOf(response) {
3840
+ const blocks = Array.isArray(response) ? response : typeof response === "object" && response !== null && Array.isArray(response.content) ? response.content : [response];
3841
+ for (const block of blocks) {
3842
+ const text = typeof block === "string" ? block : block?.text;
3843
+ if (typeof text !== "string")
3844
+ continue;
3845
+ try {
3846
+ const parsed = JSON.parse(text);
3847
+ if (typeof parsed === "object" && parsed !== null)
3848
+ return parsed;
3849
+ } catch {
3850
+ continue;
3851
+ }
3852
+ }
3853
+ return null;
3854
+ }
3855
+ var searchesPath = (cwd) => join3(dirname2(process.env["ARP_SESSION_LOG"] ?? join3(cwd, ".arp", "session.jsonl")), "searches.jsonl");
3856
+ function recordSearch(call, cwd) {
3857
+ if (call.session === null)
3858
+ return;
3859
+ const answer = answerOf(call.response);
3860
+ if (answer === null || !Array.isArray(answer["skills"]))
3861
+ return;
3862
+ const domain = typeof answer["domain"] === "string" && NODES.includes(answer["domain"]) ? answer["domain"] : null;
3863
+ const skills = answer["skills"].flatMap((row) => typeof row?.name === "string" && typeof row.source === "string" ? [{ name: row.name, source: row.source }] : []);
3864
+ if (skills.length === 0)
3865
+ return;
3866
+ try {
3867
+ const path = searchesPath(cwd);
3868
+ mkdirSync2(dirname2(path), { recursive: true });
3869
+ appendOwn(path, `${JSON.stringify({ session: call.session, domain, skills })}
3870
+ `);
3871
+ } catch {}
3872
+ }
3873
+ function foundBySearch(cwd, session, skill) {
3874
+ const path = searchesPath(cwd);
3875
+ if (!existsSync(path))
3876
+ return null;
3877
+ const name = skill.split(":").pop() ?? skill;
3878
+ let found = null;
3879
+ for (const line of readFileSync2(path, "utf8").split(`
3880
+ `)) {
3881
+ try {
3882
+ const row = JSON.parse(line);
3883
+ if (row.session !== session)
3884
+ continue;
3885
+ const hit = row.skills?.find((entry) => entry.name === name);
3886
+ if (hit !== undefined)
3887
+ found = { domain: typeof row.domain === "string" ? row.domain : null, source: hit.source };
3888
+ } catch {
3889
+ continue;
3890
+ }
3891
+ }
3892
+ return found;
3893
+ }
3894
+ var readIfThere = (path) => existsSync(path) ? readFileSync2(path, "utf8") : null;
3895
+ function installedSource(name, cwd) {
3896
+ const known = [
3897
+ ...installedFromSkillLock(readIfThere(join3(homedir2(), ".agents", ".skill-lock.json"))),
3898
+ ...installedFromSkillLock(readIfThere(join3(cwd, "skills-lock.json"))),
3899
+ ...installedFromReceipts(readIfThere(join3(arpHome(), "receipts.jsonl"))),
3900
+ ...installedFromReceipts(readIfThere(join3(cwd, ".arp", "receipts.jsonl")))
3901
+ ];
3902
+ const sources = new Set(known.filter((entry) => entry.skill === name).map((entry) => entry.source));
3903
+ return sources.size === 1 ? [...sources][0] ?? null : null;
3904
+ }
3905
+ function skillsOfSession(log, session) {
3906
+ if (!existsSync(log))
3907
+ return [];
3908
+ const skills = [];
3909
+ for (const line of readFileSync2(log, "utf8").split(`
3910
+ `)) {
3911
+ try {
3912
+ const row = JSON.parse(line);
3913
+ if (row["kind"] === "skill" && row["session"] === session && typeof row["name"] === "string") {
3914
+ skills.unshift({
3915
+ name: row["name"],
3916
+ source: typeof row["source"] === "string" ? row["source"] : null
3917
+ });
3918
+ }
3919
+ } catch {}
3920
+ }
3921
+ return skills;
3922
+ }
3923
+ function skillDirectory(name, cwd) {
3924
+ const roots = [join3(cwd, ".claude", "skills"), join3(homedir2(), ".claude", "skills")];
3925
+ const given = process.env["ARP_SKILLS_DIR"];
3926
+ if (given !== undefined && given !== "")
3927
+ roots.unshift(given);
3928
+ return roots.map((root) => join3(root, name)).find((dir) => existsSync(join3(dir, "SKILL.md"))) ?? null;
3929
+ }
3930
+ function arpHome() {
3931
+ const given = process.env["ARP_HOME"]?.trim();
3932
+ return given !== undefined && given !== "" ? given : join3(homedir2(), ".arp");
3933
+ }
3934
+ function appendFailure(line) {
3935
+ const path = join3(arpHome(), "failures.jsonl");
3936
+ const seen = existsSync(path) ? readFileSync2(path, "utf8") : "";
3937
+ const key = `"session":${JSON.stringify(line.session)},"skill":${JSON.stringify(line.skill)},`;
3938
+ if (seen.split(`
3939
+ `).some((row) => row.includes(key) && row.includes(`"reason":"${line.reason}"`)))
3940
+ return false;
3941
+ mkdirSync2(dirname2(path), { recursive: true });
3942
+ appendOwn(path, `${JSON.stringify(line)}
3943
+ `);
3944
+ return true;
3945
+ }
3946
+ function recordSkillFailure(call, cwd) {
3947
+ const classified = classifyCall(call);
3948
+ if (classified === null || classified.outcome === "ok" || call.session === null)
3949
+ return null;
3950
+ const command = call.input?.["command"];
3951
+ if (typeof command !== "string")
3952
+ return null;
3953
+ const reason = failureReason(failureText(call));
3954
+ if (reason === null)
3955
+ return null;
3956
+ try {
3957
+ const log = process.env["ARP_SESSION_LOG"] ?? join3(cwd, ".arp", "session.jsonl");
3958
+ for (const skill of skillsOfSession(log, call.session)) {
3959
+ const directory = skillDirectory(skill.name, cwd);
3960
+ if (directory === null)
3961
+ continue;
3962
+ const markdown = readFileSync2(join3(directory, "SKILL.md"), "utf8");
3963
+ if (!askedBySkill(command, markdown, directory))
3964
+ continue;
3965
+ const search = foundBySearch(cwd, call.session, skill.name);
3966
+ const words = call.transcript !== null && existsSync(call.transcript) ? lastUserWords(readFileSync2(call.transcript, "utf8")) : "";
3967
+ const domain = search?.domain ?? contextOf(words, skill.name);
3968
+ const need = needOf(reason, failureText(call), markdown);
3969
+ const line = {
3970
+ at: new Date().toISOString(),
3971
+ session: call.session,
3972
+ skill: skill.name,
3973
+ source: skill.source ?? search?.source ?? installedSource(skill.name.split(":").pop() ?? skill.name, cwd),
3974
+ ...domain === null ? {} : { domain },
3975
+ reason,
3976
+ ...need === null ? {} : { need }
3977
+ };
3978
+ return appendFailure(line) ? line : null;
3979
+ }
3980
+ } catch {}
3981
+ return null;
3982
+ }
3983
+
3984
+ // ../hook/src/failure-answer.ts
3985
+ var ANSWER_MS = 3000;
3986
+ var WHERE = "Intuition testnet 13579";
3987
+ var IN_CONTEXT_OF = _13579_default.arp.endpointBinding.inContextOf;
3988
+ var PAYERS = [_13579_default.arp.deployer, _13579_default.arp.sponsor];
3989
+ var sha256 = (text) => createHash("sha256").update(text, "utf8").digest();
3990
+ async function answerFailure(failure, env = process.env, fetcher) {
3991
+ if (env["ARP_FAILURE_LINES"] === "off" || failure.source === null)
3992
+ return null;
3993
+ const url = skillUrlOf2(failure.source, failure.skill);
3994
+ if (url === null)
3995
+ return null;
3996
+ const { uri, label } = skillAtom(url, sha256);
3997
+ const graphqlUrl = env["INTUITION_GRAPHQL_URL"] ?? _13579_default.chain.graphqlUrl;
3998
+ let timer;
3999
+ const late = new Promise((resolve) => {
4000
+ timer = setTimeout(() => resolve(null), ANSWER_MS);
4001
+ });
4002
+ const read = readSkillLines(uri, {
4003
+ graphqlUrl,
4004
+ inContextOf: IN_CONTEXT_OF,
4005
+ payers: PAYERS,
4006
+ timeoutMs: ANSWER_MS,
4007
+ ...fetcher === undefined ? {} : { fetch: fetcher }
4008
+ }).then((usage) => linesSentence(usage, label, WHERE)).catch(() => null);
4009
+ try {
4010
+ return await Promise.race([read, late]);
4011
+ } finally {
4012
+ clearTimeout(timer);
4013
+ }
4014
+ }
4015
+ function failureOutput(context) {
4016
+ return JSON.stringify({ hookSpecificOutput: { hookEventName: "PostToolUseFailure", additionalContext: context } });
4017
+ }
4018
+ var RECORD = Symbol("record");
4019
+ async function postToolUseFailure(payload) {
4020
+ const call = toolCallOf(payload);
4021
+ if (call === null || call.tool !== "Bash")
4022
+ return RECORD;
4023
+ const failure = recordSkillFailure(call, call.cwd ?? process.cwd());
4024
+ const context = failure === null ? null : await answerFailure(failure);
4025
+ return context === null ? null : failureOutput(context);
4026
+ }
4027
+
4028
+ // ../hook/src/worked.ts
4029
+ import { existsSync as existsSync2, mkdirSync as mkdirSync3, readFileSync as readFileSync3 } from "node:fs";
4030
+ import { dirname as dirname3, join as join4 } from "node:path";
4031
+
4032
+ // ../../packages/protocol/src/local-outcomes.ts
4033
+ var OUTCOME_ANSWERS2 = ["worked", "failed", "unsure"];
4034
+ function isOutcomeAnswer2(word) {
4035
+ return OUTCOME_ANSWERS2.includes(word);
4036
+ }
4037
+ var ANSWER = /^[\s>*`-]*arp:\s*([A-Za-z0-9._:@/-]+)\s+(worked|failed|unsure)[\s.`*]*$/gim;
4038
+ function answersIn2(text, asked) {
4039
+ const found = new Map;
4040
+ for (const match of text.matchAll(ANSWER)) {
4041
+ const [, skill, word] = match;
4042
+ if (skill === undefined || word === undefined)
4043
+ continue;
4044
+ const answer = word.toLowerCase();
4045
+ if (!asked.includes(skill) || found.has(skill) || !isOutcomeAnswer2(answer))
4046
+ continue;
4047
+ found.set(skill, answer);
4048
+ }
4049
+ return found;
4050
+ }
4051
+
4052
+ // ../hook/src/worked.ts
4053
+ var MAX_ASKED = 5;
4054
+ function isRecord5(value) {
4055
+ return typeof value === "object" && value !== null && !Array.isArray(value);
4056
+ }
4057
+ var field = (raw, snake, camel) => raw[snake] ?? raw[camel];
4058
+ var text = (value) => typeof value === "string" && value.length > 0 ? value : null;
4059
+ function stopInputOf(raw) {
4060
+ if (!isRecord5(raw) || field(raw, "hook_event_name", "hookEventName") !== "Stop")
4061
+ return null;
4062
+ const session = text(field(raw, "session_id", "sessionId"));
4063
+ if (session === null)
4064
+ return null;
4065
+ return {
4066
+ session,
4067
+ cwd: text(raw["cwd"]) ?? process.cwd(),
4068
+ active: field(raw, "stop_hook_active", "stopHookActive") === true,
4069
+ last: text(field(raw, "last_assistant_message", "lastAssistantMessage")) ?? "",
4070
+ transcript: text(field(raw, "transcript_path", "transcriptPath"))
4071
+ };
4072
+ }
4073
+ function questionFor(skills) {
4074
+ return "ARP asks once per skill: did each skill you used here do its job, and did the task finish with it? " + "Reply with one line per skill and nothing else: `arp: <skill> worked`, `arp: <skill> failed` or `arp: <skill> unsure`. " + `Kept on this machine unless \`arp share\` is on. Skills: ${skills.join(", ")}`;
4075
+ }
4076
+ var isArpsOwn = (name) => name === "arp" || name.endsWith(":arp");
4077
+ function rows(path) {
4078
+ if (!existsSync2(path))
4079
+ return [];
4080
+ const found = [];
4081
+ for (const line of readFileSync3(path, "utf8").split(`
4082
+ `)) {
4083
+ if (line.trim() === "")
4084
+ continue;
4085
+ try {
4086
+ const row = JSON.parse(line);
4087
+ if (isRecord5(row))
4088
+ found.push(row);
4089
+ } catch {}
4090
+ }
4091
+ return found;
4092
+ }
4093
+ function withOf(skill, source, cwd, before) {
4094
+ const name = skill.split(":").pop() ?? skill;
4095
+ let need = null;
4096
+ let latest = "";
4097
+ for (const row of rows(join4(arpHome(), "failures.jsonl"))) {
4098
+ const { skill: rowSkill, source: rowSource, need: rowNeed, at } = row;
4099
+ if (typeof rowSkill !== "string" || typeof rowNeed !== "string" || typeof at !== "string")
4100
+ continue;
4101
+ if (rowSkill !== skill && rowSkill !== name && !rowSkill.endsWith(`:${name}`))
4102
+ continue;
4103
+ if (typeof rowSource === "string" && source !== null && rowSource !== source)
4104
+ continue;
4105
+ if (at > before || at < latest)
4106
+ continue;
4107
+ need = rowNeed;
4108
+ latest = at;
4109
+ }
4110
+ if (need === null)
4111
+ return null;
4112
+ const directory = skillDirectory(name, cwd);
4113
+ if (directory === null)
4114
+ return null;
4115
+ return publishableNeed3(need, readFileSync3(join4(directory, "SKILL.md"), "utf8"));
4116
+ }
4117
+ function record(input, asked, outcome, at) {
4118
+ const search = foundBySearch(input.cwd, input.session, asked.skill);
4119
+ const words = input.transcript !== null && existsSync2(input.transcript) ? lastUserWords(readFileSync3(input.transcript, "utf8")) : "";
4120
+ const domain = search?.domain ?? contextOf(words, asked.skill);
4121
+ const source = asked.source ?? search?.source ?? installedSource(asked.skill.split(":").pop() ?? asked.skill, input.cwd);
4122
+ const named = outcome === "worked" ? withOf(asked.skill, source, input.cwd, at) : null;
4123
+ const line = {
4124
+ at,
4125
+ session: input.session,
4126
+ skill: asked.skill,
4127
+ source,
4128
+ ...domain === null ? {} : { domain },
4129
+ outcome,
4130
+ ...named === null ? {} : { with: named }
4131
+ };
4132
+ appendOwn(join4(arpHome(), "outcomes.jsonl"), `${JSON.stringify(line)}
4133
+ `);
4134
+ }
4135
+ async function stop(payload) {
4136
+ const input = stopInputOf(payload);
4137
+ if (input === null)
4138
+ return null;
4139
+ const ask = onStop(input);
4140
+ return ask === null ? null : JSON.stringify(ask);
4141
+ }
4142
+ function onStop(input, now = new Date) {
4143
+ try {
4144
+ const home = arpHome();
4145
+ mkdirSync3(home, { recursive: true });
4146
+ const askedPath = join4(home, "asked.jsonl");
4147
+ const asked = rows(askedPath).flatMap((row) => row["session"] === input.session && typeof row["skill"] === "string" ? [{
4148
+ at: typeof row["at"] === "string" ? row["at"] : "",
4149
+ session: input.session,
4150
+ skill: row["skill"],
4151
+ source: typeof row["source"] === "string" ? row["source"] : null
4152
+ }] : []);
4153
+ const answered = new Set(rows(join4(home, "outcomes.jsonl")).flatMap((row) => row["session"] === input.session && typeof row["skill"] === "string" ? [row["skill"]] : []));
4154
+ const pending = asked.filter((row) => !answered.has(row.skill));
4155
+ const at = now.toISOString();
4156
+ for (const [skill, answer] of answersIn2(input.last, pending.map((row) => row.skill))) {
4157
+ const row = pending.find((entry) => entry.skill === skill);
4158
+ if (row !== undefined)
4159
+ record(input, row, answer, at);
4160
+ }
4161
+ if (input.active)
4162
+ return null;
4163
+ const known = new Set(asked.map((row) => row.skill));
4164
+ const log = process.env["ARP_SESSION_LOG"] ?? join4(input.cwd, ".arp", "session.jsonl");
4165
+ const fresh = [];
4166
+ for (const skill of skillsOfSession(log, input.session)) {
4167
+ if (known.has(skill.name) || isArpsOwn(skill.name))
4168
+ continue;
4169
+ known.add(skill.name);
4170
+ fresh.push({ at, session: input.session, skill: skill.name, source: skill.source });
4171
+ }
4172
+ const ask = fresh.slice(0, MAX_ASKED);
4173
+ if (ask.length === 0)
4174
+ return null;
4175
+ mkdirSync3(dirname3(askedPath), { recursive: true });
4176
+ appendOwn(askedPath, ask.map((row) => `${JSON.stringify(row)}
4177
+ `).join(""));
4178
+ return { decision: "block", reason: questionFor(ask.map((row) => row.skill)) };
4179
+ } catch {
4180
+ return null;
4181
+ }
4182
+ }
4183
+
4184
+ // ../hook/src/hook.ts
4185
+ var ROUTES = {
4186
+ PreToolUse: (payload) => preToolUse(payload),
4187
+ PostToolUseFailure: (payload) => postToolUseFailure(payload),
4188
+ Stop: (payload) => stop(payload)
4189
+ };
4190
+ async function route(handler, payload) {
4191
+ let out = null;
4192
+ try {
4193
+ out = await handler(payload);
4194
+ } catch {
4195
+ out = null;
4196
+ }
4197
+ if (out === RECORD)
4198
+ return;
4199
+ if (out === null)
4200
+ process.exit(0);
4201
+ process.stdout.write(`${out}
4202
+ `, () => process.exit(0));
4203
+ await new Promise(() => {
4204
+ return;
4205
+ });
4206
+ }
4207
+ function fetchedRefs(cwd) {
4208
+ const path = process.env["ARP_RECEIPTS"] ?? join5(cwd, ".arp", "receipts.jsonl");
4209
+ if (!existsSync3(path))
4210
+ return [];
4211
+ let text2;
4212
+ try {
4213
+ text2 = readFileSync4(path, "utf8");
4214
+ } catch {
4215
+ return [];
4216
+ }
4217
+ const rows2 = [];
4218
+ for (const line of text2.split(`
4219
+ `)) {
4220
+ if (line.trim().length === 0)
4221
+ continue;
4222
+ try {
4223
+ const row = JSON.parse(line);
4224
+ if (typeof row.skill !== "string" || typeof row.atom !== "string")
4225
+ continue;
4226
+ rows2.push({
4227
+ skill: row.skill,
4228
+ atom: row.atom,
4229
+ url: typeof row.url === "string" ? row.url : "",
4230
+ at: typeof row.at === "string" ? row.at : ""
4231
+ });
4232
+ } catch {
4233
+ continue;
4234
+ }
4235
+ }
4236
+ return rows2;
4237
+ }
4238
+ function responseOf(call, outcome) {
4239
+ if (!call.hasResponse)
4240
+ return null;
4241
+ const raw = call.response;
4242
+ let bytes = 0;
4243
+ try {
4244
+ bytes = typeof raw === "string" ? raw.length : JSON.stringify(raw)?.length ?? 0;
4245
+ } catch {
4246
+ bytes = 0;
4247
+ }
4248
+ return { answered: raw !== null, bytes, failed: outcome !== "ok" };
4249
+ }
4250
+ function readString2(from, key) {
4251
+ const value = from?.[key];
4252
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
4253
+ }
4254
+ function serverRef(server, cwd) {
4255
+ const url = serverUrlOf(readMcpServers({ cwd }).get(server));
4256
+ if (url === null)
4257
+ return null;
4258
+ try {
4259
+ return normaliseToolUrl(url);
4260
+ } catch {
4261
+ return null;
4262
+ }
4263
+ }
4264
+ function whatOf(call, cwd, fetched) {
4265
+ if (call.tool === "Skill") {
4266
+ const name = readString2(call.input, "skill");
4267
+ if (name === null)
4268
+ return null;
4269
+ const source = readString2(call.input, "source");
4270
+ return {
4271
+ kind: "skill",
4272
+ name,
4273
+ source,
4274
+ ref: readString2(call.input, "atom_id") ?? readString2(call.input, "tool_atom_id") ?? readString2(call.input, "url") ?? refForInvocation(name, source, fetched())
4275
+ };
4276
+ }
4277
+ const mcp = /^mcp__([^_]+(?:_[^_]+)*?)__/.exec(call.tool);
4278
+ if (mcp?.[1] !== undefined) {
4279
+ return { kind: "mcp", name: mcp[1], source: null, ref: serverRef(mcp[1], cwd) };
4280
+ }
4281
+ return null;
4282
+ }
4283
+ var raw = "";
4284
+ for await (const chunk of process.stdin)
4285
+ raw += chunk;
4286
+ var parsed;
4287
+ try {
4288
+ parsed = JSON.parse(raw);
4289
+ } catch {
4290
+ process.exit(0);
4291
+ }
4292
+ if (process.argv.includes("--capture"))
4293
+ capture(parsed, join5(homedir3(), ".arp", "captures"));
4294
+ var event = eventOf(parsed);
4295
+ var handler = event === null ? undefined : ROUTES[event];
4296
+ if (handler !== undefined)
4297
+ await route(handler, parsed);
4298
+ var call = toolCallOf(parsed);
4299
+ if (call === null)
4300
+ process.exit(0);
4301
+ var cwd = call.cwd ?? process.cwd();
4302
+ if (call.tool === "Bash") {
4303
+ recordSkillFailure(call, cwd);
4304
+ process.exit(0);
4305
+ }
4306
+ if (call.tool.endsWith("__arp_pulse"))
4307
+ recordSearch(call, cwd);
4308
+ var what = whatOf(call, cwd, () => fetchedRefs(cwd));
4309
+ if (what === null)
4310
+ process.exit(0);
4311
+ var classified = classifyCall(call);
4312
+ if (classified === null)
4313
+ process.exit(0);
4314
+ var own = join5(cwd, ".arp");
4315
+ var path = process.env["ARP_SESSION_LOG"] ?? join5(own, "session.jsonl");
4316
+ var line = {
4317
+ at: new Date().toISOString(),
4318
+ session: call.session,
4319
+ call: call.id,
4320
+ format: call.format,
4321
+ ...what,
4322
+ outcome: classified.outcome,
4323
+ code: classified.code,
4324
+ ms: call.ms,
4325
+ response: responseOf(call, classified.outcome)
4326
+ };
4327
+ try {
4328
+ mkdirSync4(dirname4(path), { recursive: true });
4329
+ if (dirname4(path) === own && lstatSync2(own).isSymbolicLink())
4330
+ throw new Error(`${own} is a symbolic link`);
4331
+ const ignore = join5(own, ".gitignore");
4332
+ if (dirname4(path) === own && !existsSync3(ignore))
4333
+ writeFileSync2(ignore, `*
4334
+ `, { flag: "wx" });
4335
+ appendOwn(path, `${JSON.stringify(line)}
4336
+ `);
4337
+ } catch {}