@tekmidian/pai 1.0.5 → 1.0.7
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/{aibroker-client-CQPGqLxL.mjs → aibroker-client-CXsyC7A8.mjs} +2 -2
- package/dist/aibroker-client-ChB7gSxV.mjs +3 -0
- package/dist/auto-route-CAlZ5p-h.mjs +11 -0
- package/dist/{auto-route-DUYr57rs.mjs → auto-route-PDOAYszN.mjs} +2 -2
- package/dist/budget-BXmsSBLI.mjs +15 -0
- package/dist/{caller-identity-Bim8JT-D.mjs → caller-identity-DPDSrZE2.mjs} +4 -4
- package/dist/{capacity-CsZMkVyg.mjs → capacity-CThSydrd.mjs} +82 -10
- package/dist/{chain-Dzz6xcKH.mjs → chain-BvdKqRiZ.mjs} +5 -5
- package/dist/cli/index.mjs +2175 -284
- package/dist/{cockpit-actions-BTA1njMO.mjs → cockpit-actions-BgdKB9G3.mjs} +26 -26
- package/dist/{cockpit-actions-BgsiNcUY.mjs → cockpit-actions-DNl0rKfW.mjs} +18 -18
- package/dist/cockpit-memory-CqLPjcWe.mjs +20 -0
- package/dist/config/defaults/config.yaml +24 -1
- package/dist/config/defaults/workers.yaml +2 -0
- package/dist/{config-h5qK3fst.mjs → config-C2dd2SXS.mjs} +2 -2
- package/dist/{config-CST2uq1v.mjs → config-DGV64YJa.mjs} +11 -3
- package/dist/{config-Dv3t7xnT.mjs → config-DHgPx3ER.mjs} +1 -1
- package/dist/{config-DYbyEe4-.mjs → config-SlZ-Z52i.mjs} +3 -2
- package/dist/{controls-OiVVbe-f.mjs → controls-ByrcupcA.mjs} +59 -66
- package/dist/daemon/index.mjs +40 -40
- package/dist/{daemon-C1dycZ3W.mjs → daemon-BjgJyJMP.mjs} +79 -31
- package/dist/daemon-iymy18Ie.mjs +46 -0
- package/dist/daemon-mcp/index.mjs +49 -38
- package/dist/detect-C8nFP-kR.mjs +10 -0
- package/dist/{detect-CHuxFrLy.mjs → detect-DLjeYwnt.mjs} +2 -2
- package/dist/{embed-pass-DtVF2fOV.mjs → embed-pass-DdTMn4DH.mjs} +5 -5
- package/dist/{embedding-gate-B98PK_wz.mjs → embedding-gate-BVQvUmox.mjs} +2 -2
- package/dist/{embedding-gate-CTAk8STe.mjs → embedding-gate-iq0oQEkF.mjs} +3 -3
- package/dist/{endreason-BqyyU7BH.mjs → endreason-BjPom527.mjs} +4 -4
- package/dist/{factory-BV0MQA3T.mjs → factory-CYwa0jYj.mjs} +6 -6
- package/dist/factory-DFwez99M.mjs +9 -0
- package/dist/{fallback-Bj2cyVk_.mjs → fallback-CQ8_CuVu.mjs} +9 -231
- package/dist/{health-kufVIf6i.mjs → health-Bb2U4PNK.mjs} +5 -5
- package/dist/{helpers-CvbYEKoD.mjs → helpers-Dj2nY56t.mjs} +2 -2
- package/dist/{helpers-WV8tdQHM.mjs → helpers-DyHKAwrW.mjs} +6 -6
- package/dist/hooks/block-sleep-poll.mjs +9 -0
- package/dist/hooks/capture-all-events.mjs +99 -3
- package/dist/hooks/capture-tool-output.mjs +99 -3
- package/dist/hooks/handoff-link.mjs +159 -0
- package/dist/hooks/load-project-context.mjs +10 -1
- package/dist/hooks/local-model-hint.mjs +9 -0
- package/dist/hooks/route-agents-to-worker.mjs +9 -0
- package/dist/hooks/security-validator.mjs +940 -92
- package/dist/hooks/supervision-banner.mjs +219 -48
- package/dist/hooks/worker-edit-repair.mjs +9 -0
- package/dist/hooks/worker-guard.mjs +97 -1
- package/dist/hooks/worker-note.mjs +108 -3
- package/dist/hooks/worker-pool-host.mjs +1670 -315
- package/dist/hooks/worker-proxy.mjs +9 -0
- package/dist/hooks/worker-status-line.mjs +251 -70
- package/dist/hooks/worker-supervision.mjs +9 -0
- package/dist/hooks/worker-tool-name-repair.mjs +9 -0
- package/dist/index.mjs +9 -9
- package/dist/{ipc-client-CnYEF31R.mjs → ipc-client-CmagIFLh.mjs} +2 -2
- package/dist/{ipc-client-DN7EvoVo.mjs → ipc-client-DmbSIBUK.mjs} +1 -1
- package/dist/kill-tree-BlPw1vaU.mjs +10 -0
- package/dist/{kill-tree-CcpsRLCZ.mjs → kill-tree-DTmiEb3T.mjs} +8 -8
- package/dist/{launch-DpQPZGsT.mjs → launch-CV6oPHI2.mjs} +3 -3
- package/dist/{launch-UPQBoW2q.mjs → launch-Dy8qQnSD.mjs} +3 -3
- package/dist/{indexer-backend-B2vtFl38.mjs → lessons-CdmqZD0G.mjs} +262 -43
- package/dist/{local-candidate-Cp_bw4kK.mjs → local-candidate-C2FGhf54.mjs} +3 -3
- package/dist/{local-instances-bdCNNSsL.mjs → local-instances-DhF4_sV2.mjs} +2 -2
- package/dist/{local-instances-B-c-CxzP.mjs → local-instances-GgXydQ2P.mjs} +4 -4
- package/dist/{local-tiers-BtdEEe5n.mjs → local-tiers-CqwGUcEn.mjs} +3 -3
- package/dist/{local-tiers-OBqAAfOg.mjs → local-tiers-X_dQfI4Q.mjs} +3 -3
- package/dist/{main-config-ops-BYsK3BxM.mjs → main-config-ops-C_fkINDv.mjs} +3 -3
- package/dist/{main-resolver-CAC3xfZM.mjs → main-resolver-CN_sfG1R.mjs} +18 -18
- package/dist/{migrate-DrA_OwlZ.mjs → migrate-C2z1YmWC.mjs} +2 -2
- package/dist/{model-inventory-BuTpi9a6.mjs → model-inventory-BYNrSTaY.mjs} +13 -13
- package/dist/{models-add-CJx2YAwh.mjs → models-add-Dc7VXmcu.mjs} +38 -38
- package/dist/operator-IrLbk8hy.mjs +7 -0
- package/dist/{operator-DrwWItVt.mjs → operator-lRGvYr3D.mjs} +2 -2
- package/dist/{pai-marker-DLKJ9Yr5.mjs → pai-marker-kA0iM7rP.mjs} +2 -2
- package/dist/{pane-audit-wv9UkyCe.mjs → pane-audit-DUuilP1V.mjs} +13 -23
- package/dist/{paths-DS5VQKoR.mjs → paths-BwfwHOvN.mjs} +4 -4
- package/dist/{paths-DBd78I7Z.mjs → paths-CKGYM0Lb.mjs} +3 -3
- package/dist/{planner-K0mFrCpL.mjs → planner-BDHVUkIM.mjs} +29 -29
- package/dist/{pool-BZ94nFuq.mjs → pool-CFeHGX7q.mjs} +2 -2
- package/dist/{pool-cli-BjYQDfx6.mjs → pool-cli-Bj2TeA-d.mjs} +6 -6
- package/dist/{pool-cli-B1eKySeN.mjs → pool-cli-DOLgPgOM.mjs} +5 -5
- package/dist/{postgres-CBHY5PIi.mjs → postgres-B1B80bcj.mjs} +3 -3
- package/dist/{postgres-C-T5OWer.mjs → postgres-BL5oBBgY.mjs} +3 -3
- package/dist/{project-setup-pIPHZaXf.mjs → project-setup-i5D0xkTn.mjs} +24 -25
- package/dist/{providers-Dzx5GAUI.mjs → providers-BC2Myo_O.mjs} +6 -6
- package/dist/providers-C-mnlH1b.mjs +16 -0
- package/dist/{query-feedback-DN52N9C5.mjs → query-feedback-BWl2HRwN.mjs} +2 -2
- package/dist/registrable-Ct0DKNKS.mjs +9 -0
- package/dist/{registrable-CXBBpUcz.mjs → registrable-D_4qXCnq.mjs} +4 -4
- package/dist/render-CbifCwTb.mjs +2350 -0
- package/dist/render-FB4Fv_fi.mjs +13 -0
- package/dist/root-80ESg6b7.mjs +36 -0
- package/dist/{root-bG48WVpW.mjs → root-B-ZYiEgi.mjs} +10 -10
- package/dist/route-table-DcBZCuco.mjs +15 -0
- package/dist/{router-CQSc3lk3.mjs → router-D2476pOp.mjs} +2 -2
- package/dist/{router-DwHJRgG9.mjs → router-ghujlEFb.mjs} +1 -1
- package/dist/{routing-BlD_tKjW.mjs → routing-CF0wlR-_.mjs} +15 -15
- package/dist/{routing-D27jxj9x.mjs → routing-CJ8ioPl2.mjs} +13 -13
- package/dist/{run-AZVwceiU.mjs → run-CAjfKBQV.mjs} +74 -31
- package/dist/{runtime-paths-WsO9sJFc.mjs → runtime-paths-twfV23YL.mjs} +2 -2
- package/dist/{scan-C3uotg_f.mjs → scan-ew8M6tTH.mjs} +7 -7
- package/dist/{scope-D8HK6vU7.mjs → scope-BRcaPw5D.mjs} +4 -4
- package/dist/session-BmQsXF_a.mjs +35 -0
- package/dist/{session-BAfypQb9.mjs → session-C1JnDXvP.mjs} +28 -28
- package/dist/session-scan-DWCUKhDM.mjs +9 -0
- package/dist/{session-scan-BmnjSReu.mjs → session-scan-DihMibI-.mjs} +6 -6
- package/dist/{session-usage-oycSdiD3.mjs → session-usage-BRIWFYPS.mjs} +3 -3
- package/dist/status-Bj4yVKj0.mjs +6 -0
- package/dist/{status-COtzewKV.mjs → status-DTMT5lyn.mjs} +9 -5
- package/dist/{tool-errors-DXJ70-sr.mjs → tool-errors-BOW2n882.mjs} +2 -2
- package/dist/{tool-errors-B2LnIqR0.mjs → tool-errors-jNJj3Gzm.mjs} +6 -6
- package/dist/{viewer-BgGRqXfD.mjs → viewer-4BU8w_gK.mjs} +16 -14
- package/dist/viewer-D3VEdqhC.mjs +22 -0
- package/dist/{wait-ChpHKJZV.mjs → wait-BindDA5w.mjs} +3 -3
- package/dist/{worker-config-DgdT0iTB.mjs → worker-config-CdPmb4_2.mjs} +54 -103
- package/dist/worker-config-CfV2dgSb.mjs +42 -0
- package/dist/{workers-config-BhZBrR-Q.mjs → workers-config-2VipVOYk.mjs} +2 -2
- package/dist/{worktree-BY--Rgmy.mjs → worktree-7ZS3RBf8.mjs} +175 -9
- package/dist/{zettelkasten-BHVx5zj-.mjs → zettelkasten-BH8AdNh8.mjs} +4 -4
- package/dist/{zettelkasten-LoH9RBiN.mjs → zettelkasten-FFhQFESJ.mjs} +2 -2
- package/docs/commands/README.md +32 -2
- package/docs/commands/audit.md +34 -3
- package/docs/commands/backup.md +1 -1
- package/docs/commands/build.md +4 -4
- package/docs/commands/cd.md +1 -1
- package/docs/commands/clear-names.md +1 -1
- package/docs/commands/cockpit.md +1 -1
- package/docs/commands/config.md +1 -1
- package/docs/commands/daemon.md +1 -1
- package/docs/commands/db.md +1 -1
- package/docs/commands/doc.md +1 -1
- package/docs/commands/end.md +1 -1
- package/docs/commands/find.md +1 -1
- package/docs/commands/git.md +110 -0
- package/docs/commands/handoff.md +70 -0
- package/docs/commands/harness.md +74 -0
- package/docs/commands/help.md +1 -1
- package/docs/commands/home.md +1 -1
- package/docs/commands/hooks-db.md +1 -1
- package/docs/commands/identity.md +1 -1
- package/docs/commands/install.md +1 -1
- package/docs/commands/issue.md +1 -1
- package/docs/commands/kg.md +1 -1
- package/docs/commands/launch.md +1 -1
- package/docs/commands/lessons.md +201 -0
- package/docs/commands/list.md +1 -1
- package/docs/commands/ls.md +1 -1
- package/docs/commands/mcp.md +1 -1
- package/docs/commands/memory.md +1 -1
- package/docs/commands/models.md +1 -1
- package/docs/commands/more.md +1 -1
- package/docs/commands/new.md +1 -1
- package/docs/commands/notes.md +1 -1
- package/docs/commands/notify.md +1 -1
- package/docs/commands/observation.md +1 -1
- package/docs/commands/obsidian.md +1 -1
- package/docs/commands/open.md +1 -1
- package/docs/commands/pane.md +1 -1
- package/docs/commands/pause.md +1 -1
- package/docs/commands/plan.md +1 -1
- package/docs/commands/project.md +1 -1
- package/docs/commands/projects.md +1 -1
- package/docs/commands/providers.md +1 -1
- package/docs/commands/queue.md +1 -1
- package/docs/commands/registry.md +1 -1
- package/docs/commands/reload.md +1 -1
- package/docs/commands/rename.md +1 -1
- package/docs/commands/restore.md +1 -1
- package/docs/commands/resume.md +1 -1
- package/docs/commands/router.md +1 -1
- package/docs/commands/rules.md +70 -0
- package/docs/commands/session.md +1 -1
- package/docs/commands/sessions.md +1 -1
- package/docs/commands/setup.md +1 -1
- package/docs/commands/setups.md +1 -1
- package/docs/commands/shell-init.md +1 -1
- package/docs/commands/skill.md +1 -1
- package/docs/commands/task.md +1 -1
- package/docs/commands/tasks.md +1 -1
- package/docs/commands/topic.md +1 -1
- package/docs/commands/update.md +1 -1
- package/docs/commands/worker.md +1 -1
- package/docs/commands/zettel.md +1 -1
- package/docs/concepts/panes.md +3 -2
- package/gemini-extension.json +1 -1
- package/package.json +2 -2
- 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/lib/loop-guard.ts +3 -5
- package/src/hooks/ts/lib/rules/builtin/base64-decode-to-shell.rule.yaml +15 -0
- package/src/hooks/ts/lib/rules/builtin/chmod-world-writable.rule.yaml +13 -0
- package/src/hooks/ts/lib/rules/builtin/chmod-zero.rule.yaml +13 -0
- package/src/hooks/ts/lib/rules/builtin/credential-file-read.rule.yaml +13 -0
- package/src/hooks/ts/lib/rules/builtin/credential-read-then-network.rule.yaml +29 -0
- package/src/hooks/ts/lib/rules/builtin/crontab-persistence.rule.yaml +10 -0
- package/src/hooks/ts/lib/rules/builtin/curl-piped-to-shell.rule.yaml +22 -0
- package/src/hooks/ts/lib/rules/builtin/download-then-execute.rule.yaml +30 -0
- package/src/hooks/ts/lib/rules/builtin/find-root-delete.rule.yaml +14 -0
- package/src/hooks/ts/lib/rules/builtin/git-push-force.rule.yaml +24 -0
- package/src/hooks/ts/lib/rules/builtin/git-push-plus-refspec.rule.yaml +12 -0
- package/src/hooks/ts/lib/rules/builtin/git-reset-hard.rule.yaml +12 -0
- package/src/hooks/ts/lib/rules/builtin/injection-then-tool.rule.yaml +30 -0
- package/src/hooks/ts/lib/rules/builtin/instruction-override-disregard.rule.yaml +14 -0
- package/src/hooks/ts/lib/rules/builtin/instruction-override-ignore.rule.yaml +13 -0
- package/src/hooks/ts/lib/rules/builtin/launchagents-write-persistence.rule.yaml +12 -0
- package/src/hooks/ts/lib/rules/builtin/launchctl-load-persistence.rule.yaml +10 -0
- package/src/hooks/ts/lib/rules/builtin/reverse-shell-dev-tcp.rule.yaml +14 -0
- package/src/hooks/ts/lib/rules/builtin/reverse-shell-interactive-bash.rule.yaml +12 -0
- package/src/hooks/ts/lib/rules/builtin/rm-recursive-parent.rule.yaml +13 -0
- package/src/hooks/ts/lib/rules/builtin/rm-recursive-relative.rule.yaml +12 -0
- package/src/hooks/ts/lib/rules/builtin/rm-recursive-root.rule.yaml +27 -0
- package/src/hooks/ts/lib/rules/builtin/rm-trailing-tilde.rule.yaml +12 -0
- package/src/hooks/ts/lib/rules/builtin/sudoers-nopasswd.rule.yaml +15 -0
- package/src/hooks/ts/lib/rules/builtin.generated.ts +557 -0
- package/src/hooks/ts/lib/rules/eval.ts +76 -0
- package/src/hooks/ts/lib/rules/lint.ts +108 -0
- package/src/hooks/ts/lib/rules/load.ts +264 -0
- package/src/hooks/ts/lib/rules/types.ts +58 -0
- package/src/hooks/ts/pre-tool-use/security-validator.ts +35 -96
- package/src/hooks/ts/user-prompt/handoff-link.ts +34 -0
- package/dist/aibroker-client-BxzeEHPF.mjs +0 -3
- package/dist/auto-route-DWYK_0i0.mjs +0 -11
- package/dist/budget-DX-VIWGf.mjs +0 -15
- package/dist/cockpit-memory-DIrNs4xr.mjs +0 -20
- package/dist/daemon-ieo0lnpq.mjs +0 -46
- package/dist/detect-C0ZBXqDL.mjs +0 -10
- package/dist/factory-DeASMV7Z.mjs +0 -9
- package/dist/kill-tree-CXZ0WfVf.mjs +0 -10
- package/dist/operator-Bpxq_WB5.mjs +0 -7
- package/dist/providers-QJzpaNhX.mjs +0 -16
- package/dist/registrable-Drn8wIDO.mjs +0 -9
- package/dist/render-C4KR8qQ8.mjs +0 -13
- package/dist/render-Cz3BWIBO.mjs +0 -903
- package/dist/root-Bfb1zgwE.mjs +0 -36
- package/dist/route-table-ZVMNBsy7.mjs +0 -15
- package/dist/session-BcnhepLZ.mjs +0 -35
- package/dist/session-scan-CqUQdCac.mjs +0 -9
- package/dist/status-D_SWmOlH.mjs +0 -6
- package/dist/viewer-CbGN2Ri4.mjs +0 -22
- package/dist/worker-config-D1KVAMp4.mjs +0 -42
|
@@ -1,234 +1,12 @@
|
|
|
1
|
-
import { l as claudeHomeDir, t as aibrokerHomeDir } from "./runtime-paths-
|
|
2
|
-
import { F as resolveProviderKey, L as writeWorkersSection, M as readWorkersSection, P as resolveModelCapability, c as WorkersConfigError } from "./config-
|
|
3
|
-
import { O as readJsonStrict, k as writeJsonAtomic } from "./config-
|
|
4
|
-
import { u as workersLogDir } from "./paths-
|
|
5
|
-
import { _ as resolveTarget } from "./routing-
|
|
6
|
-
import { yt as psTable } from "./controls-OiVVbe-f.mjs";
|
|
1
|
+
import { l as claudeHomeDir, t as aibrokerHomeDir } from "./runtime-paths-twfV23YL.mjs";
|
|
2
|
+
import { F as resolveProviderKey, L as writeWorkersSection, M as readWorkersSection, P as resolveModelCapability, c as WorkersConfigError } from "./config-DGV64YJa.mjs";
|
|
3
|
+
import { O as readJsonStrict, k as writeJsonAtomic } from "./config-SlZ-Z52i.mjs";
|
|
4
|
+
import { u as workersLogDir } from "./paths-BwfwHOvN.mjs";
|
|
5
|
+
import { _ as resolveTarget } from "./routing-CF0wlR-_.mjs";
|
|
7
6
|
import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
|
|
8
|
-
import {
|
|
9
|
-
import { execFileSync
|
|
10
|
-
import { fileURLToPath } from "node:url";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
import { execFileSync } from "node:child_process";
|
|
11
9
|
|
|
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
|
|
232
10
|
//#region src/workers/fallback.ts
|
|
233
11
|
/**
|
|
234
12
|
* fallback.ts — machine-wide Claude Code fallback to a worker provider.
|
|
@@ -493,5 +271,5 @@ function fallbackStatusText(s) {
|
|
|
493
271
|
}
|
|
494
272
|
|
|
495
273
|
//#endregion
|
|
496
|
-
export {
|
|
497
|
-
//# sourceMappingURL=fallback-
|
|
274
|
+
export { fallbackStatusText as i, fallbackOn as n, fallbackStatus as r, fallbackOff as t };
|
|
275
|
+
//# sourceMappingURL=fallback-CQ8_CuVu.mjs.map
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { t as ANTHROPIC_NATIVE } from "./config-
|
|
3
|
-
import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-
|
|
4
|
-
import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-
|
|
1
|
+
import { _ as paiHomePath } from "./runtime-paths-twfV23YL.mjs";
|
|
2
|
+
import { t as ANTHROPIC_NATIVE } from "./config-DGV64YJa.mjs";
|
|
3
|
+
import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-CF0wlR-_.mjs";
|
|
4
|
+
import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-C2FGhf54.mjs";
|
|
5
5
|
import { mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
|
|
6
6
|
import { Chalk } from "chalk";
|
|
7
7
|
|
|
@@ -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-Bb2U4PNK.mjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { i as getRegistryBackend } from "./factory-
|
|
1
|
+
import { i as getRegistryBackend } from "./factory-CYwa0jYj.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-Dj2nY56t.mjs.map
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import "./config-
|
|
1
|
+
import "./config-SlZ-Z52i.mjs";
|
|
2
2
|
import "./helpers-CRuBUas3.mjs";
|
|
3
|
-
import "./factory-
|
|
4
|
-
import "./postgres-
|
|
5
|
-
import "./embedding-gate-
|
|
3
|
+
import "./factory-CYwa0jYj.mjs";
|
|
4
|
+
import "./postgres-BL5oBBgY.mjs";
|
|
5
|
+
import "./embedding-gate-iq0oQEkF.mjs";
|
|
6
6
|
import "./embeddings-BVq3esBF.mjs";
|
|
7
|
-
import "./router-
|
|
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-
|
|
7
|
+
import "./router-D2476pOp.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-Dj2nY56t.mjs";
|
|
9
9
|
|
|
10
10
|
export { getProject };
|
|
@@ -8174,6 +8174,7 @@ function defaultWorkersConfig() {
|
|
|
8174
8174
|
cacheKeepaliveSecs: num(w.cacheKeepaliveSecs, 0),
|
|
8175
8175
|
defaultMaxMinutes: num(w.defaultMaxMinutes, 60),
|
|
8176
8176
|
waitAlarmMinutes: num(w.waitAlarmMinutes, 120),
|
|
8177
|
+
scanBudgetMs: num(w.scanBudgetMs, 5e3),
|
|
8177
8178
|
stagger: {
|
|
8178
8179
|
enabled: bool(stagger.enabled, true),
|
|
8179
8180
|
localDefaultSec: num(stagger.localDefaultSec, 20),
|
|
@@ -8768,6 +8769,13 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
|
|
|
8768
8769
|
}
|
|
8769
8770
|
waitAlarmMinutes = w.waitAlarmMinutes;
|
|
8770
8771
|
}
|
|
8772
|
+
let scanBudgetMs = d.scanBudgetMs ?? 5e3;
|
|
8773
|
+
if (w.scanBudgetMs !== void 0) {
|
|
8774
|
+
if (typeof w.scanBudgetMs !== "number" || !Number.isInteger(w.scanBudgetMs) || w.scanBudgetMs < 1) {
|
|
8775
|
+
bad(".scanBudgetMs", "must be a positive integer (milliseconds)");
|
|
8776
|
+
}
|
|
8777
|
+
scanBudgetMs = w.scanBudgetMs;
|
|
8778
|
+
}
|
|
8771
8779
|
const stagger = { ...d.stagger };
|
|
8772
8780
|
if (w.stagger !== void 0) {
|
|
8773
8781
|
if (typeof w.stagger !== "object" || w.stagger === null || Array.isArray(w.stagger)) {
|
|
@@ -8904,6 +8912,7 @@ function parseWorkersConfig(raw, yamlProviders = {}) {
|
|
|
8904
8912
|
cacheKeepaliveSecs,
|
|
8905
8913
|
defaultMaxMinutes,
|
|
8906
8914
|
waitAlarmMinutes,
|
|
8915
|
+
scanBudgetMs,
|
|
8907
8916
|
stagger,
|
|
8908
8917
|
capacity,
|
|
8909
8918
|
localIdle,
|
|
@@ -7724,6 +7724,104 @@ import { appendFileSync, chmodSync as chmodSync2, existsSync as existsSync4, mkd
|
|
|
7724
7724
|
// src/workers/ps-table.ts
|
|
7725
7725
|
var PS_MAX_BUFFER = 64 * 1024 * 1024;
|
|
7726
7726
|
|
|
7727
|
+
// src/utils/redact.ts
|
|
7728
|
+
var REDACTED = "[REDACTED]";
|
|
7729
|
+
var REDACTED_RE = String.raw`\[REDACTED\]`;
|
|
7730
|
+
var KEY_WORDS = "password|passwd|secret|token|api[_-]?key|credential|auth(?:orization)?|bearer";
|
|
7731
|
+
var PROSE = "is|are|was|were|be|to|of|in|on|for|and|or|the|a|an|that|this|it|not|out|here|there|so|as|at|by|with|if|when|which";
|
|
7732
|
+
var VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
|
|
7733
|
+
var REDACT_RULES = [
|
|
7734
|
+
{
|
|
7735
|
+
// `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
|
|
7736
|
+
id: "authorization",
|
|
7737
|
+
re: /(Authorization\s*:\s*)(Bearer|Basic)\s+([^\s'"]+)/gi,
|
|
7738
|
+
replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
|
|
7739
|
+
},
|
|
7740
|
+
{
|
|
7741
|
+
// `Cookie: a=b; c=d` — keep the cookie names, redact every value
|
|
7742
|
+
id: "cookie",
|
|
7743
|
+
re: /((?:Set-)?Cookie\s*:\s*)([^\n]+)/gi,
|
|
7744
|
+
replace: (_m, head, rest) => `${head}${rest.replace(/([^=;\s'"]+=)[^;'"]*/g, `$1${REDACTED}`)}`
|
|
7745
|
+
},
|
|
7746
|
+
{
|
|
7747
|
+
// `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
|
|
7748
|
+
// the word must be a whole key segment, so `monkeys=` stays untouched.
|
|
7749
|
+
// The separator may start with the key's closing quote (JSON); it is kept.
|
|
7750
|
+
id: "key-value",
|
|
7751
|
+
re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(["']?\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(?!(?:${PROSE})\b)(${VAL})`, "gi"),
|
|
7752
|
+
replace: (m, key, sep2, val) => {
|
|
7753
|
+
if (/[_-](?:count|length|len|size|limit|max|min|budget)$/i.test(key) && /^\d+$/.test(val)) return m;
|
|
7754
|
+
const q = sep2[0] === '"' || sep2[0] === "'" ? val[0] : "";
|
|
7755
|
+
return q && (q === '"' || q === "'") ? `${key}${sep2}${q}${REDACTED}${q}` : `${key}${sep2}${REDACTED}`;
|
|
7756
|
+
}
|
|
7757
|
+
},
|
|
7758
|
+
{
|
|
7759
|
+
// npmrc `//registry/:_authToken=xxx`
|
|
7760
|
+
id: "npm-auth-token",
|
|
7761
|
+
re: new RegExp(String.raw`(_authToken\s*=\s*)(${VAL})`, "g"),
|
|
7762
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
7763
|
+
},
|
|
7764
|
+
{
|
|
7765
|
+
// `curl -u user:pass` / `--user user:pass` — keep the user
|
|
7766
|
+
id: "curl-user",
|
|
7767
|
+
re: /(\bcurl\b[^\n]{0,500}?\s(?:-u|--user)[\s=]+['"]?[^\s:'"]+:)([^\s'"]+)/g,
|
|
7768
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
7769
|
+
},
|
|
7770
|
+
{
|
|
7771
|
+
// `mysql -phunter2` / `mysqldump -p'hunter2'` — attached password only
|
|
7772
|
+
id: "mysql-p",
|
|
7773
|
+
re: /(\bmysql(?:dump)?\b[^\n]{0,300}?\s-p)('[^']*'|"[^"]*"|[^\s'"-][^\s'"]*)/g,
|
|
7774
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
7775
|
+
},
|
|
7776
|
+
{
|
|
7777
|
+
// `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
|
|
7778
|
+
id: "env-style",
|
|
7779
|
+
re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:export\s+)?[A-Z][A-Z0-9]*_(?:KEY|SECRET|TOKEN|PASS\w*|CRED\w*|AUTH\w*)\s*=\s*)(${VAL})`, "g"),
|
|
7780
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
7781
|
+
},
|
|
7782
|
+
{
|
|
7783
|
+
// long CLI flags only: `--password X`, `--token X`, `--api-key X`, `--secret X`, `--passwd X`
|
|
7784
|
+
id: "cli-flag",
|
|
7785
|
+
re: new RegExp(String.raw`(--(?:password|token|api-key|secret|passwd)(?:\s*=\s*|\s+))(${VAL})`, "gi"),
|
|
7786
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
7787
|
+
},
|
|
7788
|
+
{
|
|
7789
|
+
// `scheme://user:pass@host` — redact the password, keep user and host
|
|
7790
|
+
id: "url-credentials",
|
|
7791
|
+
re: /((?<![a-z0-9+.-])[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:)([^\s/@]+)(@)/gi,
|
|
7792
|
+
replace: (_m, head, _pass, at) => `${head}${REDACTED}${at}`
|
|
7793
|
+
},
|
|
7794
|
+
{
|
|
7795
|
+
// provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
|
|
7796
|
+
// glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
|
|
7797
|
+
id: "token-prefix",
|
|
7798
|
+
re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}|[sr]k_(?:live|test)_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{36}|hf_[A-Za-z0-9]{30,}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
|
|
7799
|
+
replace: REDACTED
|
|
7800
|
+
},
|
|
7801
|
+
{
|
|
7802
|
+
// 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
|
|
7803
|
+
id: "long-run",
|
|
7804
|
+
re: /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40,4096}={0,2}(?![\w/])/g,
|
|
7805
|
+
// a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
|
|
7806
|
+
replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
|
|
7807
|
+
}
|
|
7808
|
+
];
|
|
7809
|
+
var PEM_BLOCK = /-----BEGIN[^-\n]*PRIVATE KEY-----[\s\S]*?(?:-----END[^-\n]*PRIVATE KEY-----|$)/g;
|
|
7810
|
+
var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
|
|
7811
|
+
var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
|
|
7812
|
+
var LONG_RUN_MAX_LINE = 64 * 1024;
|
|
7813
|
+
var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
|
|
7814
|
+
function redactLine(line) {
|
|
7815
|
+
let out = line;
|
|
7816
|
+
for (const r of LINE_RULES) out = out.replace(r.re, r.replace);
|
|
7817
|
+
if (out.length <= LONG_RUN_MAX_LINE && KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
|
|
7818
|
+
return out;
|
|
7819
|
+
}
|
|
7820
|
+
function redactSecrets(text) {
|
|
7821
|
+
const withPem = text.replace(PEM_BLOCK, `-----BEGIN PRIVATE KEY----- ${REDACTED}`);
|
|
7822
|
+
return withPem.split("\n").map(redactLine).join("\n");
|
|
7823
|
+
}
|
|
7824
|
+
|
|
7727
7825
|
// src/hooks/ts/lib/loop-guard.ts
|
|
7728
7826
|
var LOOP_MAX_REPEATS = 4;
|
|
7729
7827
|
var LOOP_READ_STREAK = Number(process.env.PAI_LOOP_READ_STREAK) > 0 ? Number(process.env.PAI_LOOP_READ_STREAK) : 15;
|
|
@@ -7732,10 +7830,8 @@ var LOOP_DENY_REASON = `loop guard: you ran this command ${LOOP_MAX_REPEATS} tim
|
|
|
7732
7830
|
var WAIT_CAP_MS = 45 * 6e4;
|
|
7733
7831
|
var FP_FULL_READ_BYTES = 256 * 1024;
|
|
7734
7832
|
var FP_TOTAL_BYTES = 4 * 1024 * 1024;
|
|
7735
|
-
var SECRET_LINE = /pass(?:word|wd)|secret|token|api[_-]?key|credential|authorization|bearer|private key|^\s*(?:export\s+)?[A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASS\w*|CRED\w*|AUTH\w*)\s*=|\b(?:sk|ghp|gho|xox[bap])[-_][A-Za-z0-9_-]{16,}|\b[A-Za-z0-9+]{40,}={0,2}(?![\w/])|\b[a-z][a-z0-9+.-]*:\/\/[^\s\/:@]+:[^\s\/@]+@|\b(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}\b|\bgh[pousr]_[A-Za-z0-9]{20,}/i;
|
|
7736
|
-
var MASKED_LINE = "[line masked: looks like a secret]";
|
|
7737
7833
|
function maskSecrets(text) {
|
|
7738
|
-
return text
|
|
7834
|
+
return redactSecrets(text);
|
|
7739
7835
|
}
|
|
7740
7836
|
|
|
7741
7837
|
// src/utils/hash.ts
|
|
@@ -141,6 +141,104 @@ import { appendFileSync, chmodSync, existsSync as existsSync3, mkdirSync as mkdi
|
|
|
141
141
|
// src/workers/ps-table.ts
|
|
142
142
|
var PS_MAX_BUFFER = 64 * 1024 * 1024;
|
|
143
143
|
|
|
144
|
+
// src/utils/redact.ts
|
|
145
|
+
var REDACTED = "[REDACTED]";
|
|
146
|
+
var REDACTED_RE = String.raw`\[REDACTED\]`;
|
|
147
|
+
var KEY_WORDS = "password|passwd|secret|token|api[_-]?key|credential|auth(?:orization)?|bearer";
|
|
148
|
+
var PROSE = "is|are|was|were|be|to|of|in|on|for|and|or|the|a|an|that|this|it|not|out|here|there|so|as|at|by|with|if|when|which";
|
|
149
|
+
var VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
|
|
150
|
+
var REDACT_RULES = [
|
|
151
|
+
{
|
|
152
|
+
// `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
|
|
153
|
+
id: "authorization",
|
|
154
|
+
re: /(Authorization\s*:\s*)(Bearer|Basic)\s+([^\s'"]+)/gi,
|
|
155
|
+
replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
|
|
156
|
+
},
|
|
157
|
+
{
|
|
158
|
+
// `Cookie: a=b; c=d` — keep the cookie names, redact every value
|
|
159
|
+
id: "cookie",
|
|
160
|
+
re: /((?:Set-)?Cookie\s*:\s*)([^\n]+)/gi,
|
|
161
|
+
replace: (_m, head, rest) => `${head}${rest.replace(/([^=;\s'"]+=)[^;'"]*/g, `$1${REDACTED}`)}`
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
// `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
|
|
165
|
+
// the word must be a whole key segment, so `monkeys=` stays untouched.
|
|
166
|
+
// The separator may start with the key's closing quote (JSON); it is kept.
|
|
167
|
+
id: "key-value",
|
|
168
|
+
re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:[A-Za-z0-9]+[_-])?(?:${KEY_WORDS})(?![A-Za-z0-9])[A-Za-z0-9_-]*)(["']?\s*[:=]\s*)(?!(?:Bearer|Basic) ${REDACTED_RE})(?!(?:${PROSE})\b)(${VAL})`, "gi"),
|
|
169
|
+
replace: (m, key, sep, val) => {
|
|
170
|
+
if (/[_-](?:count|length|len|size|limit|max|min|budget)$/i.test(key) && /^\d+$/.test(val)) return m;
|
|
171
|
+
const q = sep[0] === '"' || sep[0] === "'" ? val[0] : "";
|
|
172
|
+
return q && (q === '"' || q === "'") ? `${key}${sep}${q}${REDACTED}${q}` : `${key}${sep}${REDACTED}`;
|
|
173
|
+
}
|
|
174
|
+
},
|
|
175
|
+
{
|
|
176
|
+
// npmrc `//registry/:_authToken=xxx`
|
|
177
|
+
id: "npm-auth-token",
|
|
178
|
+
re: new RegExp(String.raw`(_authToken\s*=\s*)(${VAL})`, "g"),
|
|
179
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
180
|
+
},
|
|
181
|
+
{
|
|
182
|
+
// `curl -u user:pass` / `--user user:pass` — keep the user
|
|
183
|
+
id: "curl-user",
|
|
184
|
+
re: /(\bcurl\b[^\n]{0,500}?\s(?:-u|--user)[\s=]+['"]?[^\s:'"]+:)([^\s'"]+)/g,
|
|
185
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
// `mysql -phunter2` / `mysqldump -p'hunter2'` — attached password only
|
|
189
|
+
id: "mysql-p",
|
|
190
|
+
re: /(\bmysql(?:dump)?\b[^\n]{0,300}?\s-p)('[^']*'|"[^"]*"|[^\s'"-][^\s'"]*)/g,
|
|
191
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
// `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
|
|
195
|
+
id: "env-style",
|
|
196
|
+
re: new RegExp(String.raw`(?<![A-Za-z0-9])((?:export\s+)?[A-Z][A-Z0-9]*_(?:KEY|SECRET|TOKEN|PASS\w*|CRED\w*|AUTH\w*)\s*=\s*)(${VAL})`, "g"),
|
|
197
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
// long CLI flags only: `--password X`, `--token X`, `--api-key X`, `--secret X`, `--passwd X`
|
|
201
|
+
id: "cli-flag",
|
|
202
|
+
re: new RegExp(String.raw`(--(?:password|token|api-key|secret|passwd)(?:\s*=\s*|\s+))(${VAL})`, "gi"),
|
|
203
|
+
replace: (_m, head) => `${head}${REDACTED}`
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
// `scheme://user:pass@host` — redact the password, keep user and host
|
|
207
|
+
id: "url-credentials",
|
|
208
|
+
re: /((?<![a-z0-9+.-])[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:)([^\s/@]+)(@)/gi,
|
|
209
|
+
replace: (_m, head, _pass, at) => `${head}${REDACTED}${at}`
|
|
210
|
+
},
|
|
211
|
+
{
|
|
212
|
+
// provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
|
|
213
|
+
// glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
|
|
214
|
+
id: "token-prefix",
|
|
215
|
+
re: /\b(?:sk-ant-[A-Za-z0-9_-]{20,}|sk-[A-Za-z0-9_-]{20,}|gh[pousr]_[A-Za-z0-9]{30,}|github_pat_[A-Za-z0-9_]{22,}|glpat-[A-Za-z0-9_-]{20,}|xox[bap]-[A-Za-z0-9-]{10,}|(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}|[sr]k_(?:live|test)_[A-Za-z0-9]{20,}|npm_[A-Za-z0-9]{36}|hf_[A-Za-z0-9]{30,}|AIza[A-Za-z0-9_-]{35}(?![A-Za-z0-9_-])|eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+)(?![A-Za-z0-9_-])/g,
|
|
216
|
+
replace: REDACTED
|
|
217
|
+
},
|
|
218
|
+
{
|
|
219
|
+
// 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
|
|
220
|
+
id: "long-run",
|
|
221
|
+
re: /(?<![A-Za-z0-9+/])[A-Za-z0-9+/]{40,4096}={0,2}(?![\w/])/g,
|
|
222
|
+
// a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
|
|
223
|
+
replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
|
|
224
|
+
}
|
|
225
|
+
];
|
|
226
|
+
var PEM_BLOCK = /-----BEGIN[^-\n]*PRIVATE KEY-----[\s\S]*?(?:-----END[^-\n]*PRIVATE KEY-----|$)/g;
|
|
227
|
+
var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
|
|
228
|
+
var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
|
|
229
|
+
var LONG_RUN_MAX_LINE = 64 * 1024;
|
|
230
|
+
var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
|
|
231
|
+
function redactLine(line) {
|
|
232
|
+
let out = line;
|
|
233
|
+
for (const r of LINE_RULES) out = out.replace(r.re, r.replace);
|
|
234
|
+
if (out.length <= LONG_RUN_MAX_LINE && KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
|
|
235
|
+
return out;
|
|
236
|
+
}
|
|
237
|
+
function redactSecrets(text) {
|
|
238
|
+
const withPem = text.replace(PEM_BLOCK, `-----BEGIN PRIVATE KEY----- ${REDACTED}`);
|
|
239
|
+
return withPem.split("\n").map(redactLine).join("\n");
|
|
240
|
+
}
|
|
241
|
+
|
|
144
242
|
// src/hooks/ts/lib/loop-guard.ts
|
|
145
243
|
var LOOP_MAX_REPEATS = 4;
|
|
146
244
|
var LOOP_READ_STREAK = Number(process.env.PAI_LOOP_READ_STREAK) > 0 ? Number(process.env.PAI_LOOP_READ_STREAK) : 15;
|
|
@@ -149,10 +247,8 @@ var LOOP_DENY_REASON = `loop guard: you ran this command ${LOOP_MAX_REPEATS} tim
|
|
|
149
247
|
var WAIT_CAP_MS = 45 * 6e4;
|
|
150
248
|
var FP_FULL_READ_BYTES = 256 * 1024;
|
|
151
249
|
var FP_TOTAL_BYTES = 4 * 1024 * 1024;
|
|
152
|
-
var SECRET_LINE = /pass(?:word|wd)|secret|token|api[_-]?key|credential|authorization|bearer|private key|^\s*(?:export\s+)?[A-Z][A-Z0-9_]*(?:KEY|SECRET|TOKEN|PASS\w*|CRED\w*|AUTH\w*)\s*=|\b(?:sk|ghp|gho|xox[bap])[-_][A-Za-z0-9_-]{16,}|\b[A-Za-z0-9+]{40,}={0,2}(?![\w/])|\b[a-z][a-z0-9+.-]*:\/\/[^\s\/:@]+:[^\s\/@]+@|\b(?:AKIA|ASIA|AGPA|AIDA|AROA)[A-Z0-9]{16}\b|\bgh[pousr]_[A-Za-z0-9]{20,}/i;
|
|
153
|
-
var MASKED_LINE = "[line masked: looks like a secret]";
|
|
154
250
|
function maskSecrets(text) {
|
|
155
|
-
return text
|
|
251
|
+
return redactSecrets(text);
|
|
156
252
|
}
|
|
157
253
|
|
|
158
254
|
// src/utils/hash.ts
|