@tekmidian/pai 1.0.4 → 1.0.6

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.
Files changed (248) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/{aibroker-client-CQPGqLxL.mjs → aibroker-client-CXsyC7A8.mjs} +2 -2
  3. package/dist/aibroker-client-ChB7gSxV.mjs +3 -0
  4. package/dist/auto-route-Bc8xP6TQ.mjs +11 -0
  5. package/dist/{auto-route-21GdHL70.mjs → auto-route-YaEGVrFl.mjs} +2 -2
  6. package/dist/budget-DEiebT2A.mjs +15 -0
  7. package/dist/{caller-identity-yLFb7CKq.mjs → caller-identity-C6Nc96iM.mjs} +4 -4
  8. package/dist/{capacity-DEveQdFV.mjs → capacity-B2PgKAg4.mjs} +69 -6
  9. package/dist/{chain-D7PFur8Y.mjs → chain-CtK49-Ma.mjs} +5 -5
  10. package/dist/cli/index.mjs +2126 -290
  11. package/dist/{cockpit-actions-BfRMr2sm.mjs → cockpit-actions-C73mJAJ8.mjs} +18 -18
  12. package/dist/{cockpit-actions-OodH_vx_.mjs → cockpit-actions-D1OPP6Es.mjs} +30 -26
  13. package/dist/cockpit-memory-CLHZD64W.mjs +20 -0
  14. package/dist/config/defaults/config.yaml +21 -1
  15. package/dist/{config-XpZWOYOG.mjs → config-Bz8pAU5Q.mjs} +30 -5
  16. package/dist/{config-DtENJ6cL.mjs → config-DHgPx3ER.mjs} +1 -1
  17. package/dist/config-DLmyEK2q.mjs +4 -0
  18. package/dist/{config-Bu1_vbY8.mjs → config-SlZ-Z52i.mjs} +4 -3
  19. package/dist/{controls-JLm6g0yP.mjs → controls-rIItFeIJ.mjs} +59 -66
  20. package/dist/daemon/index.mjs +40 -39
  21. package/dist/daemon-176qA79N.mjs +46 -0
  22. package/dist/{daemon-nXanenDM.mjs → daemon-SoUvPUOf.mjs} +80 -30
  23. package/dist/daemon-mcp/index.mjs +49 -38
  24. package/dist/detect-C8nFP-kR.mjs +10 -0
  25. package/dist/{detect-BLKsUOgG.mjs → detect-DLjeYwnt.mjs} +2 -2
  26. package/dist/{embed-pass-e64AwDCa.mjs → embed-pass-CN1D8MXl.mjs} +5 -5
  27. package/dist/{embedding-gate-Cnk4YCyX.mjs → embedding-gate-BVQvUmox.mjs} +2 -2
  28. package/dist/{embedding-gate-6rZrWRXa.mjs → embedding-gate-iq0oQEkF.mjs} +3 -3
  29. package/dist/{endreason-BC-v05H_.mjs → endreason-C2-hYK0_.mjs} +4 -4
  30. package/dist/{factory-B7nv75rC.mjs → factory-CYwa0jYj.mjs} +6 -6
  31. package/dist/factory-DFwez99M.mjs +9 -0
  32. package/dist/{fallback-CBWpp2F2.mjs → fallback-CwPSCrX8.mjs} +9 -231
  33. package/dist/{health-C4FQmkJn.mjs → health-D0mUAVdw.mjs} +5 -5
  34. package/dist/{helpers-DSNK_1KP.mjs → helpers-Dj2nY56t.mjs} +2 -2
  35. package/dist/{helpers-Dz7mjTSw.mjs → helpers-DyHKAwrW.mjs} +6 -6
  36. package/dist/hooks/block-sleep-poll.mjs +1 -1
  37. package/dist/hooks/capture-all-events.mjs +68 -3
  38. package/dist/hooks/capture-tool-output.mjs +68 -3
  39. package/dist/hooks/handoff-link.mjs +128 -0
  40. package/dist/hooks/load-project-context.mjs +8 -8
  41. package/dist/hooks/local-model-hint.mjs +1 -1
  42. package/dist/hooks/route-agents-to-worker.mjs +1 -1
  43. package/dist/hooks/security-validator.mjs +842 -90
  44. package/dist/hooks/supervision-banner.mjs +186 -48
  45. package/dist/hooks/worker-edit-repair.mjs +2 -2
  46. package/dist/hooks/worker-guard.mjs +65 -9
  47. package/dist/hooks/worker-note.mjs +70 -5
  48. package/dist/hooks/worker-pool-host.mjs +1518 -265
  49. package/dist/hooks/worker-proxy.mjs +1 -1
  50. package/dist/hooks/worker-status-line.mjs +225 -86
  51. package/dist/hooks/worker-supervision.mjs +1 -1
  52. package/dist/hooks/worker-tool-name-repair.mjs +2 -2
  53. package/dist/index.mjs +9 -9
  54. package/dist/{ipc-client-CnYEF31R.mjs → ipc-client-CmagIFLh.mjs} +2 -2
  55. package/dist/{ipc-client-DN7EvoVo.mjs → ipc-client-DmbSIBUK.mjs} +1 -1
  56. package/dist/{kill-tree-DleMNZX3.mjs → kill-tree-DPiMscaY.mjs} +8 -8
  57. package/dist/kill-tree-Dxei6qlR.mjs +10 -0
  58. package/dist/{launch-DlZTKE3u.mjs → launch-BZT3JDoZ.mjs} +3 -3
  59. package/dist/{launch-Di7N-J5X.mjs → launch-Bn2Zf90h.mjs} +3 -3
  60. package/dist/{indexer-backend-BdjeL4P8.mjs → lessons-CFVU0cwA.mjs} +262 -43
  61. package/dist/{local-candidate-DLdwQt0s.mjs → local-candidate-DFd4pp-w.mjs} +3 -3
  62. package/dist/{local-instances-DOxSgT_L.mjs → local-instances-DhF4_sV2.mjs} +2 -2
  63. package/dist/{local-instances-ZeRkkuS5.mjs → local-instances-KTh8IeOT.mjs} +4 -4
  64. package/dist/{local-tiers-BE4jGaMa.mjs → local-tiers-CqwGUcEn.mjs} +3 -3
  65. package/dist/{local-tiers-DNMI5W86.mjs → local-tiers-DSlIYvvm.mjs} +3 -3
  66. package/dist/{main-config-ops-kTXR8Pyv.mjs → main-config-ops-rda08BCD.mjs} +3 -3
  67. package/dist/{main-resolver-yp_puSSb.mjs → main-resolver-BKwI0I6H.mjs} +18 -18
  68. package/dist/{migrate-DrA_OwlZ.mjs → migrate-C2z1YmWC.mjs} +2 -2
  69. package/dist/{model-inventory-h6Z9fN_o.mjs → model-inventory-BXv15B0d.mjs} +13 -13
  70. package/dist/{models-add-TVni3A7V.mjs → models-add-5yXTyz3g.mjs} +38 -37
  71. package/dist/operator-Bmv5tiHQ.mjs +7 -0
  72. package/dist/{operator-CyuB3aVw.mjs → operator-Br6GeswF.mjs} +2 -2
  73. package/dist/{pai-marker-BcZyJguM.mjs → pai-marker-D6OoVbM_.mjs} +2 -2
  74. package/dist/{pane-audit-Lqy9N_Ki.mjs → pane-audit-DLYy9-4g.mjs} +13 -23
  75. package/dist/{paths-CHifubDh.mjs → paths-CypxFTfn.mjs} +4 -4
  76. package/dist/{paths-CFHTloSe.mjs → paths-DIOwNcj-.mjs} +3 -3
  77. package/dist/{planner-j77ndkBf.mjs → planner-BzZ_2lc-.mjs} +29 -29
  78. package/dist/{pool-Dh-q3iJi.mjs → pool-9EsbKD-U.mjs} +2 -2
  79. package/dist/{pool-cli-DQ6OzRy2.mjs → pool-cli-Cy5mlycP.mjs} +6 -6
  80. package/dist/{pool-cli-BggU8GRp.mjs → pool-cli-Db0uDwB9.mjs} +5 -5
  81. package/dist/{postgres-BK4FP9Zg.mjs → postgres-B1B80bcj.mjs} +3 -3
  82. package/dist/{postgres-DNIOQijl.mjs → postgres-BL5oBBgY.mjs} +3 -3
  83. package/dist/{project-setup-CBRtFFh0.mjs → project-setup-DHxdJjEc.mjs} +24 -25
  84. package/dist/providers-BH6hQYbU.mjs +16 -0
  85. package/dist/{providers-C9QC0TtO.mjs → providers-BNV7CzC-.mjs} +6 -6
  86. package/dist/{query-feedback-DN52N9C5.mjs → query-feedback-BWl2HRwN.mjs} +2 -2
  87. package/dist/registrable-BwFiqazy.mjs +9 -0
  88. package/dist/{registrable-DpyTtajg.mjs → registrable-Dxs4oKIj.mjs} +4 -4
  89. package/dist/render-DVGXpfaT.mjs +13 -0
  90. package/dist/render-jPpMrudf.mjs +2240 -0
  91. package/dist/root-C8cxhdn9.mjs +36 -0
  92. package/dist/{root-C4oXlXS_.mjs → root-DmOzMeSv.mjs} +10 -10
  93. package/dist/route-table-COAmc1nB.mjs +15 -0
  94. package/dist/{router-CQSc3lk3.mjs → router-D2476pOp.mjs} +2 -2
  95. package/dist/{router-DwHJRgG9.mjs → router-ghujlEFb.mjs} +1 -1
  96. package/dist/{routing-f2zulGwD.mjs → routing-B_cg1_Xx.mjs} +13 -13
  97. package/dist/{routing-DmkheCRH.mjs → routing-aJKMIagQ.mjs} +16 -16
  98. package/dist/{run-BwZKBJZZ.mjs → run-DE9Q0ldN.mjs} +55 -31
  99. package/dist/{runtime-paths-WsO9sJFc.mjs → runtime-paths-twfV23YL.mjs} +2 -2
  100. package/dist/{scan-BBGvU5EB.mjs → scan-CNMcltOX.mjs} +7 -7
  101. package/dist/{scope-D-h6F6DN.mjs → scope-BTWstJ1B.mjs} +4 -4
  102. package/dist/session-DgZifjLx.mjs +35 -0
  103. package/dist/{session-Dn5OJXlg.mjs → session-HBYOABWU.mjs} +28 -28
  104. package/dist/session-scan-BZxnYN1v.mjs +9 -0
  105. package/dist/{session-scan-DUn10MBd.mjs → session-scan-CX3MKCNg.mjs} +6 -6
  106. package/dist/{session-usage-CPvXvSkw.mjs → session-usage-CCmPFFa6.mjs} +117 -2
  107. package/dist/{status-ggJ7lgVg.mjs → status-Cecau8Ps.mjs} +9 -5
  108. package/dist/status-D52xC_i0.mjs +6 -0
  109. package/dist/{tool-errors-7E13StWd.mjs → tool-errors-BFw1gv-z.mjs} +2 -2
  110. package/dist/{tool-errors-CJWODvlo.mjs → tool-errors-COM2JGEr.mjs} +6 -6
  111. package/dist/viewer-Ce-Xa9L3.mjs +22 -0
  112. package/dist/{viewer-wfKnvnrI.mjs → viewer-DvBg6N22.mjs} +16 -14
  113. package/dist/{wait-ByV0OyMZ.mjs → wait-C5iWILj_.mjs} +3 -3
  114. package/dist/worker-config-BmcJ9R0U.mjs +42 -0
  115. package/dist/{worker-config-eY5Qy4vl.mjs → worker-config-DkONNk_H.mjs} +164 -107
  116. package/dist/workers-config-DwzrtdYu.mjs +4 -0
  117. package/dist/{worktree-CRs2gyg0.mjs → worktree-O_kU6Q3y.mjs} +164 -8
  118. package/dist/{zettelkasten-tpCRBYvH.mjs → zettelkasten-BH8AdNh8.mjs} +4 -4
  119. package/dist/{zettelkasten-_h_tUm2T.mjs → zettelkasten-FFhQFESJ.mjs} +2 -2
  120. package/docs/commands/README.md +33 -2
  121. package/docs/commands/audit.md +34 -3
  122. package/docs/commands/backup.md +1 -1
  123. package/docs/commands/build.md +4 -4
  124. package/docs/commands/cd.md +1 -1
  125. package/docs/commands/clear-names.md +1 -1
  126. package/docs/commands/cockpit.md +1 -1
  127. package/docs/commands/config.md +21 -1
  128. package/docs/commands/daemon.md +1 -1
  129. package/docs/commands/db.md +1 -1
  130. package/docs/commands/doc.md +1 -1
  131. package/docs/commands/end.md +1 -1
  132. package/docs/commands/find.md +1 -1
  133. package/docs/commands/git.md +110 -0
  134. package/docs/commands/handoff.md +70 -0
  135. package/docs/commands/harness.md +74 -0
  136. package/docs/commands/help.md +1 -1
  137. package/docs/commands/home.md +1 -1
  138. package/docs/commands/hooks-db.md +1 -1
  139. package/docs/commands/identity.md +1 -1
  140. package/docs/commands/install.md +1 -1
  141. package/docs/commands/issue.md +1 -1
  142. package/docs/commands/kg.md +1 -1
  143. package/docs/commands/launch.md +1 -1
  144. package/docs/commands/lessons.md +201 -0
  145. package/docs/commands/list.md +1 -1
  146. package/docs/commands/ls.md +1 -1
  147. package/docs/commands/mcp.md +1 -1
  148. package/docs/commands/memory.md +1 -1
  149. package/docs/commands/models.md +1 -1
  150. package/docs/commands/more.md +1 -1
  151. package/docs/commands/new.md +1 -1
  152. package/docs/commands/notes.md +1 -1
  153. package/docs/commands/notify.md +1 -1
  154. package/docs/commands/observation.md +1 -1
  155. package/docs/commands/obsidian.md +1 -1
  156. package/docs/commands/open.md +1 -1
  157. package/docs/commands/pane.md +1 -1
  158. package/docs/commands/pause.md +1 -1
  159. package/docs/commands/plan.md +1 -1
  160. package/docs/commands/project.md +1 -1
  161. package/docs/commands/projects.md +1 -1
  162. package/docs/commands/providers.md +1 -1
  163. package/docs/commands/queue.md +1 -1
  164. package/docs/commands/registry.md +1 -1
  165. package/docs/commands/reload.md +1 -1
  166. package/docs/commands/rename.md +1 -1
  167. package/docs/commands/restore.md +1 -1
  168. package/docs/commands/resume.md +1 -1
  169. package/docs/commands/router.md +1 -1
  170. package/docs/commands/rules.md +70 -0
  171. package/docs/commands/session.md +1 -1
  172. package/docs/commands/sessions.md +1 -1
  173. package/docs/commands/setup.md +1 -1
  174. package/docs/commands/setups.md +1 -1
  175. package/docs/commands/shell-init.md +1 -1
  176. package/docs/commands/skill.md +1 -1
  177. package/docs/commands/task.md +1 -1
  178. package/docs/commands/tasks.md +1 -1
  179. package/docs/commands/topic.md +1 -1
  180. package/docs/commands/update.md +1 -1
  181. package/docs/commands/worker.md +1 -1
  182. package/docs/commands/zettel.md +1 -1
  183. package/docs/concepts/panes.md +3 -2
  184. package/gemini-extension.json +1 -1
  185. package/package.json +2 -2
  186. package/pai-plugin.json +1 -1
  187. package/plugins/context-preservation/plugin.json +1 -1
  188. package/plugins/core/plugin.json +1 -1
  189. package/plugins/creative/plugin.json +1 -1
  190. package/plugins/observability/plugin.json +1 -1
  191. package/plugins/productivity/plugin.json +1 -1
  192. package/plugins/semantic-search/plugin.json +1 -1
  193. package/plugins/ui/plugin.json +1 -1
  194. package/plugins/zettelkasten/plugin.json +1 -1
  195. package/src/hooks/ts/lib/loop-guard.ts +3 -5
  196. package/src/hooks/ts/lib/rules/builtin/base64-decode-to-shell.rule.yaml +13 -0
  197. package/src/hooks/ts/lib/rules/builtin/chmod-world-writable.rule.yaml +13 -0
  198. package/src/hooks/ts/lib/rules/builtin/chmod-zero.rule.yaml +11 -0
  199. package/src/hooks/ts/lib/rules/builtin/credential-file-read.rule.yaml +13 -0
  200. package/src/hooks/ts/lib/rules/builtin/credential-read-then-network.rule.yaml +29 -0
  201. package/src/hooks/ts/lib/rules/builtin/crontab-persistence.rule.yaml +10 -0
  202. package/src/hooks/ts/lib/rules/builtin/curl-piped-to-shell.rule.yaml +15 -0
  203. package/src/hooks/ts/lib/rules/builtin/download-then-execute.rule.yaml +30 -0
  204. package/src/hooks/ts/lib/rules/builtin/find-root-delete.rule.yaml +11 -0
  205. package/src/hooks/ts/lib/rules/builtin/git-push-force.rule.yaml +24 -0
  206. package/src/hooks/ts/lib/rules/builtin/git-push-plus-refspec.rule.yaml +12 -0
  207. package/src/hooks/ts/lib/rules/builtin/git-reset-hard.rule.yaml +12 -0
  208. package/src/hooks/ts/lib/rules/builtin/injection-then-tool.rule.yaml +30 -0
  209. package/src/hooks/ts/lib/rules/builtin/instruction-override-disregard.rule.yaml +12 -0
  210. package/src/hooks/ts/lib/rules/builtin/instruction-override-ignore.rule.yaml +13 -0
  211. package/src/hooks/ts/lib/rules/builtin/launchagents-write-persistence.rule.yaml +12 -0
  212. package/src/hooks/ts/lib/rules/builtin/launchctl-load-persistence.rule.yaml +10 -0
  213. package/src/hooks/ts/lib/rules/builtin/reverse-shell-dev-tcp.rule.yaml +11 -0
  214. package/src/hooks/ts/lib/rules/builtin/reverse-shell-interactive-bash.rule.yaml +11 -0
  215. package/src/hooks/ts/lib/rules/builtin/rm-recursive-parent.rule.yaml +11 -0
  216. package/src/hooks/ts/lib/rules/builtin/rm-recursive-relative.rule.yaml +11 -0
  217. package/src/hooks/ts/lib/rules/builtin/rm-recursive-root.rule.yaml +24 -0
  218. package/src/hooks/ts/lib/rules/builtin/rm-trailing-tilde.rule.yaml +11 -0
  219. package/src/hooks/ts/lib/rules/builtin/sudoers-nopasswd.rule.yaml +15 -0
  220. package/src/hooks/ts/lib/rules/builtin.generated.ts +530 -0
  221. package/src/hooks/ts/lib/rules/eval.ts +74 -0
  222. package/src/hooks/ts/lib/rules/lint.ts +102 -0
  223. package/src/hooks/ts/lib/rules/load.ts +229 -0
  224. package/src/hooks/ts/lib/rules/types.ts +56 -0
  225. package/src/hooks/ts/pre-tool-use/security-validator.ts +27 -96
  226. package/src/hooks/ts/user-prompt/handoff-link.ts +34 -0
  227. package/dist/aibroker-client-BxzeEHPF.mjs +0 -3
  228. package/dist/auto-route-C3S2W3Bc.mjs +0 -11
  229. package/dist/budget-BrloTOZW.mjs +0 -15
  230. package/dist/cockpit-memory-teG9M8bG.mjs +0 -20
  231. package/dist/config-Cxi-aBf4.mjs +0 -4
  232. package/dist/daemon-DeYImF1F.mjs +0 -45
  233. package/dist/detect-Rrimh0xc.mjs +0 -10
  234. package/dist/factory-Bs9imVMq.mjs +0 -9
  235. package/dist/kill-tree-SV6hrIa3.mjs +0 -10
  236. package/dist/operator-BTqvTIc8.mjs +0 -7
  237. package/dist/providers-FvCLzFge.mjs +0 -16
  238. package/dist/registrable-BzH4TObg.mjs +0 -9
  239. package/dist/render-B35bQTE-.mjs +0 -13
  240. package/dist/render-C84BqQRC.mjs +0 -903
  241. package/dist/root-DD1xx_Vu.mjs +0 -36
  242. package/dist/route-table-FEfDuhIV.mjs +0 -15
  243. package/dist/session-BAhtXdxj.mjs +0 -35
  244. package/dist/session-scan-B57dNuA4.mjs +0 -9
  245. package/dist/status-Dm4dYciN.mjs +0 -6
  246. package/dist/viewer-DEySE4c_.mjs +0 -22
  247. package/dist/worker-config-CO5FXLAT.mjs +0 -41
  248. package/dist/workers-config-f8KrkY4L.mjs +0 -4
