@tempoxyz/patron 0.0.16 → 0.0.18
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/README.md +21 -6
- package/dist/bin.js +6 -2
- package/dist/chunks/{-UIKBA3CN.js → -643GYNS6.js} +23 -18
- package/dist/chunks/chunk-CF4LJZLC.js +1204 -0
- package/dist/chunks/chunk-CV2WYKM7.js +43 -0
- package/dist/chunks/chunk-GTMLTZRN.js +48 -0
- package/dist/chunks/{chunk-FXE4CGY7.js → chunk-RDEPJ6XD.js} +0 -43
- package/dist/chunks/chunk-RJRJWNSQ.js +114 -0
- package/dist/chunks/{chunk-4Z6ZIXMK.js → chunk-XJOIDBXC.js} +158 -1129
- package/dist/chunks/{hook-process-GKUDU2B3.js → hook-CCXQ4T4L.js} +71 -166
- package/dist/chunks/hook-process-YHSATQFR.js +75 -0
- package/dist/chunks/{wallet-JDUPZN7E.js → wallet-WNPT6R4M.js} +2 -1
- package/package.json +1 -1
|
@@ -1,117 +1,37 @@
|
|
|
1
1
|
import { createRequire as __patronCreateRequire } from 'node:module'
|
|
2
2
|
const require = __patronCreateRequire(import.meta.url)
|
|
3
|
+
import {
|
|
4
|
+
HOOK_TIMEOUT_MS,
|
|
5
|
+
MAX_DOMAINS_PER_HOOK,
|
|
6
|
+
hookDomains,
|
|
7
|
+
parseHookInput,
|
|
8
|
+
payableDomain,
|
|
9
|
+
turnEnd
|
|
10
|
+
} from "./chunk-RJRJWNSQ.js";
|
|
3
11
|
import {
|
|
4
12
|
FileTokenStore,
|
|
5
|
-
clampTokensPerPage,
|
|
6
13
|
codexHome,
|
|
7
14
|
loadIssuer,
|
|
8
15
|
needsRefill,
|
|
9
|
-
|
|
10
|
-
refillSize
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
} from "./chunk-
|
|
16
|
+
redeem,
|
|
17
|
+
refillSize
|
|
18
|
+
} from "./chunk-XJOIDBXC.js";
|
|
19
|
+
import {
|
|
20
|
+
clampTokensPerPage,
|
|
21
|
+
settingsFor
|
|
22
|
+
} from "./chunk-CF4LJZLC.js";
|
|
16
23
|
import {
|
|
17
24
|
readConfig,
|
|
18
25
|
readUsage,
|
|
19
26
|
updateUsage,
|
|
20
27
|
withLock,
|
|
21
28
|
writePrivateFile
|
|
22
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-RDEPJ6XD.js";
|
|
30
|
+
import "./chunk-GTMLTZRN.js";
|
|
23
31
|
|
|
24
32
|
// src/hook.ts
|
|
25
33
|
import { homedir } from "node:os";
|
|
26
34
|
|
|
27
|
-
// src/hook-input.ts
|
|
28
|
-
var MAX_DOMAINS_PER_HOOK = 10;
|
|
29
|
-
var MAX_DEPTH = 6;
|
|
30
|
-
var MAX_URLS = 50;
|
|
31
|
-
var FETCH_TOOLS = /* @__PURE__ */ new Set(["WebFetch", "read_web_page"]);
|
|
32
|
-
var SEARCH_TOOLS = /* @__PURE__ */ new Set(["WebSearch", "web_search"]);
|
|
33
|
-
function hookUrls(payload) {
|
|
34
|
-
if (!isRecord(payload) || typeof payload.tool_name !== "string") return [];
|
|
35
|
-
const tool = payload.tool_name;
|
|
36
|
-
const response = "tool_response" in payload ? payload.tool_response : jsonValue(payload.tool_output);
|
|
37
|
-
if (FETCH_TOOLS.has(tool)) {
|
|
38
|
-
const input = payload.tool_input;
|
|
39
|
-
if (isRecord(input) && typeof input.url === "string") return [input.url];
|
|
40
|
-
const urls2 = [];
|
|
41
|
-
collectUrls(response, urls2, 0);
|
|
42
|
-
return urls2.slice(0, 1);
|
|
43
|
-
}
|
|
44
|
-
if (!SEARCH_TOOLS.has(tool)) return [];
|
|
45
|
-
const urls = [];
|
|
46
|
-
collectUrls(response, urls, 0);
|
|
47
|
-
if (urls.length === 0 && tool === "web_search") collectTextUrls(response, urls, 0);
|
|
48
|
-
return urls;
|
|
49
|
-
}
|
|
50
|
-
function hookDomains(payload) {
|
|
51
|
-
const domains = [];
|
|
52
|
-
for (const url of hookUrls(payload)) {
|
|
53
|
-
const domain = normalizePayee(url);
|
|
54
|
-
if (domain && !domains.includes(domain)) domains.push(domain);
|
|
55
|
-
if (domains.length >= MAX_DOMAINS_PER_HOOK) break;
|
|
56
|
-
}
|
|
57
|
-
return domains;
|
|
58
|
-
}
|
|
59
|
-
function turnEnd(payload) {
|
|
60
|
-
if (!isRecord(payload)) return void 0;
|
|
61
|
-
if (payload.hook_event_name === "Stop" && typeof payload.turn_id === "string" && typeof payload.transcript_path === "string")
|
|
62
|
-
return { transcriptPath: payload.transcript_path };
|
|
63
|
-
if (payload.type === "agent-turn-complete" && typeof payload["thread-id"] === "string")
|
|
64
|
-
return { codexThreadId: payload["thread-id"] };
|
|
65
|
-
return void 0;
|
|
66
|
-
}
|
|
67
|
-
function isCursorPayload(payload) {
|
|
68
|
-
return isRecord(payload) && typeof payload.cursor_version === "string";
|
|
69
|
-
}
|
|
70
|
-
function parseHookInput(raw) {
|
|
71
|
-
try {
|
|
72
|
-
return JSON.parse(raw);
|
|
73
|
-
} catch {
|
|
74
|
-
return void 0;
|
|
75
|
-
}
|
|
76
|
-
}
|
|
77
|
-
function jsonValue(value) {
|
|
78
|
-
if (typeof value !== "string") return value;
|
|
79
|
-
try {
|
|
80
|
-
return JSON.parse(value);
|
|
81
|
-
} catch {
|
|
82
|
-
return value;
|
|
83
|
-
}
|
|
84
|
-
}
|
|
85
|
-
function collectUrls(value, urls, depth) {
|
|
86
|
-
if (depth > MAX_DEPTH || urls.length >= MAX_URLS) return;
|
|
87
|
-
if (Array.isArray(value)) {
|
|
88
|
-
for (const item of value) collectUrls(item, urls, depth + 1);
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
if (!isRecord(value)) return;
|
|
92
|
-
for (const [key, item] of Object.entries(value)) {
|
|
93
|
-
if (key === "url" && typeof item === "string") urls.push(item);
|
|
94
|
-
else collectUrls(item, urls, depth + 1);
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
function collectTextUrls(value, urls, depth) {
|
|
98
|
-
if (depth > MAX_DEPTH || urls.length >= MAX_URLS) return;
|
|
99
|
-
if (typeof value === "string") {
|
|
100
|
-
for (const match of value.matchAll(/https?:\/\/[^\s"'<>()[\]`]+/g)) {
|
|
101
|
-
if (urls.length >= MAX_URLS) return;
|
|
102
|
-
urls.push(match[0].replace(/[.,;:!?]+$/, ""));
|
|
103
|
-
}
|
|
104
|
-
return;
|
|
105
|
-
}
|
|
106
|
-
if (Array.isArray(value))
|
|
107
|
-
for (const item of value) collectTextUrls(item, urls, depth + 1);
|
|
108
|
-
else if (isRecord(value))
|
|
109
|
-
for (const item of Object.values(value)) collectTextUrls(item, urls, depth + 1);
|
|
110
|
-
}
|
|
111
|
-
function isRecord(value) {
|
|
112
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
113
|
-
}
|
|
114
|
-
|
|
115
35
|
// src/transcript.ts
|
|
116
36
|
import { createHash } from "node:crypto";
|
|
117
37
|
import { mkdir, open, readdir, readFile, rm, stat } from "node:fs/promises";
|
|
@@ -134,7 +54,7 @@ function codexRolloutUrls(lines) {
|
|
|
134
54
|
} catch {
|
|
135
55
|
continue;
|
|
136
56
|
}
|
|
137
|
-
if (!
|
|
57
|
+
if (!isRecord(record) || !isRecord(record.payload)) continue;
|
|
138
58
|
const payload = record.payload;
|
|
139
59
|
if (record.type === "response_item") responseItemUrls(payload, urls);
|
|
140
60
|
else if (record.type === "event_msg") eventUrls(payload, urls);
|
|
@@ -162,7 +82,7 @@ function responseItemUrls(item, urls) {
|
|
|
162
82
|
}
|
|
163
83
|
function eventUrls(event, urls) {
|
|
164
84
|
const search = event.type === "web_search_end" ? event : event.type === "item_completed" && field(event.item, "type") === "WebSearch" ? event.item : void 0;
|
|
165
|
-
if (!
|
|
85
|
+
if (!isRecord(search)) return;
|
|
166
86
|
pushUrl(urls, field(search.action, "url"));
|
|
167
87
|
for (const result of asArray(search.results)) pushUrl(urls, field(result, "url"));
|
|
168
88
|
}
|
|
@@ -179,7 +99,7 @@ async function takeTranscriptDomains(home, transcriptPath2, options) {
|
|
|
179
99
|
const known = /* @__PURE__ */ new Set([...state.paid, ...state.pending]);
|
|
180
100
|
const pending = [...state.pending];
|
|
181
101
|
for (const url of codexRolloutUrls(lines)) {
|
|
182
|
-
const domain =
|
|
102
|
+
const domain = payableDomain(url);
|
|
183
103
|
if (domain && !known.has(domain)) {
|
|
184
104
|
known.add(domain);
|
|
185
105
|
pending.push(domain);
|
|
@@ -257,7 +177,7 @@ async function readState(path) {
|
|
|
257
177
|
} catch {
|
|
258
178
|
return void 0;
|
|
259
179
|
}
|
|
260
|
-
if (!
|
|
180
|
+
if (!isRecord(value) || typeof value.offset !== "number") return void 0;
|
|
261
181
|
const strings = (list) => asArray(list).filter((item) => typeof item === "string");
|
|
262
182
|
return {
|
|
263
183
|
offset: value.offset,
|
|
@@ -278,17 +198,17 @@ function pushUrl(urls, value) {
|
|
|
278
198
|
if (typeof value === "string" && /^https?:\/\//i.test(value)) urls.push(value);
|
|
279
199
|
}
|
|
280
200
|
function field(value, key) {
|
|
281
|
-
return
|
|
201
|
+
return isRecord(value) ? value[key] : void 0;
|
|
282
202
|
}
|
|
283
203
|
function asArray(value) {
|
|
284
204
|
return Array.isArray(value) ? value : [];
|
|
285
205
|
}
|
|
286
|
-
function
|
|
206
|
+
function isRecord(value) {
|
|
287
207
|
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
288
208
|
}
|
|
289
209
|
|
|
290
210
|
// src/hook.ts
|
|
291
|
-
var
|
|
211
|
+
var PAY_TIMEOUT_MS = 2e4;
|
|
292
212
|
var ABORT_MARGIN_MS = 500;
|
|
293
213
|
async function runHook(dependencies, timeoutMs = HOOK_TIMEOUT_MS) {
|
|
294
214
|
let timer;
|
|
@@ -333,31 +253,20 @@ async function payReads(dependencies, deadline) {
|
|
|
333
253
|
const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
|
|
334
254
|
fetch: boundedFetch
|
|
335
255
|
});
|
|
336
|
-
const paid = [];
|
|
337
|
-
let empty = false;
|
|
338
256
|
const perPage = clampTokensPerPage(config.tokensPerPage);
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
store
|
|
350
|
-
}).catch(() => null);
|
|
351
|
-
if (result === void 0) {
|
|
352
|
-
empty = true;
|
|
353
|
-
break rounds;
|
|
354
|
-
}
|
|
355
|
-
if (!result?.ok) continue;
|
|
356
|
-
if (round === 0) paid.push(result.domain || domain);
|
|
357
|
-
next.push(domain);
|
|
257
|
+
const taken = await store.takeWithRemaining(domains.length * perPage, domains.length);
|
|
258
|
+
const { empty, paid, unspent } = await redeemRounds(
|
|
259
|
+
taken.tokens,
|
|
260
|
+
domains,
|
|
261
|
+
perPage,
|
|
262
|
+
deadline,
|
|
263
|
+
{
|
|
264
|
+
fetch: boundedFetch,
|
|
265
|
+
issuer,
|
|
266
|
+
relayUrl: settings.relayUrl
|
|
358
267
|
}
|
|
359
|
-
|
|
360
|
-
|
|
268
|
+
);
|
|
269
|
+
await store.add(unspent);
|
|
361
270
|
const now = dependencies.now?.() ?? /* @__PURE__ */ new Date();
|
|
362
271
|
if (paid.length > 0)
|
|
363
272
|
await updateUsage(
|
|
@@ -369,7 +278,7 @@ async function payReads(dependencies, deadline) {
|
|
|
369
278
|
},
|
|
370
279
|
now
|
|
371
280
|
);
|
|
372
|
-
const refill = needsRefill(
|
|
281
|
+
const refill = needsRefill(taken.remaining + unspent.length) && refillSize(config, await readUsage(settings.home, now)) > 0;
|
|
373
282
|
if (refill) dependencies.startRefill();
|
|
374
283
|
return {
|
|
375
284
|
paid,
|
|
@@ -377,6 +286,38 @@ async function payReads(dependencies, deadline) {
|
|
|
377
286
|
...empty && paid.length === 0 ? { skipped: "no-tokens" } : {}
|
|
378
287
|
};
|
|
379
288
|
}
|
|
289
|
+
async function redeemRounds(tokens, domains, perPage, deadline, context) {
|
|
290
|
+
const paid = [];
|
|
291
|
+
const failed2 = [];
|
|
292
|
+
let used = 0;
|
|
293
|
+
let pending = domains.slice();
|
|
294
|
+
let empty = tokens.length === 0;
|
|
295
|
+
for (let round = 0; round < perPage && pending.length > 0 && !empty; round++) {
|
|
296
|
+
if (Date.now() >= deadline) break;
|
|
297
|
+
const batch = pending.slice(0, tokens.length - used);
|
|
298
|
+
if (batch.length < pending.length) empty = true;
|
|
299
|
+
const start = used;
|
|
300
|
+
used += batch.length;
|
|
301
|
+
const results = await Promise.all(
|
|
302
|
+
batch.map(async (domain, index) => {
|
|
303
|
+
const token = tokens[start + index];
|
|
304
|
+
try {
|
|
305
|
+
return await redeem({ ...context, domain, token });
|
|
306
|
+
} catch {
|
|
307
|
+
failed2.push(token);
|
|
308
|
+
return void 0;
|
|
309
|
+
}
|
|
310
|
+
})
|
|
311
|
+
);
|
|
312
|
+
pending = batch.filter((domain, index) => {
|
|
313
|
+
const result = results[index];
|
|
314
|
+
if (!result?.ok) return false;
|
|
315
|
+
if (round === 0) paid.push(result.domain || domain);
|
|
316
|
+
return true;
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
return { empty, paid, unspent: [...failed2, ...tokens.slice(used)] };
|
|
320
|
+
}
|
|
380
321
|
function withDeadline(fetchFn, deadline) {
|
|
381
322
|
return (input, init) => fetchFn(input, {
|
|
382
323
|
...init,
|
|
@@ -387,43 +328,7 @@ function transcriptPath(turn, agents = { env: process.env, home: homedir() }) {
|
|
|
387
328
|
if ("transcriptPath" in turn) return Promise.resolve(turn.transcriptPath);
|
|
388
329
|
return findCodexRollout(codexHome(agents.env, agents.home), turn.codexThreadId);
|
|
389
330
|
}
|
|
390
|
-
|
|
391
|
-
// src/hook-process.ts
|
|
392
|
-
var MAX_INPUT_BYTES = 8 * 1024 * 1024;
|
|
393
|
-
async function runHookProcess(argument = process.argv[3]) {
|
|
394
|
-
setTimeout(() => process.exit(0), HOOK_TIMEOUT_MS + 500).unref();
|
|
395
|
-
const raw = argument ?? await readStdin(HOOK_TIMEOUT_MS / 2);
|
|
396
|
-
if (isCursorPayload(parseHookInput(raw))) process.stdout.write("{}\n");
|
|
397
|
-
await runHook({
|
|
398
|
-
readInput: async () => raw,
|
|
399
|
-
settings: resolveSettings(),
|
|
400
|
-
startRefill: () => startRefill()
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
function readStdin(timeoutMs) {
|
|
404
|
-
return new Promise((resolve) => {
|
|
405
|
-
const chunks = [];
|
|
406
|
-
let size = 0;
|
|
407
|
-
const finish = () => {
|
|
408
|
-
clearTimeout(timer);
|
|
409
|
-
process.stdin.removeAllListeners();
|
|
410
|
-
process.stdin.pause();
|
|
411
|
-
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
412
|
-
};
|
|
413
|
-
const timer = setTimeout(finish, timeoutMs);
|
|
414
|
-
process.stdin.on("data", (chunk) => {
|
|
415
|
-
size += chunk.length;
|
|
416
|
-
if (size > MAX_INPUT_BYTES) {
|
|
417
|
-
chunks.length = 0;
|
|
418
|
-
finish();
|
|
419
|
-
return;
|
|
420
|
-
}
|
|
421
|
-
chunks.push(chunk);
|
|
422
|
-
});
|
|
423
|
-
process.stdin.on("end", finish);
|
|
424
|
-
process.stdin.on("error", finish);
|
|
425
|
-
});
|
|
426
|
-
}
|
|
427
331
|
export {
|
|
428
|
-
|
|
332
|
+
PAY_TIMEOUT_MS,
|
|
333
|
+
runHook
|
|
429
334
|
};
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { createRequire as __patronCreateRequire } from 'node:module'
|
|
2
|
+
const require = __patronCreateRequire(import.meta.url)
|
|
3
|
+
import {
|
|
4
|
+
HOOK_TIMEOUT_MS,
|
|
5
|
+
hookDomains,
|
|
6
|
+
isCursorPayload,
|
|
7
|
+
parseHookInput,
|
|
8
|
+
turnEnd
|
|
9
|
+
} from "./chunk-RJRJWNSQ.js";
|
|
10
|
+
import {
|
|
11
|
+
startPayment,
|
|
12
|
+
startRefill
|
|
13
|
+
} from "./chunk-CV2WYKM7.js";
|
|
14
|
+
import {
|
|
15
|
+
resolveSettings
|
|
16
|
+
} from "./chunk-CF4LJZLC.js";
|
|
17
|
+
import "./chunk-GTMLTZRN.js";
|
|
18
|
+
|
|
19
|
+
// src/hook-process.ts
|
|
20
|
+
var MAX_INPUT_BYTES = 8 * 1024 * 1024;
|
|
21
|
+
async function runHookProcess(argument = process.argv[3]) {
|
|
22
|
+
setTimeout(() => process.exit(0), HOOK_TIMEOUT_MS + 500).unref();
|
|
23
|
+
const raw = argument ?? await readStdin(HOOK_TIMEOUT_MS / 2);
|
|
24
|
+
const payload = parseHookInput(raw);
|
|
25
|
+
if (isCursorPayload(payload)) process.stdout.write("{}\n");
|
|
26
|
+
if (!turnEnd(payload) && hookDomains(payload).length === 0) return;
|
|
27
|
+
if (await startPayment(raw)) return;
|
|
28
|
+
const { runHook } = await import("./hook-CCXQ4T4L.js");
|
|
29
|
+
await runHook({
|
|
30
|
+
readInput: async () => raw,
|
|
31
|
+
settings: resolveSettings(),
|
|
32
|
+
startRefill: () => startRefill()
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
async function runPayProcess() {
|
|
36
|
+
const { PAY_TIMEOUT_MS, runHook } = await import("./hook-CCXQ4T4L.js");
|
|
37
|
+
setTimeout(() => process.exit(0), PAY_TIMEOUT_MS + 1e3).unref();
|
|
38
|
+
const raw = await readStdin(HOOK_TIMEOUT_MS);
|
|
39
|
+
await runHook(
|
|
40
|
+
{
|
|
41
|
+
readInput: async () => raw,
|
|
42
|
+
settings: resolveSettings(),
|
|
43
|
+
startRefill: () => startRefill()
|
|
44
|
+
},
|
|
45
|
+
PAY_TIMEOUT_MS
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
function readStdin(timeoutMs) {
|
|
49
|
+
return new Promise((resolve) => {
|
|
50
|
+
const chunks = [];
|
|
51
|
+
let size = 0;
|
|
52
|
+
const finish = () => {
|
|
53
|
+
clearTimeout(timer);
|
|
54
|
+
process.stdin.removeAllListeners();
|
|
55
|
+
process.stdin.pause();
|
|
56
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
57
|
+
};
|
|
58
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
59
|
+
process.stdin.on("data", (chunk) => {
|
|
60
|
+
size += chunk.length;
|
|
61
|
+
if (size > MAX_INPUT_BYTES) {
|
|
62
|
+
chunks.length = 0;
|
|
63
|
+
finish();
|
|
64
|
+
return;
|
|
65
|
+
}
|
|
66
|
+
chunks.push(chunk);
|
|
67
|
+
});
|
|
68
|
+
process.stdin.on("end", finish);
|
|
69
|
+
process.stdin.on("error", finish);
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
export {
|
|
73
|
+
runHookProcess,
|
|
74
|
+
runPayProcess
|
|
75
|
+
};
|
|
@@ -2,7 +2,8 @@ import { createRequire as __patronCreateRequire } from 'node:module'
|
|
|
2
2
|
const require = __patronCreateRequire(import.meta.url)
|
|
3
3
|
import {
|
|
4
4
|
statePaths
|
|
5
|
-
} from "./chunk-
|
|
5
|
+
} from "./chunk-RDEPJ6XD.js";
|
|
6
|
+
import "./chunk-GTMLTZRN.js";
|
|
6
7
|
|
|
7
8
|
// src/wallet.ts
|
|
8
9
|
import { Store } from "accounts";
|