@tempoxyz/patron 0.0.23 → 0.0.25
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/bin.js +3 -3
- package/dist/chunks/{-JRJJV4LP.js → -ZZLSTHT6.js} +21 -11
- package/dist/chunks/{chunk-5GS6AZ5L.js → chunk-HVTTV2A5.js} +10 -1
- package/dist/chunks/{chunk-75CD5P6X.js → chunk-NQ6RRPM6.js} +4 -2
- package/dist/chunks/chunk-O64T22EK.js +54 -0
- package/dist/chunks/{chunk-UWIBR62N.js → chunk-SGQ525FB.js} +7 -54
- package/dist/chunks/{chunk-HEQBEBKL.js → chunk-TV5VLFTD.js} +4 -5
- package/dist/chunks/{hook-AHF4ELOX.js → hook-OZRD6I6F.js} +7 -5
- package/dist/chunks/hook-process-ZPEWRFL2.js +243 -0
- package/dist/chunks/{wallet-R3UWBXVC.js → wallet-7M2LEO4J.js} +2 -1
- package/package.json +1 -1
- package/dist/chunks/hook-process-3OTLNDSS.js +0 -75
package/dist/bin.js
CHANGED
|
@@ -4,14 +4,14 @@ const require = __patronCreateRequire(import.meta.url)
|
|
|
4
4
|
|
|
5
5
|
// src/bin.ts
|
|
6
6
|
if (process.argv[2] === "hook") {
|
|
7
|
-
const { runHookProcess } = await import("./chunks/hook-process-
|
|
7
|
+
const { runHookProcess } = await import("./chunks/hook-process-ZPEWRFL2.js");
|
|
8
8
|
await runHookProcess().catch(() => void 0);
|
|
9
9
|
process.exit(0);
|
|
10
10
|
} else if (process.argv[2] === "pay") {
|
|
11
|
-
const { runPayProcess } = await import("./chunks/hook-process-
|
|
11
|
+
const { runPayProcess } = await import("./chunks/hook-process-ZPEWRFL2.js");
|
|
12
12
|
await runPayProcess().catch(() => void 0);
|
|
13
13
|
process.exit(0);
|
|
14
14
|
} else {
|
|
15
|
-
const { run } = await import("./chunks/-
|
|
15
|
+
const { run } = await import("./chunks/-ZZLSTHT6.js");
|
|
16
16
|
process.exitCode = await run(process.argv.slice(2));
|
|
17
17
|
}
|
|
@@ -29,10 +29,10 @@ import {
|
|
|
29
29
|
withPatronStatus,
|
|
30
30
|
withoutPatronHandlers,
|
|
31
31
|
writeJsonObject
|
|
32
|
-
} from "./chunk-
|
|
32
|
+
} from "./chunk-NQ6RRPM6.js";
|
|
33
33
|
import {
|
|
34
34
|
startRefill
|
|
35
|
-
} from "./chunk-
|
|
35
|
+
} from "./chunk-TV5VLFTD.js";
|
|
36
36
|
import {
|
|
37
37
|
DEFAULT_MONTHLY_BUDGET_USD,
|
|
38
38
|
MAX_TOKENS_PER_PAGE,
|
|
@@ -53,12 +53,14 @@ import {
|
|
|
53
53
|
readJson,
|
|
54
54
|
readUsage,
|
|
55
55
|
statePaths,
|
|
56
|
-
tryLock,
|
|
57
56
|
updateUsage,
|
|
58
|
-
withLock,
|
|
59
57
|
writeConfig,
|
|
60
58
|
writePrivateFile
|
|
61
|
-
} from "./chunk-
|
|
59
|
+
} from "./chunk-SGQ525FB.js";
|
|
60
|
+
import {
|
|
61
|
+
tryLock,
|
|
62
|
+
withLock
|
|
63
|
+
} from "./chunk-O64T22EK.js";
|
|
62
64
|
import "./chunk-GTMLTZRN.js";
|
|
63
65
|
|
|
64
66
|
// src/index.ts
|
|
@@ -90,6 +92,13 @@ export const description = 'Patron: pays $0.001 to each site Amp reads with read
|
|
|
90
92
|
const COMMAND = ${JSON.stringify(command)}
|
|
91
93
|
const TOOLS = new Set(${JSON.stringify(AMP_WEB_TOOLS)})
|
|
92
94
|
|
|
95
|
+
/** Length of a tool's output; 0 for none or blank text. */
|
|
96
|
+
function size(output: unknown): number {
|
|
97
|
+
if (output === undefined || output === null) return 0
|
|
98
|
+
const text = typeof output === 'string' ? output : JSON.stringify(output)
|
|
99
|
+
return text.trim().length
|
|
100
|
+
}
|
|
101
|
+
|
|
93
102
|
export default function (amp: PluginAPI) {
|
|
94
103
|
amp.on('tool.result', (event) => {
|
|
95
104
|
if (event.status !== 'done' || !TOOLS.has(event.tool)) return
|
|
@@ -102,7 +111,8 @@ export default function (amp: PluginAPI) {
|
|
|
102
111
|
hook_event_name: 'tool.result',
|
|
103
112
|
tool_input: event.input,
|
|
104
113
|
tool_name: event.tool,
|
|
105
|
-
|
|
114
|
+
// read_web_page sends only the page's length, so an empty page pays nothing.
|
|
115
|
+
tool_response: event.tool === 'web_search' ? event.output : { bytes: size(event.output) },
|
|
106
116
|
}),
|
|
107
117
|
)
|
|
108
118
|
child.unref()
|
|
@@ -690,10 +700,10 @@ async function linkRefillFailedAt(home) {
|
|
|
690
700
|
var REFILL_LOCK_STALE_MS = 5 * 60 * 1e3;
|
|
691
701
|
var defaultOpenWallet = async (settings, config, issuer, maxUnits) => {
|
|
692
702
|
if (config.wallet === "link") {
|
|
693
|
-
const { openLinkWallet } = await import("./wallet-
|
|
703
|
+
const { openLinkWallet } = await import("./wallet-7M2LEO4J.js");
|
|
694
704
|
return openLinkWallet(config, maxUnits);
|
|
695
705
|
}
|
|
696
|
-
const { openWallet } = await import("./wallet-
|
|
706
|
+
const { openWallet } = await import("./wallet-7M2LEO4J.js");
|
|
697
707
|
return openWallet(settings, config.wallet, issuer, maxUnits);
|
|
698
708
|
};
|
|
699
709
|
async function buyWithinBudget(settings, config, wanted, openWallet = defaultOpenWallet) {
|
|
@@ -1062,7 +1072,7 @@ async function tempoSignIn(deps, budgetUnits, issuer) {
|
|
|
1062
1072
|
deps,
|
|
1063
1073
|
deps.settings.privateKey ? "Using PATRON_PRIVATE_KEY" : "Signing in with Tempo Wallet"
|
|
1064
1074
|
);
|
|
1065
|
-
const { signIn } = await import("./wallet-
|
|
1075
|
+
const { signIn } = await import("./wallet-7M2LEO4J.js");
|
|
1066
1076
|
const account = await signIn(deps.settings, {
|
|
1067
1077
|
budgetUnits,
|
|
1068
1078
|
issuer,
|
|
@@ -1176,7 +1186,7 @@ async function changeBudget(deps, input) {
|
|
|
1176
1186
|
} else budget = await askBudget(deps, config.monthlyBudgetUsd);
|
|
1177
1187
|
if (config.wallet === "tempo" && budget > config.monthlyBudgetUsd) {
|
|
1178
1188
|
step(deps, "Approve the new spending limit in Tempo Wallet");
|
|
1179
|
-
const { authorizeBudget } = await import("./wallet-
|
|
1189
|
+
const { authorizeBudget } = await import("./wallet-7M2LEO4J.js");
|
|
1180
1190
|
const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
|
|
1181
1191
|
fetch: deps.fetch
|
|
1182
1192
|
});
|
|
@@ -1292,7 +1302,7 @@ async function setName(deps, name) {
|
|
|
1292
1302
|
const issuer = await loadIssuer(settings.home, settings.gatewayUrl, {
|
|
1293
1303
|
fetch: deps.fetch
|
|
1294
1304
|
});
|
|
1295
|
-
const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-
|
|
1305
|
+
const open = deps.openWallet ?? (async (s, c, i, max) => (await import("./wallet-7M2LEO4J.js")).openWallet(s, c.wallet, i, max));
|
|
1296
1306
|
const wallet = await open(settings, config, issuer, 0n);
|
|
1297
1307
|
await setProfile(settings.gatewayUrl, wallet, name, deps.fetch);
|
|
1298
1308
|
await writeConfig(settings.home, { ...config, name });
|
|
@@ -7,6 +7,7 @@ import {
|
|
|
7
7
|
|
|
8
8
|
// src/hook-input.ts
|
|
9
9
|
var HOOK_TIMEOUT_MS = 2e3;
|
|
10
|
+
var PAY_TIMEOUT_MS = 2e4;
|
|
10
11
|
var MAX_DOMAINS_PER_HOOK = 10;
|
|
11
12
|
var MAX_DEPTH = 6;
|
|
12
13
|
var MAX_URLS = 50;
|
|
@@ -45,7 +46,14 @@ function payableDomain(url) {
|
|
|
45
46
|
function succeeded(response) {
|
|
46
47
|
if (!isRecord(response)) return true;
|
|
47
48
|
const status = response.code ?? response.status ?? response.statusCode;
|
|
48
|
-
|
|
49
|
+
if (typeof status === "number" && (status < 200 || status >= 300 || status === 204))
|
|
50
|
+
return false;
|
|
51
|
+
if (response.bytes === 0) return false;
|
|
52
|
+
for (const field of ["markdown", "content"]) {
|
|
53
|
+
const body = response[field];
|
|
54
|
+
if (typeof body === "string" && body.trim() === "") return false;
|
|
55
|
+
}
|
|
56
|
+
return true;
|
|
49
57
|
}
|
|
50
58
|
function turnEnd(payload) {
|
|
51
59
|
if (!isRecord(payload)) return void 0;
|
|
@@ -105,6 +113,7 @@ function isRecord(value) {
|
|
|
105
113
|
|
|
106
114
|
export {
|
|
107
115
|
HOOK_TIMEOUT_MS,
|
|
116
|
+
PAY_TIMEOUT_MS,
|
|
108
117
|
MAX_DOMAINS_PER_HOOK,
|
|
109
118
|
hookDomains,
|
|
110
119
|
payableDomain,
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { createRequire as __patronCreateRequire } from 'node:module'
|
|
2
|
+
const require = __patronCreateRequire(import.meta.url)
|
|
3
|
+
|
|
4
|
+
// src/lock.ts
|
|
5
|
+
import { open, rm, stat } from "node:fs/promises";
|
|
6
|
+
async function withLock(path, fn, options = {}) {
|
|
7
|
+
const deadline = Date.now() + (options.timeoutMs ?? 3e3);
|
|
8
|
+
const staleMs = options.staleMs ?? 1e4;
|
|
9
|
+
for (; ; ) {
|
|
10
|
+
try {
|
|
11
|
+
const handle = await open(path, "wx", 384);
|
|
12
|
+
await handle.close();
|
|
13
|
+
break;
|
|
14
|
+
} catch (error) {
|
|
15
|
+
if (error.code !== "EEXIST") throw error;
|
|
16
|
+
const age = await stat(path).then(
|
|
17
|
+
(stats) => Date.now() - stats.mtimeMs,
|
|
18
|
+
() => 0
|
|
19
|
+
);
|
|
20
|
+
if (age > staleMs) {
|
|
21
|
+
await rm(path, { force: true });
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
if (Date.now() > deadline) throw new Error(`Patron state is busy: ${path}`);
|
|
25
|
+
await new Promise((resolve) => setTimeout(resolve, 10 + Math.random() * 20));
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
try {
|
|
29
|
+
return await fn();
|
|
30
|
+
} finally {
|
|
31
|
+
await rm(path, { force: true });
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async function tryLock(path, staleMs) {
|
|
35
|
+
try {
|
|
36
|
+
const handle = await open(path, "wx", 384);
|
|
37
|
+
await handle.close();
|
|
38
|
+
} catch (error) {
|
|
39
|
+
if (error.code !== "EEXIST") throw error;
|
|
40
|
+
const age = await stat(path).then(
|
|
41
|
+
(stats) => Date.now() - stats.mtimeMs,
|
|
42
|
+
() => 0
|
|
43
|
+
);
|
|
44
|
+
if (age <= staleMs) return void 0;
|
|
45
|
+
await rm(path, { force: true });
|
|
46
|
+
return tryLock(path, staleMs);
|
|
47
|
+
}
|
|
48
|
+
return () => rm(path, { force: true });
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export {
|
|
52
|
+
withLock,
|
|
53
|
+
tryLock
|
|
54
|
+
};
|
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
import { createRequire as __patronCreateRequire } from 'node:module'
|
|
2
2
|
const require = __patronCreateRequire(import.meta.url)
|
|
3
|
+
import {
|
|
4
|
+
withLock
|
|
5
|
+
} from "./chunk-O64T22EK.js";
|
|
3
6
|
|
|
4
7
|
// src/state.ts
|
|
8
|
+
import { randomBytes } from "node:crypto";
|
|
5
9
|
import {
|
|
6
10
|
chmod,
|
|
7
11
|
lstat,
|
|
@@ -9,59 +13,10 @@ import {
|
|
|
9
13
|
readFile,
|
|
10
14
|
readlink,
|
|
11
15
|
rename,
|
|
12
|
-
rm
|
|
16
|
+
rm,
|
|
13
17
|
writeFile
|
|
14
18
|
} from "node:fs/promises";
|
|
15
19
|
import { dirname, join, resolve } from "node:path";
|
|
16
|
-
|
|
17
|
-
// src/lock.ts
|
|
18
|
-
import { open, rm, stat } from "node:fs/promises";
|
|
19
|
-
async function withLock(path, fn, options = {}) {
|
|
20
|
-
const deadline = Date.now() + (options.timeoutMs ?? 3e3);
|
|
21
|
-
const staleMs = options.staleMs ?? 1e4;
|
|
22
|
-
for (; ; ) {
|
|
23
|
-
try {
|
|
24
|
-
const handle = await open(path, "wx", 384);
|
|
25
|
-
await handle.close();
|
|
26
|
-
break;
|
|
27
|
-
} catch (error) {
|
|
28
|
-
if (error.code !== "EEXIST") throw error;
|
|
29
|
-
const age = await stat(path).then(
|
|
30
|
-
(stats) => Date.now() - stats.mtimeMs,
|
|
31
|
-
() => 0
|
|
32
|
-
);
|
|
33
|
-
if (age > staleMs) {
|
|
34
|
-
await rm(path, { force: true });
|
|
35
|
-
continue;
|
|
36
|
-
}
|
|
37
|
-
if (Date.now() > deadline) throw new Error(`Patron state is busy: ${path}`);
|
|
38
|
-
await new Promise((resolve2) => setTimeout(resolve2, 10 + Math.random() * 20));
|
|
39
|
-
}
|
|
40
|
-
}
|
|
41
|
-
try {
|
|
42
|
-
return await fn();
|
|
43
|
-
} finally {
|
|
44
|
-
await rm(path, { force: true });
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
async function tryLock(path, staleMs) {
|
|
48
|
-
try {
|
|
49
|
-
const handle = await open(path, "wx", 384);
|
|
50
|
-
await handle.close();
|
|
51
|
-
} catch (error) {
|
|
52
|
-
if (error.code !== "EEXIST") throw error;
|
|
53
|
-
const age = await stat(path).then(
|
|
54
|
-
(stats) => Date.now() - stats.mtimeMs,
|
|
55
|
-
() => 0
|
|
56
|
-
);
|
|
57
|
-
if (age <= staleMs) return void 0;
|
|
58
|
-
await rm(path, { force: true });
|
|
59
|
-
return tryLock(path, staleMs);
|
|
60
|
-
}
|
|
61
|
-
return () => rm(path, { force: true });
|
|
62
|
-
}
|
|
63
|
-
|
|
64
|
-
// src/state.ts
|
|
65
20
|
var AGENT_IDS = ["claude-code", "codex", "cursor", "amp"];
|
|
66
21
|
function statePaths(home) {
|
|
67
22
|
return {
|
|
@@ -114,13 +69,13 @@ async function symlinkTarget(path, depth = 0) {
|
|
|
114
69
|
}
|
|
115
70
|
}
|
|
116
71
|
async function replaceFile(path, contents) {
|
|
117
|
-
const temporary = `${path}.${process.pid}.${
|
|
72
|
+
const temporary = `${path}.${process.pid}.${randomBytes(6).toString("hex")}.tmp`;
|
|
118
73
|
try {
|
|
119
74
|
await writeFile(temporary, contents, { mode: 384 });
|
|
120
75
|
await chmod(temporary, 384);
|
|
121
76
|
await rename(temporary, path);
|
|
122
77
|
} catch (error) {
|
|
123
|
-
await
|
|
78
|
+
await rm(temporary, { force: true }).catch(() => void 0);
|
|
124
79
|
throw error;
|
|
125
80
|
}
|
|
126
81
|
}
|
|
@@ -195,8 +150,6 @@ async function updateUsage(home, update, now = /* @__PURE__ */ new Date()) {
|
|
|
195
150
|
}
|
|
196
151
|
|
|
197
152
|
export {
|
|
198
|
-
withLock,
|
|
199
|
-
tryLock,
|
|
200
153
|
AGENT_IDS,
|
|
201
154
|
statePaths,
|
|
202
155
|
ensureHome,
|
|
@@ -29,18 +29,17 @@ function refillCommand(script) {
|
|
|
29
29
|
];
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
|
-
function
|
|
32
|
+
function startDrain(script = process.argv[1]) {
|
|
33
33
|
return new Promise((resolve) => {
|
|
34
34
|
try {
|
|
35
35
|
if (!script) return resolve(false);
|
|
36
36
|
const child = spawn(process.execPath, [...process.execArgv, script, "pay"], {
|
|
37
37
|
detached: true,
|
|
38
38
|
env: process.env,
|
|
39
|
-
stdio:
|
|
39
|
+
stdio: "ignore"
|
|
40
40
|
});
|
|
41
41
|
child.on("error", () => resolve(false));
|
|
42
|
-
child.
|
|
43
|
-
child.stdin.end(payload, () => {
|
|
42
|
+
child.on("spawn", () => {
|
|
44
43
|
child.unref();
|
|
45
44
|
resolve(true);
|
|
46
45
|
});
|
|
@@ -52,5 +51,5 @@ function startPayment(payload, script = process.argv[1]) {
|
|
|
52
51
|
|
|
53
52
|
export {
|
|
54
53
|
startRefill,
|
|
55
|
-
|
|
54
|
+
startDrain
|
|
56
55
|
};
|
|
@@ -3,11 +3,12 @@ const require = __patronCreateRequire(import.meta.url)
|
|
|
3
3
|
import {
|
|
4
4
|
HOOK_TIMEOUT_MS,
|
|
5
5
|
MAX_DOMAINS_PER_HOOK,
|
|
6
|
+
PAY_TIMEOUT_MS,
|
|
6
7
|
hookDomains,
|
|
7
8
|
parseHookInput,
|
|
8
9
|
payableDomain,
|
|
9
10
|
turnEnd
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-HVTTV2A5.js";
|
|
11
12
|
import {
|
|
12
13
|
FileTokenStore,
|
|
13
14
|
codexHome,
|
|
@@ -15,7 +16,7 @@ import {
|
|
|
15
16
|
needsRefill,
|
|
16
17
|
redeem,
|
|
17
18
|
refillSize
|
|
18
|
-
} from "./chunk-
|
|
19
|
+
} from "./chunk-NQ6RRPM6.js";
|
|
19
20
|
import {
|
|
20
21
|
clampTokensPerPage,
|
|
21
22
|
settingsFor
|
|
@@ -24,9 +25,11 @@ import {
|
|
|
24
25
|
readConfig,
|
|
25
26
|
readUsage,
|
|
26
27
|
updateUsage,
|
|
27
|
-
withLock,
|
|
28
28
|
writePrivateFile
|
|
29
|
-
} from "./chunk-
|
|
29
|
+
} from "./chunk-SGQ525FB.js";
|
|
30
|
+
import {
|
|
31
|
+
withLock
|
|
32
|
+
} from "./chunk-O64T22EK.js";
|
|
30
33
|
import "./chunk-GTMLTZRN.js";
|
|
31
34
|
|
|
32
35
|
// src/hook.ts
|
|
@@ -208,7 +211,6 @@ function isRecord(value) {
|
|
|
208
211
|
}
|
|
209
212
|
|
|
210
213
|
// src/hook.ts
|
|
211
|
-
var PAY_TIMEOUT_MS = 2e4;
|
|
212
214
|
var ABORT_MARGIN_MS = 500;
|
|
213
215
|
async function runHook(dependencies, timeoutMs = HOOK_TIMEOUT_MS) {
|
|
214
216
|
let timer;
|
|
@@ -0,0 +1,243 @@
|
|
|
1
|
+
import { createRequire as __patronCreateRequire } from 'node:module'
|
|
2
|
+
const require = __patronCreateRequire(import.meta.url)
|
|
3
|
+
import {
|
|
4
|
+
HOOK_TIMEOUT_MS,
|
|
5
|
+
PAY_TIMEOUT_MS,
|
|
6
|
+
hookDomains,
|
|
7
|
+
isCursorPayload,
|
|
8
|
+
parseHookInput,
|
|
9
|
+
turnEnd
|
|
10
|
+
} from "./chunk-HVTTV2A5.js";
|
|
11
|
+
import {
|
|
12
|
+
startDrain,
|
|
13
|
+
startRefill
|
|
14
|
+
} from "./chunk-TV5VLFTD.js";
|
|
15
|
+
import {
|
|
16
|
+
resolveSettings
|
|
17
|
+
} from "./chunk-WZRGCKEK.js";
|
|
18
|
+
import {
|
|
19
|
+
tryLock
|
|
20
|
+
} from "./chunk-O64T22EK.js";
|
|
21
|
+
import "./chunk-GTMLTZRN.js";
|
|
22
|
+
|
|
23
|
+
// src/hook-process.ts
|
|
24
|
+
import { homedir } from "node:os";
|
|
25
|
+
import { join as join2 } from "node:path";
|
|
26
|
+
|
|
27
|
+
// src/pay-queue.ts
|
|
28
|
+
import { randomBytes } from "node:crypto";
|
|
29
|
+
import {
|
|
30
|
+
mkdir,
|
|
31
|
+
readdir,
|
|
32
|
+
readFile,
|
|
33
|
+
rename,
|
|
34
|
+
rm,
|
|
35
|
+
stat,
|
|
36
|
+
utimes,
|
|
37
|
+
writeFile
|
|
38
|
+
} from "node:fs/promises";
|
|
39
|
+
import { join } from "node:path";
|
|
40
|
+
function queuePaths(home) {
|
|
41
|
+
return {
|
|
42
|
+
dir: join(home, "pay-queue"),
|
|
43
|
+
lock: join(home, "pay.lock"),
|
|
44
|
+
start: join(home, "pay.start")
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
var MAX_QUEUED = 500;
|
|
48
|
+
var PAY_CONCURRENCY = 8;
|
|
49
|
+
var DRAIN_STALE_MS = 6e4;
|
|
50
|
+
var START_STALE_MS = 15e3;
|
|
51
|
+
async function enqueue(home, event) {
|
|
52
|
+
try {
|
|
53
|
+
const { dir } = queuePaths(home);
|
|
54
|
+
await mkdir(dir, { recursive: true, mode: 448 });
|
|
55
|
+
if ((await queued(dir)).length >= MAX_QUEUED) return void 0;
|
|
56
|
+
const name = `${String(Date.now()).padStart(15, "0")}-${randomBytes(6).toString("hex")}.json`;
|
|
57
|
+
const temporary = join(dir, `.${name}.tmp`);
|
|
58
|
+
await writeFile(temporary, JSON.stringify(event), { mode: 384 });
|
|
59
|
+
const path = join(dir, name);
|
|
60
|
+
await rename(temporary, path);
|
|
61
|
+
return path;
|
|
62
|
+
} catch {
|
|
63
|
+
return void 0;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
async function take(path) {
|
|
67
|
+
const taken = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.taken`;
|
|
68
|
+
try {
|
|
69
|
+
await rename(path, taken);
|
|
70
|
+
} catch (error) {
|
|
71
|
+
if (error.code !== "ENOENT")
|
|
72
|
+
await rm(path, { force: true }).catch(() => void 0);
|
|
73
|
+
return void 0;
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const event = JSON.parse(await readFile(taken, "utf8"));
|
|
77
|
+
return typeof event?.raw === "string" ? event : void 0;
|
|
78
|
+
} catch {
|
|
79
|
+
return void 0;
|
|
80
|
+
} finally {
|
|
81
|
+
await rm(taken, { force: true }).catch(() => void 0);
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
async function drainerRunning(home, now = Date.now()) {
|
|
85
|
+
return stat(queuePaths(home).lock).then(
|
|
86
|
+
(stats) => now - stats.mtimeMs <= DRAIN_STALE_MS,
|
|
87
|
+
() => false
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
async function claimStart(home) {
|
|
91
|
+
return tryLock(queuePaths(home).start, START_STALE_MS).catch(() => void 0);
|
|
92
|
+
}
|
|
93
|
+
async function drainQueue(home, options) {
|
|
94
|
+
const { dir, lock, start } = queuePaths(home);
|
|
95
|
+
const deadline = options.deadline ?? Number.POSITIVE_INFINITY;
|
|
96
|
+
let processed = 0;
|
|
97
|
+
for (; ; ) {
|
|
98
|
+
const release = await tryLock(lock, DRAIN_STALE_MS).catch(() => void 0);
|
|
99
|
+
if (!release) return processed;
|
|
100
|
+
await rm(start, { force: true }).catch(() => void 0);
|
|
101
|
+
let pass = 0;
|
|
102
|
+
try {
|
|
103
|
+
pass = await drainHeld(dir, lock, options, deadline);
|
|
104
|
+
} finally {
|
|
105
|
+
await release();
|
|
106
|
+
}
|
|
107
|
+
processed += pass;
|
|
108
|
+
if (pass === 0 || Date.now() >= deadline || (await queued(dir)).length === 0)
|
|
109
|
+
return processed;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
async function drainHeld(dir, lock, options, deadline) {
|
|
113
|
+
let processed = 0;
|
|
114
|
+
let pending = [];
|
|
115
|
+
const seen = /* @__PURE__ */ new Set();
|
|
116
|
+
const next = async () => {
|
|
117
|
+
for (; ; ) {
|
|
118
|
+
if (pending.length === 0)
|
|
119
|
+
pending = (await queued(dir)).filter((name2) => !seen.has(name2));
|
|
120
|
+
const name = pending.shift();
|
|
121
|
+
if (!name) return void 0;
|
|
122
|
+
if (seen.has(name)) continue;
|
|
123
|
+
seen.add(name);
|
|
124
|
+
return name;
|
|
125
|
+
}
|
|
126
|
+
};
|
|
127
|
+
const worker = async () => {
|
|
128
|
+
for (; ; ) {
|
|
129
|
+
if (Date.now() >= deadline) return;
|
|
130
|
+
const name = await next();
|
|
131
|
+
if (!name) return;
|
|
132
|
+
const event = await take(join(dir, name));
|
|
133
|
+
if (!event) continue;
|
|
134
|
+
await options.pay(event).catch(() => void 0);
|
|
135
|
+
processed++;
|
|
136
|
+
const now = /* @__PURE__ */ new Date();
|
|
137
|
+
await utimes(lock, now, now).catch(() => void 0);
|
|
138
|
+
}
|
|
139
|
+
};
|
|
140
|
+
const workers = Math.max(1, options.concurrency ?? PAY_CONCURRENCY);
|
|
141
|
+
await Promise.all(Array.from({ length: workers }, worker));
|
|
142
|
+
return processed;
|
|
143
|
+
}
|
|
144
|
+
async function queuedCount(home) {
|
|
145
|
+
return (await queued(queuePaths(home).dir)).length;
|
|
146
|
+
}
|
|
147
|
+
async function queued(dir) {
|
|
148
|
+
const names = await readdir(dir).catch(() => []);
|
|
149
|
+
return names.filter((name) => name.endsWith(".json") && !name.startsWith(".")).sort();
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
// src/hook-process.ts
|
|
153
|
+
var DRAIN_MAX_MS = 12e4;
|
|
154
|
+
var REFILL_RETRY_MS = 3e4;
|
|
155
|
+
var MAX_INPUT_BYTES = 8 * 1024 * 1024;
|
|
156
|
+
async function runHookProcess(argument = process.argv[3]) {
|
|
157
|
+
const started = Date.now();
|
|
158
|
+
setTimeout(() => process.exit(0), HOOK_TIMEOUT_MS + 500).unref();
|
|
159
|
+
const raw = argument ?? await readStdin(HOOK_TIMEOUT_MS / 2);
|
|
160
|
+
const payload = parseHookInput(raw);
|
|
161
|
+
if (isCursorPayload(payload)) process.stdout.write("{}\n");
|
|
162
|
+
if (!turnEnd(payload) && hookDomains(payload).length === 0) return;
|
|
163
|
+
const settings = resolveSettings();
|
|
164
|
+
const event = {
|
|
165
|
+
raw,
|
|
166
|
+
codexHome: process.env.CODEX_HOME || join2(homedir(), ".codex")
|
|
167
|
+
};
|
|
168
|
+
const path = await enqueue(settings.home, event);
|
|
169
|
+
if (path) {
|
|
170
|
+
if (await drainerRunning(settings.home)) return;
|
|
171
|
+
const claim = await claimStart(settings.home);
|
|
172
|
+
if (!claim) return;
|
|
173
|
+
if (await startDrain()) return;
|
|
174
|
+
await claim();
|
|
175
|
+
const own = await take(path);
|
|
176
|
+
if (!own) return;
|
|
177
|
+
}
|
|
178
|
+
await payEvent(
|
|
179
|
+
event,
|
|
180
|
+
settings,
|
|
181
|
+
() => startRefill(),
|
|
182
|
+
started + HOOK_TIMEOUT_MS - Date.now()
|
|
183
|
+
);
|
|
184
|
+
}
|
|
185
|
+
async function runPayProcess() {
|
|
186
|
+
setTimeout(() => process.exit(0), DRAIN_MAX_MS + PAY_TIMEOUT_MS + 5e3).unref();
|
|
187
|
+
const settings = resolveSettings();
|
|
188
|
+
const raw = await readStdin(HOOK_TIMEOUT_MS);
|
|
189
|
+
if (raw.trim()) await enqueue(settings.home, { raw });
|
|
190
|
+
let refilledAt = Number.NEGATIVE_INFINITY;
|
|
191
|
+
const refill = () => {
|
|
192
|
+
if (Date.now() - refilledAt < REFILL_RETRY_MS) return;
|
|
193
|
+
refilledAt = Date.now();
|
|
194
|
+
startRefill();
|
|
195
|
+
};
|
|
196
|
+
await drainQueue(settings.home, {
|
|
197
|
+
deadline: Date.now() + DRAIN_MAX_MS,
|
|
198
|
+
pay: (event) => payEvent(event, settings, refill, PAY_TIMEOUT_MS)
|
|
199
|
+
});
|
|
200
|
+
if (!await drainerRunning(settings.home) && await queuedCount(settings.home) > 0)
|
|
201
|
+
await startDrain();
|
|
202
|
+
}
|
|
203
|
+
async function payEvent(event, settings, refill, timeoutMs) {
|
|
204
|
+
if (timeoutMs <= 0) return;
|
|
205
|
+
const { runHook } = await import("./hook-OZRD6I6F.js");
|
|
206
|
+
await runHook(
|
|
207
|
+
{
|
|
208
|
+
readInput: async () => event.raw,
|
|
209
|
+
settings,
|
|
210
|
+
startRefill: refill,
|
|
211
|
+
...event.codexHome ? { agents: { env: { CODEX_HOME: event.codexHome }, home: homedir() } } : {}
|
|
212
|
+
},
|
|
213
|
+
timeoutMs
|
|
214
|
+
);
|
|
215
|
+
}
|
|
216
|
+
function readStdin(timeoutMs) {
|
|
217
|
+
return new Promise((resolve) => {
|
|
218
|
+
const chunks = [];
|
|
219
|
+
let size = 0;
|
|
220
|
+
const finish = () => {
|
|
221
|
+
clearTimeout(timer);
|
|
222
|
+
process.stdin.removeAllListeners();
|
|
223
|
+
process.stdin.pause();
|
|
224
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
225
|
+
};
|
|
226
|
+
const timer = setTimeout(finish, timeoutMs);
|
|
227
|
+
process.stdin.on("data", (chunk) => {
|
|
228
|
+
size += chunk.length;
|
|
229
|
+
if (size > MAX_INPUT_BYTES) {
|
|
230
|
+
chunks.length = 0;
|
|
231
|
+
finish();
|
|
232
|
+
return;
|
|
233
|
+
}
|
|
234
|
+
chunks.push(chunk);
|
|
235
|
+
});
|
|
236
|
+
process.stdin.on("end", finish);
|
|
237
|
+
process.stdin.on("error", finish);
|
|
238
|
+
});
|
|
239
|
+
}
|
|
240
|
+
export {
|
|
241
|
+
runHookProcess,
|
|
242
|
+
runPayProcess
|
|
243
|
+
};
|
|
@@ -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-SGQ525FB.js";
|
|
6
|
+
import "./chunk-O64T22EK.js";
|
|
6
7
|
import "./chunk-GTMLTZRN.js";
|
|
7
8
|
|
|
8
9
|
// src/wallet.ts
|
package/package.json
CHANGED
|
@@ -1,75 +0,0 @@
|
|
|
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-5GS6AZ5L.js";
|
|
10
|
-
import {
|
|
11
|
-
startPayment,
|
|
12
|
-
startRefill
|
|
13
|
-
} from "./chunk-HEQBEBKL.js";
|
|
14
|
-
import {
|
|
15
|
-
resolveSettings
|
|
16
|
-
} from "./chunk-WZRGCKEK.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-AHF4ELOX.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-AHF4ELOX.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
|
-
};
|