@@ -1,234 +1,12 @@
1
- import { l as claudeHomeDir, t as aibrokerHomeDir } from "./runtime-paths-WsO9sJFc.mjs";
2
- import { F as writeWorkersSection, N as resolveModelCapability, P as resolveProviderKey, c as WorkersConfigError, j as readWorkersSection } from "./config-XpZWOYOG.mjs";
3
- import { D as readJsonStrict, O as writeJsonAtomic } from "./config-Bu1_vbY8.mjs";
4
- import { u as workersLogDir } from "./paths-CHifubDh.mjs";
5
- import { _ as resolveTarget } from "./routing-DmkheCRH.mjs";
6
- import { yt as psTable } from "./controls-JLm6g0yP.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-Bz8pAU5Q.mjs";
3
+ import { O as readJsonStrict, k as writeJsonAtomic } from "./config-SlZ-Z52i.mjs";
4
+ import { u as workersLogDir } from "./paths-CypxFTfn.mjs";
5
+ import { _ as resolveTarget } from "./routing-aJKMIagQ.mjs";
7
6
  import { existsSync, mkdirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
8
- import { isAbsolute, join, relative } from "node:path";
9
- import { execFileSync, spawn } from "node:child_process";
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 { 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
274
+ export { fallbackStatusText as i, fallbackOn as n, fallbackStatus as r, fallbackOff as t };
275
+ //# sourceMappingURL=fallback-CwPSCrX8.mjs.map
@@ -1,7 +1,7 @@
1
- import { g as paiHomePath } from "./runtime-paths-WsO9sJFc.mjs";
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-DmkheCRH.mjs";
4
- import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-DLdwQt0s.mjs";
1
+ import { _ as paiHomePath } from "./runtime-paths-twfV23YL.mjs";
2
+ import { t as ANTHROPIC_NATIVE } from "./config-Bz8pAU5Q.mjs";
3
+ import { A as budgetSkipReason, D as budgetExceeded, E as budgetCache, M as budgetWall } from "./routing-aJKMIagQ.mjs";
4
+ import { n as tierProviderNames, t as isLocalCandidate } from "./local-candidate-DFd4pp-w.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-C4FQmkJn.mjs.map
314
+ //# sourceMappingURL=health-D0mUAVdw.mjs.map
@@ -1,4 +1,4 @@
1
- import { i as getRegistryBackend } from "./factory-B7nv75rC.mjs";
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-DSNK_1KP.mjs.map
69
+ //# sourceMappingURL=helpers-Dj2nY56t.mjs.map
@@ -1,10 +1,10 @@
1
- import "./config-Bu1_vbY8.mjs";
1
+ import "./config-SlZ-Z52i.mjs";
2
2
  import "./helpers-CRuBUas3.mjs";
3
- import "./factory-B7nv75rC.mjs";
4
- import "./postgres-DNIOQijl.mjs";
5
- import "./embedding-gate-6rZrWRXa.mjs";
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-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-DSNK_1KP.mjs";
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 };
@@ -7406,7 +7406,7 @@ function parseEscalate(v, bad2) {
7406
7406
  }
7407
7407
 
7408
7408
  // src/workers/config.ts
7409
- import { existsSync as existsSync6, readFileSync as readFileSync6 } from "node:fs";
7409
+ import { existsSync as existsSync6, readFileSync as readFileSync6, statSync as statSync2 } from "node:fs";
7410
7410
 
7411
7411
  // src/daemon/config.ts
7412
7412
  import { homedir as homedir2, userInfo } from "node:os";
@@ -7724,6 +7724,73 @@ 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 VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
7732
+ var REDACT_RULES = [
7733
+ {
7734
+ // `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
7735
+ id: "authorization",
7736
+ re: /(Authorization\s*:\s*)(Bearer|Basic)\s+(\S+)/gi,
7737
+ replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
7738
+ },
7739
+ {
7740
+ // `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
7741
+ // the word must be a whole key segment, so `monkeys=` stays untouched
7742
+ id: "key-value",
7743
+ 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})(${VAL})`, "gi"),
7744
+ replace: (_m, key, sep2) => `${key}${sep2}${REDACTED}`
7745
+ },
7746
+ {
7747
+ // `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
7748
+ id: "env-style",
7749
+ 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"),
7750
+ replace: (_m, head) => `${head}${REDACTED}`
7751
+ },
7752
+ {
7753
+ // long CLI flags only: `--password X`, `--token X`, `--api-key X`, `--secret X`, `--passwd X`
7754
+ id: "cli-flag",
7755
+ re: new RegExp(String.raw`(--(?:password|token|api-key|secret|passwd)(?:\s*=\s*|\s+))(${VAL})`, "gi"),
7756
+ replace: (_m, head) => `${head}${REDACTED}`
7757
+ },
7758
+ {
7759
+ // `scheme://user:pass@host` — redact the password, keep user and host
7760
+ id: "url-credentials",
7761
+ re: /((?<![a-z0-9+.-])[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:)([^\s/@]+)(@)/gi,
7762
+ replace: (_m, head, _pass, at) => `${head}${REDACTED}${at}`
7763
+ },
7764
+ {
7765
+ // provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
7766
+ // glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
7767
+ id: "token-prefix",
7768
+ 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)[A-Z0-9]{16}|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,
7769
+ replace: REDACTED
7770
+ },
7771
+ {
7772
+ // 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
7773
+ id: "long-run",
7774
+ re: /\b[A-Za-z0-9+/]{40,}={0,2}(?![\w/])/g,
7775
+ // a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
7776
+ replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
7777
+ }
7778
+ ];
7779
+ var PEM_BLOCK = /-----BEGIN[^-\n]*PRIVATE KEY-----[\s\S]*?(?:-----END[^-\n]*PRIVATE KEY-----|$)/g;
7780
+ var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
7781
+ var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
7782
+ var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
7783
+ function redactLine(line) {
7784
+ let out = line;
7785
+ for (const r of LINE_RULES) out = out.replace(r.re, r.replace);
7786
+ if (KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
7787
+ return out;
7788
+ }
7789
+ function redactSecrets(text) {
7790
+ const withPem = text.replace(PEM_BLOCK, `-----BEGIN PRIVATE KEY----- ${REDACTED}`);
7791
+ return withPem.split("\n").map(redactLine).join("\n");
7792
+ }
7793
+
7727
7794
  // src/hooks/ts/lib/loop-guard.ts
7728
7795
  var LOOP_MAX_REPEATS = 4;
7729
7796
  var LOOP_READ_STREAK = Number(process.env.PAI_LOOP_READ_STREAK) > 0 ? Number(process.env.PAI_LOOP_READ_STREAK) : 15;
@@ -7732,10 +7799,8 @@ var LOOP_DENY_REASON = `loop guard: you ran this command ${LOOP_MAX_REPEATS} tim
7732
7799
  var WAIT_CAP_MS = 45 * 6e4;
7733
7800
  var FP_FULL_READ_BYTES = 256 * 1024;
7734
7801
  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
7802
  function maskSecrets(text) {
7738
- return text.split("\n").map((l) => SECRET_LINE.test(l) ? MASKED_LINE : l).join("\n");
7803
+ return redactSecrets(text);
7739
7804
  }
7740
7805
 
7741
7806
  // src/utils/hash.ts
@@ -141,6 +141,73 @@ 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 VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
149
+ var REDACT_RULES = [
150
+ {
151
+ // `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
152
+ id: "authorization",
153
+ re: /(Authorization\s*:\s*)(Bearer|Basic)\s+(\S+)/gi,
154
+ replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
155
+ },
156
+ {
157
+ // `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
158
+ // the word must be a whole key segment, so `monkeys=` stays untouched
159
+ id: "key-value",
160
+ 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})(${VAL})`, "gi"),
161
+ replace: (_m, key, sep) => `${key}${sep}${REDACTED}`
162
+ },
163
+ {
164
+ // `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
165
+ id: "env-style",
166
+ 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"),
167
+ replace: (_m, head) => `${head}${REDACTED}`
168
+ },
169
+ {
170
+ // long CLI flags only: `--password X`, `--token X`, `--api-key X`, `--secret X`, `--passwd X`
171
+ id: "cli-flag",
172
+ re: new RegExp(String.raw`(--(?:password|token|api-key|secret|passwd)(?:\s*=\s*|\s+))(${VAL})`, "gi"),
173
+ replace: (_m, head) => `${head}${REDACTED}`
174
+ },
175
+ {
176
+ // `scheme://user:pass@host` — redact the password, keep user and host
177
+ id: "url-credentials",
178
+ re: /((?<![a-z0-9+.-])[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:)([^\s/@]+)(@)/gi,
179
+ replace: (_m, head, _pass, at) => `${head}${REDACTED}${at}`
180
+ },
181
+ {
182
+ // provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
183
+ // glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
184
+ id: "token-prefix",
185
+ 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)[A-Z0-9]{16}|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,
186
+ replace: REDACTED
187
+ },
188
+ {
189
+ // 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
190
+ id: "long-run",
191
+ re: /\b[A-Za-z0-9+/]{40,}={0,2}(?![\w/])/g,
192
+ // a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
193
+ replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
194
+ }
195
+ ];
196
+ var PEM_BLOCK = /-----BEGIN[^-\n]*PRIVATE KEY-----[\s\S]*?(?:-----END[^-\n]*PRIVATE KEY-----|$)/g;
197
+ var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
198
+ var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
199
+ var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
200
+ function redactLine(line) {
201
+ let out = line;
202
+ for (const r of LINE_RULES) out = out.replace(r.re, r.replace);
203
+ if (KEY_LINE.test(out)) out = out.replace(LONG_RUN.re, LONG_RUN.replace);
204
+ return out;
205
+ }
206
+ function redactSecrets(text) {
207
+ const withPem = text.replace(PEM_BLOCK, `-----BEGIN PRIVATE KEY----- ${REDACTED}`);
208
+ return withPem.split("\n").map(redactLine).join("\n");
209
+ }
210
+
144
211
  // src/hooks/ts/lib/loop-guard.ts
