@tekmidian/pai 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.claude-plugin/plugin.json +1 -1
- package/dist/{auto-route-B4azPk4l.mjs → auto-route-21GdHL70.mjs} +2 -2
- package/dist/auto-route-C3S2W3Bc.mjs +11 -0
- package/dist/{budget-Dod6rnA9.mjs → budget-BrloTOZW.mjs} +1 -1
- package/dist/{chain-D-yvET_y.mjs → chain-D7PFur8Y.mjs} +2 -2
- package/dist/cli/index.mjs +82 -198
- package/dist/{cockpit-actions-BWunx3rY.mjs → cockpit-actions-BfRMr2sm.mjs} +6 -6
- package/dist/{cockpit-actions-C8GlTzts.mjs → cockpit-actions-OodH_vx_.mjs} +20 -18
- package/dist/{cockpit-memory-vTlFWV7F.mjs → cockpit-memory-teG9M8bG.mjs} +6 -6
- package/dist/config/defaults/config.yaml +6 -0
- package/dist/{controls-BcKFHeG1.mjs → controls-JLm6g0yP.mjs} +7 -5
- package/dist/daemon/index.mjs +23 -23
- package/dist/daemon-DeYImF1F.mjs +45 -0
- package/dist/daemon-mcp/index.mjs +21 -21
- package/dist/{daemon-ColVHwGZ.mjs → daemon-nXanenDM.mjs} +23 -19
- package/dist/{detect-9CZNO0yf.mjs → detect-BLKsUOgG.mjs} +2 -2
- package/dist/{detect-D1ziFFfA.mjs → detect-Rrimh0xc.mjs} +3 -3
- package/dist/{embed-pass-DIWjA68P.mjs → embed-pass-e64AwDCa.mjs} +1 -1
- package/dist/{endreason-C577xIQz.mjs → endreason-BC-v05H_.mjs} +17 -3
- package/dist/{factory-DjAAsqr_.mjs → factory-B7nv75rC.mjs} +2 -2
- package/dist/{factory-Bsib-qDG.mjs → factory-Bs9imVMq.mjs} +2 -2
- package/dist/{fallback-DFlItw1Z.mjs → fallback-CBWpp2F2.mjs} +227 -5
- package/dist/{health-Dnym-qcT.mjs → health-C4FQmkJn.mjs} +2 -2
- package/dist/{helpers-BD6V-p9w.mjs → helpers-DSNK_1KP.mjs} +2 -2
- package/dist/{helpers-CMGjy_0N.mjs → helpers-Dz7mjTSw.mjs} +3 -3
- package/dist/hooks/capture-all-events.mjs +21 -2
- package/dist/hooks/capture-tool-output.mjs +21 -2
- package/dist/hooks/worker-pool-host.mjs +167 -124
- package/dist/hooks/worker-status-line.mjs +34 -6
- package/dist/index.mjs +4 -4
- package/dist/{indexer-backend-_a6UNhXJ.mjs → indexer-backend-BdjeL4P8.mjs} +32 -229
- package/dist/{ipc-client-CaiGJnSM.mjs → ipc-client-CnYEF31R.mjs} +1 -1
- package/dist/{ipc-client-ZRmDKd5Z.mjs → ipc-client-DN7EvoVo.mjs} +1 -1
- package/dist/{kill-tree-EWYaEk5v.mjs → kill-tree-DleMNZX3.mjs} +2 -2
- package/dist/{kill-tree-BG7dRVtp.mjs → kill-tree-SV6hrIa3.mjs} +2 -2
- package/dist/{launch-Jh5NVeNe.mjs → launch-Di7N-J5X.mjs} +2 -2
- package/dist/{launch-CXVlZjHt.mjs → launch-DlZTKE3u.mjs} +2 -2
- package/dist/{main-config-ops-BEMpuhDz.mjs → main-config-ops-kTXR8Pyv.mjs} +1 -1
- package/dist/{main-resolver-3Ns1HPmS.mjs → main-resolver-yp_puSSb.mjs} +5 -5
- package/dist/{model-inventory-BFVSNFT3.mjs → model-inventory-h6Z9fN_o.mjs} +1 -1
- package/dist/{models-add-BtB3Se6f.mjs → models-add-TVni3A7V.mjs} +22 -22
- package/dist/{pai-marker-DurzIbw8.mjs → pai-marker-BcZyJguM.mjs} +2 -2
- package/dist/{pane-audit-BQytYa60.mjs → pane-audit-Lqy9N_Ki.mjs} +23 -5
- package/dist/{planner-BM27GBfC.mjs → planner-j77ndkBf.mjs} +14 -14
- package/dist/{pool-BRvoOkv6.mjs → pool-Dh-q3iJi.mjs} +43 -4
- package/dist/{pool-cli-B_YR8_Gl.mjs → pool-cli-BggU8GRp.mjs} +2 -2
- package/dist/{pool-cli-DkZTAlSW.mjs → pool-cli-DQ6OzRy2.mjs} +2 -2
- package/dist/{postgres-BdBNkL_l.mjs → postgres-BK4FP9Zg.mjs} +1 -1
- package/dist/{postgres-C6ti4haA.mjs → postgres-DNIOQijl.mjs} +17 -7
- package/dist/{project-setup-CfpApz5o.mjs → project-setup-CBRtFFh0.mjs} +16 -236
- package/dist/{providers-CblTFrhz.mjs → providers-C9QC0TtO.mjs} +2 -2
- package/dist/{providers-BeDiVEb-.mjs → providers-FvCLzFge.mjs} +2 -2
- package/dist/{query-feedback-BRfPtqki.mjs → query-feedback-DN52N9C5.mjs} +1 -1
- package/dist/{registrable-C7b6givx.mjs → registrable-BzH4TObg.mjs} +3 -3
- package/dist/{registrable-Uzgmfyhz.mjs → registrable-DpyTtajg.mjs} +2 -2
- package/dist/{render-Cc2j5QG9.mjs → render-B35bQTE-.mjs} +4 -4
- package/dist/{render-CwIrgxLi.mjs → render-C84BqQRC.mjs} +3 -3
- package/dist/{root-BWy0c2Lq.mjs → root-C4oXlXS_.mjs} +7 -7
- package/dist/{root-wC_6Fx0B.mjs → root-DD1xx_Vu.mjs} +16 -16
- package/dist/route-table-FEfDuhIV.mjs +15 -0
- package/dist/{routing-BAAST9vT.mjs → routing-DmkheCRH.mjs} +126 -8
- package/dist/{routing-CENt4HH1.mjs → routing-f2zulGwD.mjs} +1 -1
- package/dist/{run-6Q9kCPem.mjs → run-BwZKBJZZ.mjs} +28 -14
- package/dist/{scan-ZQWm-_se.mjs → scan-BBGvU5EB.mjs} +4 -4
- package/dist/{session-Bok2PqRS.mjs → session-BAhtXdxj.mjs} +15 -15
- package/dist/{session-DVUExUnX.mjs → session-Dn5OJXlg.mjs} +23 -23
- package/dist/{session-scan-BJI_ZO8M.mjs → session-scan-B57dNuA4.mjs} +1 -1
- package/dist/{session-scan-W-gbwJHM.mjs → session-scan-DUn10MBd.mjs} +2 -2
- package/dist/session-usage-CPvXvSkw.mjs +222 -0
- package/dist/{sources-ESUkZaWv.mjs → sources-CiE3rZek.mjs} +1 -1
- package/dist/{viewer-MWBVJP3u.mjs → viewer-DEySE4c_.mjs} +8 -8
- package/dist/{viewer-DcpJwGKE.mjs → viewer-wfKnvnrI.mjs} +6 -6
- package/dist/{worker-config-gmAq_-rI.mjs → worker-config-CO5FXLAT.mjs} +21 -21
- package/dist/{worker-config-BDYNxbYz.mjs → worker-config-eY5Qy4vl.mjs} +322 -25
- package/dist/{worktree-CrnOqTBW.mjs → worktree-CRs2gyg0.mjs} +2 -2
- package/dist/{zettelkasten-BzMm8REH.mjs → zettelkasten-_h_tUm2T.mjs} +1 -1
- package/dist/{zettelkasten-B_rRRRvD.mjs → zettelkasten-tpCRBYvH.mjs} +2 -2
- package/docs/cockpit.md +1 -0
- package/docs/images/architecture.png +0 -0
- package/gemini-extension.json +1 -1
- package/package.json +1 -1
- package/pai-plugin.json +1 -1
- package/plugins/context-preservation/plugin.json +1 -1
- package/plugins/core/plugin.json +1 -1
- package/plugins/creative/plugin.json +1 -1
- package/plugins/observability/plugin.json +1 -1
- package/plugins/productivity/plugin.json +1 -1
- package/plugins/semantic-search/plugin.json +1 -1
- package/plugins/ui/plugin.json +1 -1
- package/plugins/zettelkasten/plugin.json +1 -1
- package/src/hooks/ts/capture-all-events.ts +15 -3
- package/src/hooks/ts/lib/raw-capture.ts +7 -0
- package/src/hooks/ts/post-tool-use/capture-tool-output.ts +13 -3
- package/dist/auto-route-BjoMHKyI.mjs +0 -11
- package/dist/daemon-N7WhYi6I.mjs +0 -45
- package/dist/route-table-B7zpoypi.mjs +0 -15
|
@@ -2,11 +2,233 @@ import { l as claudeHomeDir, t as aibrokerHomeDir } from "./runtime-paths-WsO9sJ
|
|
|
2
2
|
import { F as writeWorkersSection, N as resolveModelCapability, P as resolveProviderKey, c as WorkersConfigError, j as readWorkersSection } from "./config-XpZWOYOG.mjs";
|
|
3
3
|
import { D as readJsonStrict, O as writeJsonAtomic } from "./config-Bu1_vbY8.mjs";
|
|
4
4
|
import { u as workersLogDir } from "./paths-CHifubDh.mjs";
|
|
5
|
-
import { _ as resolveTarget } from "./routing-
|
|
5
|
+
import { _ as resolveTarget } from "./routing-DmkheCRH.mjs";
|
|
6
|
+
import { yt as psTable } from "./controls-JLm6g0yP.mjs";
|
|
6
7
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
7
|
-
import { join } from "node:path";
|
|
8
|
-
import { execFileSync } from "node:child_process";
|
|
8
|
+
import { isAbsolute, join, relative } from "node:path";
|
|
9
|
+
import { execFileSync, spawn } from "node:child_process";
|
|
10
|
+
import { fileURLToPath } from "node:url";
|
|
9
11
|
|
|
12
|
+
//#region src/workers/hang-probe.ts
|
|
13
|
+
/**
|
|
14
|
+
* hang-probe.ts — `pai worker test-run -- <command>`: runs a test command and, when it goes silent,
|
|
15
|
+
* tells the model WHERE it is stuck.
|
|
16
|
+
*
|
|
17
|
+
* A synchronous infinite loop blocks Node's event loop, so the test runner cannot even report its own
|
|
18
|
+
* timeout and the model sees nothing. Node's `--report-on-signal` does not help: it is serviced by the
|
|
19
|
+
* event loop (measured: a `while(true){}` process never writes the report). The child therefore runs with a
|
|
20
|
+
* preloaded watchdog (NODE_OPTIONS --require): a worker thread per process that, when a trigger file appears,
|
|
21
|
+
* attaches the inspector to the main thread, pauses it (V8 interrupts a running loop) and writes the call
|
|
22
|
+
* frames. After the command was silent for the idle threshold the wrapper triggers every node process under
|
|
23
|
+
* it and maps the frames to the worktree's files. The worker guard rewrites test commands into this wrapper
|
|
24
|
+
* (see wrapTestCommand).
|
|
25
|
+
*/
|
|
26
|
+
/** Marker line every diagnosis carries; the loop guard keys on it. */
|
|
27
|
+
const HANG_MARKER = "[pai hang probe]";
|
|
28
|
+
const DEFAULT_IDLE_SECS = 60;
|
|
29
|
+
/** Seconds of the first `timeout N` in the command, else null. */
|
|
30
|
+
function timeoutSecs(command) {
|
|
31
|
+
const m = /\b(?:g?timeout)\s+(?:-[ks]\s+\S+\s+|-\S+\s+)*(\d+(?:\.\d+)?)([smhd]?)\b/.exec(command);
|
|
32
|
+
if (!m) return null;
|
|
33
|
+
return Number(m[1]) * {
|
|
34
|
+
"": 1,
|
|
35
|
+
s: 1,
|
|
36
|
+
m: 60,
|
|
37
|
+
h: 3600,
|
|
38
|
+
d: 86400
|
|
39
|
+
}[m[2]];
|
|
40
|
+
}
|
|
41
|
+
function killQuiet(pid, sig) {
|
|
42
|
+
try {
|
|
43
|
+
process.kill(pid, sig);
|
|
44
|
+
} catch {}
|
|
45
|
+
}
|
|
46
|
+
function rmQuiet(f) {
|
|
47
|
+
try {
|
|
48
|
+
unlinkSync(f);
|
|
49
|
+
} catch {}
|
|
50
|
+
}
|
|
51
|
+
const shq = (s) => `'${s.replace(/'/g, `'\\''`)}'`;
|
|
52
|
+
/** The command line test-run executes: the decoded --cmd-b64 payload, else the words after `--`, each shell-quoted. */
|
|
53
|
+
function commandToRun(cmdB64, words) {
|
|
54
|
+
if (cmdB64) return Buffer.from(cmdB64, "base64").toString("utf8");
|
|
55
|
+
return words.map(shq).join(" ");
|
|
56
|
+
}
|
|
57
|
+
/** Call frames of one probed process, user code only, files relative to cwd. */
|
|
58
|
+
function userFrames(frames, cwd) {
|
|
59
|
+
const out = [];
|
|
60
|
+
for (const f of frames) {
|
|
61
|
+
let file = f.url;
|
|
62
|
+
if (file.startsWith("file://")) try {
|
|
63
|
+
file = fileURLToPath(file);
|
|
64
|
+
} catch {
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
if (!file || file.startsWith("node:") || file.includes("node_modules") || !isAbsolute(file)) continue;
|
|
68
|
+
const rel = relative(cwd, file);
|
|
69
|
+
if (rel.startsWith("..")) continue;
|
|
70
|
+
out.push({
|
|
71
|
+
fn: f.functionName || "(anonymous)",
|
|
72
|
+
file: rel,
|
|
73
|
+
line: f.lineNumber + 1
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
return out;
|
|
77
|
+
}
|
|
78
|
+
/** The model-facing diagnosis for the reports taken after `idleSecs` of silence. */
|
|
79
|
+
function diagnose(probed, cwd, idleSecs) {
|
|
80
|
+
const stuck = probed.map((r) => userFrames(r, cwd)).find((f) => f.length > 0);
|
|
81
|
+
if (stuck) {
|
|
82
|
+
const [top, ...rest] = stuck;
|
|
83
|
+
const via = rest[0] ? ` (called from ${rest[0].file}:${rest[0].line} ${rest[0].fn}())` : "";
|
|
84
|
+
return `${HANG_MARKER} test run hung with no output for ${idleSecs} s; the main thread is stuck in ${top.file}:${top.line} ${top.fn}()${via}. A synchronous loop that never ends blocks the runner's own timeout. Fix that loop; rerunning unchanged will hang again.\n` + stuck.slice(0, 6).map((f) => ` at ${f.fn} (${f.file}:${f.line})`).join("\n");
|
|
85
|
+
}
|
|
86
|
+
return `${HANG_MARKER} test run printed nothing for ${idleSecs} s and the main thread is idle in the event loop: it is waiting (async), not spinning. A test awaits a promise, timer, process or socket that never completes (vitest's own per-test timeout ends it unless the test raised it). Find the await and give it an end; rerunning unchanged will wait again.`;
|
|
87
|
+
}
|
|
88
|
+
function listProcs() {
|
|
89
|
+
try {
|
|
90
|
+
return psTable("pid=,ppid=,command=").split("\n").flatMap((l) => {
|
|
91
|
+
const m = /^\s*(\d+)\s+(\d+)\s+(.*)$/.exec(l);
|
|
92
|
+
return m ? [{
|
|
93
|
+
pid: Number(m[1]),
|
|
94
|
+
ppid: Number(m[2]),
|
|
95
|
+
cmd: m[3]
|
|
96
|
+
}] : [];
|
|
97
|
+
});
|
|
98
|
+
} catch {
|
|
99
|
+
return [];
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
/** Pids of node processes below `root`. */
|
|
103
|
+
function nodeDescendants(root, procs = listProcs()) {
|
|
104
|
+
const seen = new Set([root]);
|
|
105
|
+
for (let grew = true; grew;) {
|
|
106
|
+
grew = false;
|
|
107
|
+
for (const p of procs) if (!seen.has(p.pid) && seen.has(p.ppid)) seen.add(p.pid), grew = true;
|
|
108
|
+
}
|
|
109
|
+
return procs.filter((p) => p.pid !== root && seen.has(p.pid) && /(?:^|\/)node(?:\s|$)/.test(p.cmd)).map((p) => p.pid);
|
|
110
|
+
}
|
|
111
|
+
/** Runs the command, passes its output through, probes once when it goes silent. Resolves to the exit code. */
|
|
112
|
+
async function runProbed(o) {
|
|
113
|
+
const out = o.out ?? ((s) => process.stdout.write(s));
|
|
114
|
+
const err = o.err ?? ((s) => process.stderr.write(s));
|
|
115
|
+
mkdirSync(o.reportDir, { recursive: true });
|
|
116
|
+
const t = timeoutSecs(o.command);
|
|
117
|
+
const idle = Math.max(2, Math.min(o.idleSecs ?? DEFAULT_IDLE_SECS, t !== null ? t - 8 : Infinity));
|
|
118
|
+
const preload = join(o.reportDir, "preload.cjs");
|
|
119
|
+
writeFileSync(preload, PRELOAD_SOURCE);
|
|
120
|
+
const env = {
|
|
121
|
+
...process.env,
|
|
122
|
+
PAI_HANG_PROBE_DIR: o.reportDir,
|
|
123
|
+
NODE_OPTIONS: `${process.env.NODE_OPTIONS ?? ""} --require=${preload}`.trim()
|
|
124
|
+
};
|
|
125
|
+
const child = spawn("bash", ["-c", o.command], {
|
|
126
|
+
cwd: o.cwd,
|
|
127
|
+
env,
|
|
128
|
+
stdio: [
|
|
129
|
+
"ignore",
|
|
130
|
+
"pipe",
|
|
131
|
+
"pipe"
|
|
132
|
+
]
|
|
133
|
+
});
|
|
134
|
+
let last = Date.now();
|
|
135
|
+
let probing = false;
|
|
136
|
+
let announcedIdle = false;
|
|
137
|
+
let spun = false;
|
|
138
|
+
let pending = Promise.resolve();
|
|
139
|
+
child.stdout.on("data", (d) => (last = Date.now(), out(d.toString())));
|
|
140
|
+
child.stderr.on("data", (d) => (last = Date.now(), err(d.toString())));
|
|
141
|
+
const timer = setInterval(() => {
|
|
142
|
+
if (probing || spun || Date.now() - last < idle * 1e3 || !child.pid) return;
|
|
143
|
+
probing = true;
|
|
144
|
+
const pids = nodeDescendants(child.pid);
|
|
145
|
+
for (const p of pids) writeFileSync(join(o.reportDir, `probe-${p}`), "");
|
|
146
|
+
pending = collectFrames(o.reportDir, pids, 3e3).then((frames) => {
|
|
147
|
+
for (const p of pids) rmQuiet(join(o.reportDir, `probe-${p}`));
|
|
148
|
+
const stuck = frames.some((f) => userFrames(f, o.cwd).length > 0);
|
|
149
|
+
if (stuck || !announcedIdle) err(`\n${diagnose(frames, o.cwd, idle)}\n`);
|
|
150
|
+
announcedIdle = true;
|
|
151
|
+
probing = false;
|
|
152
|
+
if (stuck) {
|
|
153
|
+
spun = true;
|
|
154
|
+
for (const p of [...pids, child.pid]) killQuiet(p, "SIGTERM");
|
|
155
|
+
setTimeout(() => pids.forEach((p) => killQuiet(p, "SIGKILL")), 2e3).unref();
|
|
156
|
+
}
|
|
157
|
+
});
|
|
158
|
+
}, 1e3);
|
|
159
|
+
return await new Promise((resolve) => {
|
|
160
|
+
child.on("close", (code, sig) => {
|
|
161
|
+
clearInterval(timer);
|
|
162
|
+
pending.then(() => resolve(spun ? 124 : code ?? (sig ? 128 + (sig === "SIGKILL" ? 9 : 15) : 1)));
|
|
163
|
+
});
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
/** Frames each probed pid reported (empty list: its main thread was idle); pids that never answered are left out. */
|
|
167
|
+
async function collectFrames(dir, pids, waitMs) {
|
|
168
|
+
const got = /* @__PURE__ */ new Map();
|
|
169
|
+
for (const end = Date.now() + waitMs; Date.now() < end && got.size < pids.length;) {
|
|
170
|
+
for (const p of pids) {
|
|
171
|
+
const f = join(dir, `frames-${p}.json`);
|
|
172
|
+
if (got.has(p) || !existsSync(f)) continue;
|
|
173
|
+
try {
|
|
174
|
+
got.set(p, JSON.parse(readFileSync(f, "utf8")).frames);
|
|
175
|
+
unlinkSync(f);
|
|
176
|
+
} catch {}
|
|
177
|
+
}
|
|
178
|
+
await new Promise((r) => setTimeout(r, 100));
|
|
179
|
+
}
|
|
180
|
+
return [...got.values()];
|
|
181
|
+
}
|
|
182
|
+
/** Preloaded into every node process of the test run (CommonJS, so it also loads under --require). */
|
|
183
|
+
const PRELOAD_SOURCE = `"use strict";
|
|
184
|
+
const { Worker, isMainThread } = require("node:worker_threads");
|
|
185
|
+
if (isMainThread) {
|
|
186
|
+
const code = \`
|
|
187
|
+
const { existsSync, unlinkSync, writeFileSync, renameSync } = require("node:fs");
|
|
188
|
+
const { Session } = require("node:inspector");
|
|
189
|
+
const { workerData } = require("node:worker_threads");
|
|
190
|
+
const trigger = workerData.dir + "/probe-" + workerData.pid;
|
|
191
|
+
const done = (frames) => {
|
|
192
|
+
const tmp = workerData.dir + "/tmp-" + workerData.pid;
|
|
193
|
+
writeFileSync(tmp, JSON.stringify({ frames }));
|
|
194
|
+
renameSync(tmp, workerData.dir + "/frames-" + workerData.pid + ".json");
|
|
195
|
+
};
|
|
196
|
+
setInterval(() => {
|
|
197
|
+
if (!existsSync(trigger)) return;
|
|
198
|
+
try { unlinkSync(trigger); } catch {}
|
|
199
|
+
const s = new Session();
|
|
200
|
+
s.connectToMainThread();
|
|
201
|
+
let answered = false;
|
|
202
|
+
const urls = {}, maps = {};
|
|
203
|
+
s.on("Debugger.scriptParsed", (m) => { urls[m.params.scriptId] = m.params.url; maps[m.params.scriptId] = m.params.sourceMapURL; });
|
|
204
|
+
// transformed code (vite-node, tsx) has shifted lines: map back through its inline source map
|
|
205
|
+
const where = (f) => {
|
|
206
|
+
const id = f.location.scriptId;
|
|
207
|
+
let url = urls[id] || f.url, line = f.location.lineNumber;
|
|
208
|
+
const m = /^data:[^,]*;base64,(.*)$/.exec(maps[id] || "");
|
|
209
|
+
if (m) try {
|
|
210
|
+
const e = new (require("node:module").SourceMap)(JSON.parse(Buffer.from(m[1], "base64").toString())).findEntry(line, f.location.columnNumber || 0);
|
|
211
|
+
if (e && e.originalSource) { url = new URL(e.originalSource, url).href; line = e.originalLine; }
|
|
212
|
+
} catch {}
|
|
213
|
+
return { functionName: f.functionName, url, lineNumber: line };
|
|
214
|
+
};
|
|
215
|
+
s.on("Debugger.paused", (m) => {
|
|
216
|
+
answered = true;
|
|
217
|
+
done(m.params.callFrames.map(where));
|
|
218
|
+
s.post("Debugger.resume", () => s.post("Debugger.disable", () => s.disconnect()));
|
|
219
|
+
});
|
|
220
|
+
s.post("Debugger.enable", () => s.post("Debugger.pause"));
|
|
221
|
+
// an idle event loop runs no JS to pause in
|
|
222
|
+
setTimeout(() => { if (!answered) { done([]); s.post("Debugger.disable", () => s.disconnect()); } }, 800);
|
|
223
|
+
}, 200);
|
|
224
|
+
\`;
|
|
225
|
+
try {
|
|
226
|
+
new Worker(code, { eval: true, workerData: { dir: process.env.PAI_HANG_PROBE_DIR, pid: process.pid } }).unref();
|
|
227
|
+
} catch {}
|
|
228
|
+
}
|
|
229
|
+
`;
|
|
230
|
+
|
|
231
|
+
//#endregion
|
|
10
232
|
//#region src/workers/fallback.ts
|
|
11
233
|
/**
|
|
12
234
|
* fallback.ts — machine-wide Claude Code fallback to a worker provider.
|
|
@@ -271,5 +493,5 @@ function fallbackStatusText(s) {
|
|
|
271
493
|
}
|
|
272
494
|
|
|
273
495
|
//#endregion
|
|
274
|
-
export { fallbackStatusText as i, fallbackOn as n, fallbackStatus as r, fallbackOff as t };
|
|
275
|
-
//# sourceMappingURL=fallback-
|
|
496
|
+
export { DEFAULT_IDLE_SECS as a, fallbackStatusText as i, fallbackOn as n, commandToRun as o, fallbackStatus as r, runProbed as s, fallbackOff as t };
|
|
497
|
+
//# sourceMappingURL=fallback-CBWpp2F2.mjs.map
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { g as paiHomePath } from "./runtime-paths-WsO9sJFc.mjs";
|
|
2
2
|
import { t as ANTHROPIC_NATIVE } from "./config-XpZWOYOG.mjs";
|
|
3
|
-
import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-
|
|
3
|
+
import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-DmkheCRH.mjs";
|
|
4
4
|
import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-DLdwQt0s.mjs";
|
|
5
5
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { Chalk } from "chalk";
|
|
@@ -311,4 +311,4 @@ function saveBudgetSnapshot(map, now = Date.now()) {
|
|
|
311
311
|
|
|
312
312
|
//#endregion
|
|
313
313
|
export { colorEnabled as a, renderCommandHelp as c, renderOverview as d, renderTable as f, saveBudgetSnapshot as i, renderMarkdown as l, usageLine as m, readBudget as n, makeStyle as o, suggest as p, readBudgetSnapshot as r, mdCommand as s, providerHealth as t, renderMore as u };
|
|
314
|
-
//# sourceMappingURL=health-
|
|
314
|
+
//# sourceMappingURL=health-C4FQmkJn.mjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as getRegistryBackend } from "./factory-
|
|
1
|
+
import { i as getRegistryBackend } from "./factory-B7nv75rC.mjs";
|
|
2
2
|
|
|
3
3
|
//#region src/cli/impl/project/helpers.ts
|
|
4
4
|
/**
|
|
@@ -66,4 +66,4 @@ async function upsertTag(tagName) {
|
|
|
66
66
|
|
|
67
67
|
//#endregion
|
|
68
68
|
export { getSessionCount as a, upsertTag as c, getProjectTags as i, getProject as n, requireProject as o, getProjectAliases as r, resolveIdentifier as s, getLastSessionDate as t };
|
|
69
|
-
//# sourceMappingURL=helpers-
|
|
69
|
+
//# sourceMappingURL=helpers-DSNK_1KP.mjs.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import "./config-Bu1_vbY8.mjs";
|
|
2
2
|
import "./helpers-CRuBUas3.mjs";
|
|
3
|
-
import "./factory-
|
|
4
|
-
import "./postgres-
|
|
3
|
+
import "./factory-B7nv75rC.mjs";
|
|
4
|
+
import "./postgres-DNIOQijl.mjs";
|
|
5
5
|
import "./embedding-gate-6rZrWRXa.mjs";
|
|
6
6
|
import "./embeddings-BVq3esBF.mjs";
|
|
7
7
|
import "./router-CQSc3lk3.mjs";
|
|
8
|
-
import { a as getSessionCount, c as upsertTag, i as getProjectTags, n as getProject, o as requireProject, r as getProjectAliases, s as resolveIdentifier, t as getLastSessionDate } from "./helpers-
|
|
8
|
+
import { a as getSessionCount, c as upsertTag, i as getProjectTags, n as getProject, o as requireProject, r as getProjectAliases, s as resolveIdentifier, t as getLastSessionDate } from "./helpers-DSNK_1KP.mjs";
|
|
9
9
|
|
|
10
10
|
export { getProject };
|
|
@@ -7738,8 +7738,18 @@ function maskSecrets(text) {
|
|
|
7738
7738
|
return text.split("\n").map((l) => SECRET_LINE.test(l) ? MASKED_LINE : l).join("\n");
|
|
7739
7739
|
}
|
|
7740
7740
|
|
|
7741
|
+
// src/utils/hash.ts
|
|
7742
|
+
import { createHash } from "node:crypto";
|
|
7743
|
+
function sha256(content) {
|
|
7744
|
+
return createHash("sha256").update(content).digest("hex");
|
|
7745
|
+
}
|
|
7746
|
+
|
|
7741
7747
|
// src/hooks/ts/lib/raw-capture.ts
|
|
7742
7748
|
var RAW_CAPTURE_MAX_BYTES = 10 * 1024 * 1024;
|
|
7749
|
+
function captureEventId(parts) {
|
|
7750
|
+
const joined = `${parts.sessionId ?? ""}|${parts.toolUseId ?? ""}|${parts.event ?? ""}|${parts.ts ?? ""}`;
|
|
7751
|
+
return sha256(joined).slice(0, 16);
|
|
7752
|
+
}
|
|
7743
7753
|
function redactDeep(value) {
|
|
7744
7754
|
if (typeof value === "string") return maskSecrets(value);
|
|
7745
7755
|
if (Array.isArray(value)) return value.map(redactDeep);
|
|
@@ -7855,13 +7865,22 @@ async function main() {
|
|
|
7855
7865
|
setAgentForSession(sessionId, agentName);
|
|
7856
7866
|
}
|
|
7857
7867
|
}
|
|
7868
|
+
const timestamp = Date.now();
|
|
7858
7869
|
let event = {
|
|
7859
7870
|
source_app: agentName,
|
|
7860
7871
|
session_id: hookData.session_id || "main",
|
|
7861
7872
|
hook_event_type: eventType,
|
|
7862
7873
|
payload: redactDeep(hookData),
|
|
7863
|
-
timestamp
|
|
7864
|
-
timestamp_local: getLocalTimestamp()
|
|
7874
|
+
timestamp,
|
|
7875
|
+
timestamp_local: getLocalTimestamp(),
|
|
7876
|
+
source: "hook",
|
|
7877
|
+
fidelity: "observed",
|
|
7878
|
+
eventId: captureEventId({
|
|
7879
|
+
sessionId: hookData.session_id,
|
|
7880
|
+
toolUseId: hookData.tool_use_id,
|
|
7881
|
+
event: eventType,
|
|
7882
|
+
ts: String(timestamp)
|
|
7883
|
+
})
|
|
7865
7884
|
};
|
|
7866
7885
|
if (isAgentSpawningCall(hookData.tool_name, hookData.tool_input)) {
|
|
7867
7886
|
event = enrichEventWithAgentMetadata(
|
|
@@ -155,8 +155,18 @@ function maskSecrets(text) {
|
|
|
155
155
|
return text.split("\n").map((l) => SECRET_LINE.test(l) ? MASKED_LINE : l).join("\n");
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
// src/utils/hash.ts
|
|
159
|
+
import { createHash } from "node:crypto";
|
|
160
|
+
function sha256(content) {
|
|
161
|
+
return createHash("sha256").update(content).digest("hex");
|
|
162
|
+
}
|
|
163
|
+
|
|
158
164
|
// src/hooks/ts/lib/raw-capture.ts
|
|
159
165
|
var RAW_CAPTURE_MAX_BYTES = 10 * 1024 * 1024;
|
|
166
|
+
function captureEventId(parts) {
|
|
167
|
+
const joined = `${parts.sessionId ?? ""}|${parts.toolUseId ?? ""}|${parts.event ?? ""}|${parts.ts ?? ""}`;
|
|
168
|
+
return sha256(joined).slice(0, 16);
|
|
169
|
+
}
|
|
160
170
|
function redactDeep(value) {
|
|
161
171
|
if (typeof value === "string") return maskSecrets(value);
|
|
162
172
|
if (Array.isArray(value)) return value.map(redactDeep);
|
|
@@ -202,12 +212,21 @@ async function main() {
|
|
|
202
212
|
const yearMonth = today.substring(0, 7);
|
|
203
213
|
const dateDir = join3(CAPTURE_DIR, yearMonth);
|
|
204
214
|
const captureFile = join3(dateDir, `${today}_tool-outputs.jsonl`);
|
|
215
|
+
const timestamp = data.timestamp || now.toISOString();
|
|
205
216
|
const captureEntry = JSON.stringify({
|
|
206
|
-
timestamp
|
|
217
|
+
timestamp,
|
|
207
218
|
tool: data.tool_name,
|
|
208
219
|
input: redactDeep(data.tool_input),
|
|
209
220
|
output: redactDeep(data.tool_response),
|
|
210
|
-
session: data.session_id
|
|
221
|
+
session: data.session_id,
|
|
222
|
+
source: "hook",
|
|
223
|
+
fidelity: "observed",
|
|
224
|
+
eventId: captureEventId({
|
|
225
|
+
sessionId: data.session_id,
|
|
226
|
+
toolUseId: data.tool_use_id,
|
|
227
|
+
event: "PostToolUse",
|
|
228
|
+
ts: timestamp
|
|
229
|
+
})
|
|
211
230
|
}) + "\n";
|
|
212
231
|
appendRawCapture(captureFile, dateDir, captureEntry);
|
|
213
232
|
process.exit(0);
|