145
212
  var LOOP_MAX_REPEATS = 4;
146
213
  var LOOP_READ_STREAK = Number(process.env.PAI_LOOP_READ_STREAK) > 0 ? Number(process.env.PAI_LOOP_READ_STREAK) : 15;
@@ -149,10 +216,8 @@ var LOOP_DENY_REASON = `loop guard: you ran this command ${LOOP_MAX_REPEATS} tim
149
216
  var WAIT_CAP_MS = 45 * 6e4;
150
217
  var FP_FULL_READ_BYTES = 256 * 1024;
151
218
  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
219
  function maskSecrets(text) {
155
- return text.split("\n").map((l) => SECRET_LINE.test(l) ? MASKED_LINE : l).join("\n");
220
+ return redactSecrets(text);
156
221
  }
157
222
 
158
223
  // src/utils/hash.ts
@@ -0,0 +1,128 @@
1
+ #!/usr/bin/env node
2
+ import { createRequire as __paiCreateRequire } from 'node:module';
3
+ const require = __paiCreateRequire(import.meta.url);
4
+ if (!process.env.PAI_QUIET_NOTICES) process.env.PAI_QUIET_NOTICES = '1';
5
+
6
+ // src/session/handoff.ts
7
+ import { appendFileSync, mkdirSync as mkdirSync2, readdirSync as readdirSync2, readFileSync as readFileSync2, statSync as statSync2, writeFileSync } from "node:fs";
8
+ import { basename, dirname as dirname2, join as join2 } from "node:path";
9
+
10
+ // src/workers/ps-table.ts
11
+ var PS_MAX_BUFFER = 64 * 1024 * 1024;
12
+
13
+ // src/utils/redact.ts
14
+ var REDACTED = "[REDACTED]";
15
+ var REDACTED_RE = String.raw`\[REDACTED\]`;
16
+ var KEY_WORDS = "password|passwd|secret|token|api[_-]?key|credential|auth(?:orization)?|bearer";
17
+ var VAL = String.raw`(?:"[^"]*"|'[^']*'|[^\s'"]+)`;
18
+ var REDACT_RULES = [
19
+ {
20
+ // `Authorization: Bearer xxx` / `Authorization: Basic xxx` — keep the scheme
21
+ id: "authorization",
22
+ re: /(Authorization\s*:\s*)(Bearer|Basic)\s+(\S+)/gi,
23
+ replace: (_m, head, scheme) => `${head}${scheme} ${REDACTED}`
24
+ },
25
+ {
26
+ // `key=value`, `key: value`, `"key": "value"` — key carries a secret-ish word;
27
+ // the word must be a whole key segment, so `monkeys=` stays untouched
28
+ id: "key-value",
29
+ 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})(${VAL})`, "gi"),
30
+ replace: (_m, key, sep) => `${key}${sep}${REDACTED}`
31
+ },
32
+ {
33
+ // `export FOO_TOKEN=...` / `FOO_KEY=...` — SCREAMING_SNAKE env style
34
+ id: "env-style",
35
+ 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"),
36
+ replace: (_m, head) => `${head}${REDACTED}`
37
+ },
38
+ {
39
+ // long CLI flags only: `--password X`, `--token X`, `--api-key X`, `--secret X`, `--passwd X`
40
+ id: "cli-flag",
41
+ re: new RegExp(String.raw`(--(?:password|token|api-key|secret|passwd)(?:\s*=\s*|\s+))(${VAL})`, "gi"),
42
+ replace: (_m, head) => `${head}${REDACTED}`
43
+ },
44
+ {
45
+ // `scheme://user:pass@host` — redact the password, keep user and host
46
+ id: "url-credentials",
47
+ re: /((?<![a-z0-9+.-])[a-z][a-z0-9+.-]*:\/\/[^\s/@:]+:)([^\s/@]+)(@)/gi,
48
+ replace: (_m, head, _pass, at) => `${head}${REDACTED}${at}`
49
+ },
50
+ {
51
+ // provider token prefixes: sk-ant-, sk-, ghp_/gho_/ghu_/ghs_/ghr_, github_pat_,
52
+ // glpat-, xoxb-/xoxp-/xoxa-, AKIA/ASIA + 16 chars, AIza + 35 chars, JWT (eyJ… three segments)
53
+ id: "token-prefix",
54
+ 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)[A-Z0-9]{16}|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,
55
+ replace: REDACTED
56
+ },
57
+ {
58
+ // 40+ char opaque base64/hex run, only on a line that also has a secret-ish key word
59
+ id: "long-run",
60
+ re: /\b[A-Za-z0-9+/]{40,}={0,2}(?![\w/])/g,
61
+ // a bare 40-hex git SHA stays; it is only redacted as the value of a secret key
62
+ replace: (m) => /^[0-9a-f]{40}$/i.test(m) ? m : REDACTED
63
+ }
64
+ ];
65
+ var LINE_RULES = REDACT_RULES.filter((r) => r.id !== "long-run");
66
+ var LONG_RUN = REDACT_RULES.find((r) => r.id === "long-run");
67
+ var KEY_LINE = new RegExp(`(?:${KEY_WORDS})`, "i");
68
+
69
+ // src/hooks/ts/lib/loop-guard.ts
70
+ var LOOP_MAX_REPEATS = 4;
71
+ var LOOP_READ_STREAK = Number(process.env.PAI_LOOP_READ_STREAK) > 0 ? Number(process.env.PAI_LOOP_READ_STREAK) : 15;
72
+ var SELF = "If your part is done, commit and write your R report. If you are stuck, report the blocker in R x= (or use pai worker help if available).";
73
+ var LOOP_DENY_REASON = `loop guard: you ran this command ${LOOP_MAX_REPEATS} times with the same result and nothing changed. Stop repeating it. ${SELF}`;
74
+ var WAIT_CAP_MS = 45 * 6e4;
75
+ var FP_FULL_READ_BYTES = 256 * 1024;
76
+ var FP_TOTAL_BYTES = 4 * 1024 * 1024;
77
+
78
+ // src/config/pai-home.ts
79
+ import { existsSync, mkdirSync, readFileSync, copyFileSync, renameSync, readdirSync, statSync } from "node:fs";
80
+ import { homedir } from "node:os";
81
+ import { join, dirname } from "node:path";
82
+ function legacyPaiHomeDir() {
83
+ return join(homedir(), ".claude", "pai");
84
+ }
85
+ function defaultPaiHomeDir() {
86
+ return join(homedir(), ".pai");
87
+ }
88
+ function paiHomeDir() {
89
+ if (process.env.PAI_HOME) return process.env.PAI_HOME;
90
+ const fresh = defaultPaiHomeDir();
91
+ const legacy = legacyPaiHomeDir();
92
+ if (!existsSync(join(fresh, "config.yaml")) && existsSync(join(legacy, "config.yaml"))) return legacy;
93
+ return fresh;
94
+ }
95
+ function paiHomePath(...segments) {
96
+ return join(paiHomeDir(), ...segments);
97
+ }
98
+
99
+ // src/session/handoff.ts
100
+ function handoffsDir() {
101
+ return paiHomePath("handoffs");
102
+ }
103
+ function appendHandoffLink(from, to, now = /* @__PURE__ */ new Date()) {
104
+ try {
105
+ const dir = handoffsDir();
106
+ mkdirSync2(dir, { recursive: true, mode: 448 });
107
+ appendFileSync(join2(dir, "links.jsonl"), `${JSON.stringify({ ts: now.toISOString(), from, to })}
108
+ `);
109
+ } catch {
110
+ }
111
+ }
112
+
113
+ // src/hooks/ts/user-prompt/handoff-link.ts
114
+ var MARKER = /\[pai-handoff from=([^\]\s]+)\]/;
115
+ async function main() {
116
+ try {
117
+ const chunks = [];
118
+ for await (const chunk of process.stdin) chunks.push(chunk);
119
+ const input = JSON.parse(Buffer.concat(chunks).toString("utf8"));
120
+ const prompt = typeof input.prompt === "string" ? input.prompt : "";
121
+ const m = MARKER.exec(prompt);
122
+ if (!m || !input.session_id) return;
123
+ appendHandoffLink(m[1], input.session_id);
124
+ } catch {
125
+ }
126
+ }
127
+ void main();
128
+ //# sourceMappingURL=handoff-link.mjs.map