@tekmidian/pai 1.0.6 → 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.
Files changed (130) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/auto-route-CAlZ5p-h.mjs +11 -0
  3. package/dist/{auto-route-YaEGVrFl.mjs → auto-route-PDOAYszN.mjs} +2 -2
  4. package/dist/{budget-DEiebT2A.mjs → budget-BXmsSBLI.mjs} +10 -10
  5. package/dist/{caller-identity-C6Nc96iM.mjs → caller-identity-DPDSrZE2.mjs} +2 -2
  6. package/dist/{capacity-B2PgKAg4.mjs → capacity-CThSydrd.mjs} +25 -13
  7. package/dist/{chain-CtK49-Ma.mjs → chain-BvdKqRiZ.mjs} +5 -5
  8. package/dist/cli/index.mjs +182 -111
  9. package/dist/{cockpit-actions-D1OPP6Es.mjs → cockpit-actions-BgdKB9G3.mjs} +19 -19
  10. package/dist/{cockpit-actions-C73mJAJ8.mjs → cockpit-actions-DNl0rKfW.mjs} +14 -14
  11. package/dist/cockpit-memory-CqLPjcWe.mjs +20 -0
  12. package/dist/config/defaults/config.yaml +6 -0
  13. package/dist/config/defaults/workers.yaml +2 -0
  14. package/dist/{config-DLmyEK2q.mjs → config-C2dd2SXS.mjs} +1 -1
  15. package/dist/{config-Bz8pAU5Q.mjs → config-DGV64YJa.mjs} +9 -1
  16. package/dist/{controls-rIItFeIJ.mjs → controls-ByrcupcA.mjs} +14 -14
  17. package/dist/daemon/index.mjs +29 -29
  18. package/dist/{daemon-SoUvPUOf.mjs → daemon-BjgJyJMP.mjs} +22 -22
  19. package/dist/daemon-iymy18Ie.mjs +46 -0
  20. package/dist/daemon-mcp/index.mjs +27 -27
  21. package/dist/{embed-pass-CN1D8MXl.mjs → embed-pass-DdTMn4DH.mjs} +4 -4
  22. package/dist/{endreason-C2-hYK0_.mjs → endreason-BjPom527.mjs} +4 -4
  23. package/dist/{fallback-CwPSCrX8.mjs → fallback-CQ8_CuVu.mjs} +4 -4
  24. package/dist/{health-D0mUAVdw.mjs → health-Bb2U4PNK.mjs} +4 -4
  25. package/dist/hooks/block-sleep-poll.mjs +9 -0
  26. package/dist/hooks/capture-all-events.mjs +38 -7
  27. package/dist/hooks/capture-tool-output.mjs +38 -7
  28. package/dist/hooks/handoff-link.mjs +37 -6
  29. package/dist/hooks/load-project-context.mjs +9 -0
  30. package/dist/hooks/local-model-hint.mjs +9 -0
  31. package/dist/hooks/route-agents-to-worker.mjs +9 -0
  32. package/dist/hooks/security-validator.mjs +124 -28
  33. package/dist/hooks/supervision-banner.mjs +40 -7
  34. package/dist/hooks/worker-edit-repair.mjs +9 -0
  35. package/dist/hooks/worker-guard.mjs +46 -6
  36. package/dist/hooks/worker-note.mjs +47 -7
  37. package/dist/hooks/worker-pool-host.mjs +308 -146
  38. package/dist/hooks/worker-proxy.mjs +9 -0
  39. package/dist/hooks/worker-status-line.mjs +49 -7
  40. package/dist/hooks/worker-supervision.mjs +9 -0
  41. package/dist/hooks/worker-tool-name-repair.mjs +9 -0
  42. package/dist/index.mjs +7 -7
  43. package/dist/kill-tree-BlPw1vaU.mjs +10 -0
  44. package/dist/{kill-tree-DPiMscaY.mjs → kill-tree-DTmiEb3T.mjs} +7 -7
  45. package/dist/{launch-Bn2Zf90h.mjs → launch-CV6oPHI2.mjs} +3 -3
  46. package/dist/{launch-BZT3JDoZ.mjs → launch-Dy8qQnSD.mjs} +3 -3
  47. package/dist/{lessons-CFVU0cwA.mjs → lessons-CdmqZD0G.mjs} +21 -21
  48. package/dist/{local-candidate-DFd4pp-w.mjs → local-candidate-C2FGhf54.mjs} +2 -2
  49. package/dist/{local-instances-KTh8IeOT.mjs → local-instances-GgXydQ2P.mjs} +1 -1
  50. package/dist/{local-tiers-DSlIYvvm.mjs → local-tiers-X_dQfI4Q.mjs} +1 -1
  51. package/dist/{main-config-ops-rda08BCD.mjs → main-config-ops-C_fkINDv.mjs} +2 -2
  52. package/dist/{main-resolver-BKwI0I6H.mjs → main-resolver-CN_sfG1R.mjs} +13 -13
  53. package/dist/{model-inventory-BXv15B0d.mjs → model-inventory-BYNrSTaY.mjs} +10 -10
  54. package/dist/{models-add-5yXTyz3g.mjs → models-add-Dc7VXmcu.mjs} +30 -30
  55. package/dist/operator-IrLbk8hy.mjs +7 -0
  56. package/dist/{operator-Br6GeswF.mjs → operator-lRGvYr3D.mjs} +2 -2
  57. package/dist/{pai-marker-D6OoVbM_.mjs → pai-marker-kA0iM7rP.mjs} +2 -2
  58. package/dist/{pane-audit-DLYy9-4g.mjs → pane-audit-DUuilP1V.mjs} +8 -8
  59. package/dist/{paths-CypxFTfn.mjs → paths-BwfwHOvN.mjs} +2 -2
  60. package/dist/{paths-DIOwNcj-.mjs → paths-CKGYM0Lb.mjs} +2 -2
  61. package/dist/{planner-BzZ_2lc-.mjs → planner-BDHVUkIM.mjs} +22 -22
  62. package/dist/{pool-9EsbKD-U.mjs → pool-CFeHGX7q.mjs} +2 -2
  63. package/dist/{pool-cli-Cy5mlycP.mjs → pool-cli-Bj2TeA-d.mjs} +5 -5
  64. package/dist/{pool-cli-Db0uDwB9.mjs → pool-cli-DOLgPgOM.mjs} +5 -5
  65. package/dist/{project-setup-DHxdJjEc.mjs → project-setup-i5D0xkTn.mjs} +21 -21
  66. package/dist/{providers-BNV7CzC-.mjs → providers-BC2Myo_O.mjs} +5 -5
  67. package/dist/{providers-BH6hQYbU.mjs → providers-C-mnlH1b.mjs} +11 -11
  68. package/dist/{registrable-BwFiqazy.mjs → registrable-Ct0DKNKS.mjs} +6 -6
  69. package/dist/{registrable-Dxs4oKIj.mjs → registrable-D_4qXCnq.mjs} +4 -4
  70. package/dist/{render-jPpMrudf.mjs → render-CbifCwTb.mjs} +175 -65
  71. package/dist/{render-DVGXpfaT.mjs → render-FB4Fv_fi.mjs} +10 -10
  72. package/dist/{root-C8cxhdn9.mjs → root-80ESg6b7.mjs} +21 -21
  73. package/dist/{root-DmOzMeSv.mjs → root-B-ZYiEgi.mjs} +10 -10
  74. package/dist/{route-table-COAmc1nB.mjs → route-table-DcBZCuco.mjs} +10 -10
  75. package/dist/{routing-aJKMIagQ.mjs → routing-CF0wlR-_.mjs} +10 -10
  76. package/dist/{routing-B_cg1_Xx.mjs → routing-CJ8ioPl2.mjs} +10 -10
  77. package/dist/{run-DE9Q0ldN.mjs → run-CAjfKBQV.mjs} +53 -26
  78. package/dist/{scan-CNMcltOX.mjs → scan-ew8M6tTH.mjs} +3 -3
  79. package/dist/{scope-BTWstJ1B.mjs → scope-BRcaPw5D.mjs} +4 -4
  80. package/dist/session-BmQsXF_a.mjs +35 -0
  81. package/dist/{session-HBYOABWU.mjs → session-C1JnDXvP.mjs} +14 -14
  82. package/dist/{session-scan-BZxnYN1v.mjs → session-scan-DWCUKhDM.mjs} +5 -5
  83. package/dist/{session-scan-CX3MKCNg.mjs → session-scan-DihMibI-.mjs} +4 -4
  84. package/dist/{session-usage-CCmPFFa6.mjs → session-usage-BRIWFYPS.mjs} +2 -2
  85. package/dist/{status-D52xC_i0.mjs → status-Bj4yVKj0.mjs} +3 -3
  86. package/dist/{status-Cecau8Ps.mjs → status-DTMT5lyn.mjs} +2 -2
  87. package/dist/{tool-errors-BFw1gv-z.mjs → tool-errors-BOW2n882.mjs} +2 -2
  88. package/dist/{tool-errors-COM2JGEr.mjs → tool-errors-jNJj3Gzm.mjs} +5 -5
  89. package/dist/{viewer-DvBg6N22.mjs → viewer-4BU8w_gK.mjs} +14 -14
  90. package/dist/viewer-D3VEdqhC.mjs +22 -0
  91. package/dist/{wait-C5iWILj_.mjs → wait-BindDA5w.mjs} +3 -3
  92. package/dist/{worker-config-DkONNk_H.mjs → worker-config-CdPmb4_2.mjs} +25 -25
  93. package/dist/{worker-config-BmcJ9R0U.mjs → worker-config-CfV2dgSb.mjs} +29 -29
  94. package/dist/{workers-config-DwzrtdYu.mjs → workers-config-2VipVOYk.mjs} +1 -1
  95. package/dist/{worktree-O_kU6Q3y.mjs → worktree-7ZS3RBf8.mjs} +21 -11
  96. package/gemini-extension.json +1 -1
  97. package/package.json +1 -1
  98. package/pai-plugin.json +1 -1
  99. package/plugins/context-preservation/plugin.json +1 -1
  100. package/plugins/core/plugin.json +1 -1
  101. package/plugins/creative/plugin.json +1 -1
  102. package/plugins/observability/plugin.json +1 -1
  103. package/plugins/productivity/plugin.json +1 -1
  104. package/plugins/semantic-search/plugin.json +1 -1
  105. package/plugins/ui/plugin.json +1 -1
  106. package/plugins/zettelkasten/plugin.json +1 -1
  107. package/src/hooks/ts/lib/rules/builtin/base64-decode-to-shell.rule.yaml +3 -1
  108. package/src/hooks/ts/lib/rules/builtin/chmod-zero.rule.yaml +2 -0
  109. package/src/hooks/ts/lib/rules/builtin/curl-piped-to-shell.rule.yaml +8 -1
  110. package/src/hooks/ts/lib/rules/builtin/find-root-delete.rule.yaml +4 -1
  111. package/src/hooks/ts/lib/rules/builtin/instruction-override-disregard.rule.yaml +2 -0
  112. package/src/hooks/ts/lib/rules/builtin/reverse-shell-dev-tcp.rule.yaml +3 -0
  113. package/src/hooks/ts/lib/rules/builtin/reverse-shell-interactive-bash.rule.yaml +1 -0
  114. package/src/hooks/ts/lib/rules/builtin/rm-recursive-parent.rule.yaml +3 -1
  115. package/src/hooks/ts/lib/rules/builtin/rm-recursive-relative.rule.yaml +2 -1
  116. package/src/hooks/ts/lib/rules/builtin/rm-recursive-root.rule.yaml +4 -1
  117. package/src/hooks/ts/lib/rules/builtin/rm-trailing-tilde.rule.yaml +2 -1
  118. package/src/hooks/ts/lib/rules/builtin.generated.ts +34 -7
  119. package/src/hooks/ts/lib/rules/eval.ts +6 -4
  120. package/src/hooks/ts/lib/rules/lint.ts +7 -1
  121. package/src/hooks/ts/lib/rules/load.ts +55 -20
  122. package/src/hooks/ts/lib/rules/types.ts +2 -0
  123. package/src/hooks/ts/pre-tool-use/security-validator.ts +10 -2
  124. package/dist/auto-route-Bc8xP6TQ.mjs +0 -11
  125. package/dist/cockpit-memory-CLHZD64W.mjs +0 -20
  126. package/dist/daemon-176qA79N.mjs +0 -46
  127. package/dist/kill-tree-Dxei6qlR.mjs +0 -10
  128. package/dist/operator-Bmv5tiHQ.mjs +0 -7
  129. package/dist/session-DgZifjLx.mjs +0 -35
  130. package/dist/viewer-Ce-Xa9L3.mjs +0 -22
@@ -2,28 +2,28 @@
2
2
  import { _ as warn$1, a as fmtDate, c as ok$1, d as scaffoldProjectDirs, f as shortenPath, g as stripAnsi, h as smartDecodeDir, i as err, l as renderTable$1, m as slugify, n as dim$1, o as header, r as encodeDir, s as now, t as bold$1, u as resolvePath } from "../utils-J2b9y8PC.mjs";
3
3
  import { _ as paiHomePath, a as paiCacheDir, c as PaiFileMigrationError, d as defaultPaiHomeDir, f as legacyConfigDir, g as paiHomeDir, h as migratePaiFile, l as claudeHomeDir, m as migratePaiDir, o as paiSocketPath, r as daemonLogPath, s as schedulerLogPath, u as claudeProjectsDir, v as resolvePaiFile } from "../runtime-paths-twfV23YL.mjs";
4
4
  import { a as slugify$1, i as parseSessionFilename } from "../migrate-C2z1YmWC.mjs";
5
- import { Et as appendLedger, M as readWorkersSection, R as LOOPBACK_HOST, _t as DEFAULT_CONTEXT_WINDOW, bt as stripModelVariant, c as WorkersConfigError, et as relocateWorkersYaml, f as escalationCloud, m as isLocalProvider, p as getProviderOrNative, rt as workersYamlPath, t as ANTHROPIC_NATIVE, v as nativeAnthropicModels, yt as contextWindowFromModelId } from "../config-Bz8pAU5Q.mjs";
5
+ import { Et as appendLedger, M as readWorkersSection, R as LOOPBACK_HOST, _t as DEFAULT_CONTEXT_WINDOW, bt as stripModelVariant, c as WorkersConfigError, et as relocateWorkersYaml, f as escalationCloud, m as isLocalProvider, p as getProviderOrNative, rt as workersYamlPath, t as ANTHROPIC_NATIVE, v as nativeAnthropicModels, yt as contextWindowFromModelId } from "../config-DGV64YJa.mjs";
6
6
  import { A as DEFAULT_PG_CONNECTION_TIMEOUT_MS, C as migrateMainConfigToYaml, F as quoteIdent, M as isContainerTarget, N as postgresConnectionString, O as readJsonStrict, P as postgresFullTarget, S as MainConfigError, T as resolvedMainConfigPath, c as loadConfig, d as paiConfigYamlFilePath, f as readMainConfigRaw, h as effectiveMainConfig, j as assertPgName, k as writeJsonAtomic, l as migrateConfigFile, n as CONFIG_FILE$2, o as expandHome, p as writeMainConfigRaw, t as CONFIG_DIR, u as paiConfigFilePath } from "../config-SlZ-Z52i.mjs";
7
- import { i as ledgerPath, n as ensureNoMcpConfig, r as eventsPath, u as workersLogDir } from "../paths-CypxFTfn.mjs";
8
- import "../worktree-O_kU6Q3y.mjs";
9
- import { K as writeSectionToForge, R as formatStale, V as loadStatusConfig, W as upsertSection, b as loadStatusesCached, g as isLive, h as isChatPane, v as loadStatus, y as loadStatuses } from "../status-Cecau8Ps.mjs";
10
- import { A as readClaudeJson, N as writeClaudeJson, S as inputSideTokens, h as poolSettings, i as bundleBuildStamp, j as registerMcpScript, k as mcpEntryRunsScript, v as readPoolState, w as expandMcpNames } from "../pool-9EsbKD-U.mjs";
11
- import { a as unregistrableReason, s as worktreeReason } from "../registrable-Dxs4oKIj.mjs";
12
- import "../pai-marker-D6OoVbM_.mjs";
7
+ import { i as ledgerPath, n as ensureNoMcpConfig, r as eventsPath, u as workersLogDir } from "../paths-BwfwHOvN.mjs";
8
+ import "../worktree-7ZS3RBf8.mjs";
9
+ import { K as writeSectionToForge, R as formatStale, V as loadStatusConfig, W as upsertSection, b as loadStatusesCached, g as isLive, h as isChatPane, v as loadStatus, y as loadStatuses } from "../status-DTMT5lyn.mjs";
10
+ import { A as readClaudeJson, N as writeClaudeJson, S as inputSideTokens, h as poolSettings, i as bundleBuildStamp, j as registerMcpScript, k as mcpEntryRunsScript, v as readPoolState, w as expandMcpNames } from "../pool-CFeHGX7q.mjs";
11
+ import { a as unregistrableReason, s as worktreeReason } from "../registrable-D_4qXCnq.mjs";
12
+ import "../pai-marker-kA0iM7rP.mjs";
13
13
  import "../helpers-CRuBUas3.mjs";
14
14
  import { t as applyRecencyBoost } from "../search-RSyeQqj1.mjs";
15
15
  import { t as dropItermBundleId } from "../env-BE8mrsxr.mjs";
16
- import { a as ownerSessionName, d as terminalHasName } from "../scope-BTWstJ1B.mjs";
17
- import { At as resolveBindAddress, Bn as setParkConfigSource, Dn as allSetups, Dt as routerPort, E as budgetCache, Et as routerHandler, F as LimitsCache, Gn as appendUsage, Hn as recordDuration, In as setupsPath, Kn as formatSessionStats, Nn as saveSetup, On as downLocalProviders, Ot as defaultV1Guard, Sn as providerHostPort, U as computeInventory, Un as aggregate, Vn as sharedParker, W as currentInventory, Wn as aggregateBySession, Xn as parseSince, Y as inventoryText, Zn as readUsage, at as readInventoryInput, jn as loadSaved, kt as displayHost, m as readRoutingState, pn as readProfiles, pt as isLoopbackProvider, qn as formatStats, qt as sessionStartTarget, un as SESSION_NAME_ENV, vn as localProviderForDelegation, x as SESSION_WORKER_PROVIDER_ENV, xt as routeVerdictLine, zn as parkConfigFrom } from "../routing-aJKMIagQ.mjs";
16
+ import { a as ownerSessionName, d as terminalHasName } from "../scope-BRcaPw5D.mjs";
17
+ import { At as resolveBindAddress, Bn as setParkConfigSource, Dn as allSetups, Dt as routerPort, E as budgetCache, Et as routerHandler, F as LimitsCache, Gn as appendUsage, Hn as recordDuration, In as setupsPath, Kn as formatSessionStats, Nn as saveSetup, On as downLocalProviders, Ot as defaultV1Guard, Sn as providerHostPort, U as computeInventory, Un as aggregate, Vn as sharedParker, W as currentInventory, Wn as aggregateBySession, Xn as parseSince, Y as inventoryText, Zn as readUsage, at as readInventoryInput, jn as loadSaved, kt as displayHost, m as readRoutingState, pn as readProfiles, pt as isLoopbackProvider, qn as formatStats, qt as sessionStartTarget, un as SESSION_NAME_ENV, vn as localProviderForDelegation, x as SESSION_WORKER_PROVIDER_ENV, xt as routeVerdictLine, zn as parkConfigFrom } from "../routing-CF0wlR-_.mjs";
18
18
  import { n as minOf } from "../min-max-DrSRUaWQ.mjs";
19
- import "../tool-errors-BFw1gv-z.mjs";
20
- import "../wait-C5iWILj_.mjs";
19
+ import "../tool-errors-BOW2n882.mjs";
20
+ import "../wait-BindDA5w.mjs";
21
21
  import "../local-tiers-CqwGUcEn.mjs";
22
- import { a as buildsDir, c as listBuilds, f as removeTicket, h as tryStart, i as buildNext, o as enqueue, p as renderBuildQueue, r as buildLogPath, s as getTicket, u as patchTicket, v as poolSlots, y as slotsFor } from "../caller-identity-C6Nc96iM.mjs";
22
+ import { a as buildsDir, c as listBuilds, f as removeTicket, h as tryStart, i as buildNext, o as enqueue, p as renderBuildQueue, r as buildLogPath, s as getTicket, u as patchTicket, v as poolSlots, y as slotsFor } from "../caller-identity-DPDSrZE2.mjs";
23
23
  import { d as setSchedConfigSource, f as sharedScheduler, i as mirrorTo, s as schedConfigFrom } from "../scheduler-CtUyWJ3O.mjs";
24
- import { i as effectiveCap, o as providerCap, r as capacityOf } from "../capacity-B2PgKAg4.mjs";
24
+ import { i as effectiveCap, o as providerCap, r as capacityOf } from "../capacity-CThSydrd.mjs";
25
25
  import "../local-instances-DhF4_sV2.mjs";
26
- import { n as tierProviderNames, t as isLocalCandidate } from "../local-candidate-DFd4pp-w.mjs";
26
+ import { n as tierProviderNames, t as isLocalCandidate } from "../local-candidate-C2FGhf54.mjs";
27
27
  import { n as OPT, t as CliError } from "../define-CjJsmq-6.mjs";
28
28
  import { a as getStorageBackend, c as MergeError, f as humanDuration, i as getRegistryBackend, l as federationDbPath, o as oldRegistryPath, r as createStorageBackend, s as registryDbPath, u as oldFederationPath } from "../factory-CYwa0jYj.mjs";
29
29
  import { c as resolveFromModule, i as retryTransient, n as embedChunksWithBackend, r as indexProjectWithBackend, s as packageRoot } from "../postgres-BL5oBBgY.mjs";
@@ -32,34 +32,34 @@ import "../embeddings-BVq3esBF.mjs";
32
32
  import "../router-D2476pOp.mjs";
33
33
  import { t as detectProject } from "../detect-DLjeYwnt.mjs";
34
34
  import { n as getProject$1, o as requireProject, r as getProjectAliases, s as resolveIdentifier } from "../helpers-Dj2nY56t.mjs";
35
- import { a as resolveHome, c as upsertSession, d as scanTranscriptFolders, f as transcriptFiles, l as claudeProjectsDir$1, n as loadScanConfig, o as saveScanConfig, r as migrateScanConfig, s as upsertProject, t as cmdScan, u as findMovedProjects } from "../scan-CNMcltOX.mjs";
36
- import { A as cmdAdd, B as cmdRebind, F as cmdEdit, H as cmdUnarchive, I as cmdGo, L as cmdInfo$1, M as cmdArchive, N as cmdConsolidate, P as cmdDetect, R as cmdList$1, S as legacy, U as findMovedPath, V as cmdTag$1, _ as cmdList, a as newTop, b as cmdSlug, f as sessionCommand, g as cmdInfo, h as cmdAutoRoute, i as lsCommand, j as cmdAlias, l as renameTop, m as cmdActive, r as collectView, s as openTop, v as cmdRename, x as cmdTag, y as cmdRoute, z as cmdMove } from "../session-HBYOABWU.mjs";
37
- import { a as detectCurrentProviderName, i as detectCurrentModel, n as buildLaunchPlan, o as launchableProviderNames, r as buildLaunchRows, s as maskLaunchEnv } from "../launch-Bn2Zf90h.mjs";
38
- import { a as colorEnabled, c as renderCommandHelp, d as renderOverview, f as renderTable$2, l as renderMarkdown, m as usageLine, o as makeStyle, p as suggest, s as mdCommand, u as renderMore } from "../health-D0mUAVdw.mjs";
39
- import { a as providerResumePlan, n as launchInDir, o as restoreTopLevel, r as launchPrompt, s as resumeArgvText, t as hasConversation } from "../launch-BZT3JDoZ.mjs";
40
- import { _ as setupsTable, a as lastSetup, m as rootCommand } from "../root-DmOzMeSv.mjs";
35
+ import { a as resolveHome, c as upsertSession, d as scanTranscriptFolders, f as transcriptFiles, l as claudeProjectsDir$1, n as loadScanConfig, o as saveScanConfig, r as migrateScanConfig, s as upsertProject, t as cmdScan, u as findMovedProjects } from "../scan-ew8M6tTH.mjs";
36
+ import { A as cmdAdd, B as cmdRebind, F as cmdEdit, H as cmdUnarchive, I as cmdGo, L as cmdInfo$1, M as cmdArchive, N as cmdConsolidate, P as cmdDetect, R as cmdList$1, S as legacy, U as findMovedPath, V as cmdTag$1, _ as cmdList, a as newTop, b as cmdSlug, f as sessionCommand, g as cmdInfo, h as cmdAutoRoute, i as lsCommand, j as cmdAlias, l as renameTop, m as cmdActive, r as collectView, s as openTop, v as cmdRename, x as cmdTag, y as cmdRoute, z as cmdMove } from "../session-C1JnDXvP.mjs";
37
+ import { a as detectCurrentProviderName, i as detectCurrentModel, n as buildLaunchPlan, o as launchableProviderNames, r as buildLaunchRows, s as maskLaunchEnv } from "../launch-CV6oPHI2.mjs";
38
+ import { a as colorEnabled, c as renderCommandHelp, d as renderOverview, f as renderTable$2, l as renderMarkdown, m as usageLine, o as makeStyle, p as suggest, s as mdCommand, u as renderMore } from "../health-Bb2U4PNK.mjs";
39
+ import { a as providerResumePlan, n as launchInDir, o as restoreTopLevel, r as launchPrompt, s as resumeArgvText, t as hasConversation } from "../launch-Dy8qQnSD.mjs";
40
+ import { _ as setupsTable, a as lastSetup, m as rootCommand } from "../root-B-ZYiEgi.mjs";
41
41
  import { n as fetchLiveSessions, r as sendToSession, t as callAiBroker } from "../aibroker-client-CXsyC7A8.mjs";
42
- import { a as resolveSessionByNameOrId, o as scanCacheFilePath, r as migrateSessionScanCache, s as scanSessions, t as fmtAge } from "../session-scan-CX3MKCNg.mjs";
43
- import { A as routerPidFile, B as usageContextTokens, D as routerHandoverFile, E as probeRouter, F as startHandover, I as paneWaiver, L as launchPane, M as routerSwapArgs, P as spawnRouter, R as noTerminalReasons, S as usageJson, T as projectLaunchConfig, b as renderUsage, c as reportOriginWithHost, f as dirtyPaths, g as realRunnerDeps, j as routerRunningPid, k as routerLogFile, l as runMessenger, s as finishDetached, u as startDetached, w as pinNotices, x as transcriptUsage, y as priceTableText } from "../run-DE9Q0ldN.mjs";
44
- import { C as readRunLog, D as resumeState, E as requestPlanStop, F as runLogPath, I as PlanTracker, M as dirtyConflicts, O as runExitCode, Ot as runPaneExec, P as loadPlan, S as planStopPath, T as renderStatus, Y as readRunLock, ht as resolveHostSession, j as PlanError, k as runPlan, l as PlanReporter, nt as closePaneForWorker, ot as inVisiblePane, q as planLockPath, rt as closeSelfPane, u as QueueReporter, vt as writePaneTitle, w as renderSchedule, x as planStatus, y as blockedMessage } from "../controls-rIItFeIJ.mjs";
45
- import "../endreason-C2-hYK0_.mjs";
46
- import { B as scanTranscript, H as loadBuildsConfig, L as listRules, N as endBuildWait, P as claudeSessionTranscript, R as loadRules, V as maskSecrets, j as beginBuildWait, q as psTable, z as userRuleDirs } from "../render-jPpMrudf.mjs";
47
- import "../operator-Br6GeswF.mjs";
48
- import "../kill-tree-DPiMscaY.mjs";
49
- import { s as poolReloadLive } from "../pool-cli-Db0uDwB9.mjs";
50
- import "../chain-CtK49-Ma.mjs";
51
- import { _ as issueClaims, a as branchDiff, b as workerCommand, c as runQueue, d as loadSettings, f as move, g as issueClaim, h as renderReview, i as projectChecks, l as QueueStore, m as renderList, n as initProject, o as realQueueDeps, p as queueStatePath, r as isGitProject, s as acceptItems, t as formatCheck, u as again, v as issueStale } from "../project-setup-DHxdJjEc.mjs";
52
- import { m as runInPane, r as closeFinishedPanes } from "../pane-audit-DLYy9-4g.mjs";
53
- import "../viewer-DvBg6N22.mjs";
54
- import { g as setWorkersEnabled, s as describeProviders } from "../providers-BNV7CzC-.mjs";
55
- import { $ as exportDefaultLayout, B as mergeSettings, G as cachedRows, J as handleCockpit, K as cachedSessionMap, Q as warmCockpit, W as SystemMonitor, X as setEndpointHealth, Y as setActionHooks, Z as setRuntimeSampler, ct as providersCommand, et as createEndpointHealth, it as withWorkerAttribution, n as WORKER_CONFIG_COMMANDS, nt as loadWorkerWindows, q as cachedWorkerWindows, rt as sessionDisplayName, t as PROVIDER_EDIT_COMMANDS, tt as loadSessionMap, z as installWorkers } from "../worker-config-DkONNk_H.mjs";
56
- import { a as listConfigOp, i as getConfigValueOp, n as formatConfigGetOutput, o as setConfigValueOp, r as formatConfigSource, s as unsetConfigValueOp, t as MainConfigOpsError } from "../main-config-ops-rda08BCD.mjs";
57
- import { H as acquireRun, U as readRun, V as cockpitProbeSettings, k as readRuntimeCommands } from "../cockpit-actions-D1OPP6Es.mjs";
42
+ import { a as resolveSessionByNameOrId, o as scanCacheFilePath, r as migrateSessionScanCache, s as scanSessions, t as fmtAge } from "../session-scan-DihMibI-.mjs";
43
+ import { A as routerPidFile, B as usageContextTokens, D as routerHandoverFile, E as probeRouter, F as startHandover, I as paneWaiver, L as launchPane, M as routerSwapArgs, P as spawnRouter, R as noTerminalReasons, S as usageJson, T as projectLaunchConfig, b as renderUsage, c as reportOriginWithHost, f as dirtyPaths, g as realRunnerDeps, j as routerRunningPid, k as routerLogFile, l as runMessenger, s as finishDetached, u as startDetached, w as pinNotices, x as transcriptUsage, y as priceTableText } from "../run-CAjfKBQV.mjs";
44
+ import { C as readRunLog, D as resumeState, E as requestPlanStop, F as runLogPath, I as PlanTracker, M as dirtyConflicts, O as runExitCode, Ot as runPaneExec, P as loadPlan, S as planStopPath, T as renderStatus, Y as readRunLock, ht as resolveHostSession, j as PlanError, k as runPlan, l as PlanReporter, nt as closePaneForWorker, ot as inVisiblePane, q as planLockPath, rt as closeSelfPane, u as QueueReporter, vt as writePaneTitle, w as renderSchedule, x as planStatus, y as blockedMessage } from "../controls-ByrcupcA.mjs";
45
+ import "../endreason-BjPom527.mjs";
46
+ import { B as userRuleDirs, H as maskSecrets, J as psTable, L as listRules, N as endBuildWait, P as claudeSessionTranscript, R as loadRules, U as loadBuildsConfig, V as scanTranscript, j as beginBuildWait, z as projectRuleDirs } from "../render-CbifCwTb.mjs";
47
+ import "../operator-lRGvYr3D.mjs";
48
+ import "../kill-tree-DTmiEb3T.mjs";
49
+ import { s as poolReloadLive } from "../pool-cli-DOLgPgOM.mjs";
50
+ import "../chain-BvdKqRiZ.mjs";
51
+ import { _ as issueClaims, a as branchDiff, b as workerCommand, c as runQueue, d as loadSettings, f as move, g as issueClaim, h as renderReview, i as projectChecks, l as QueueStore, m as renderList, n as initProject, o as realQueueDeps, p as queueStatePath, r as isGitProject, s as acceptItems, t as formatCheck, u as again, v as issueStale } from "../project-setup-i5D0xkTn.mjs";
52
+ import { m as runInPane, r as closeFinishedPanes } from "../pane-audit-DUuilP1V.mjs";
53
+ import "../viewer-4BU8w_gK.mjs";
54
+ import { g as setWorkersEnabled, s as describeProviders } from "../providers-BC2Myo_O.mjs";
55
+ import { $ as exportDefaultLayout, B as mergeSettings, G as cachedRows, J as handleCockpit, K as cachedSessionMap, Q as warmCockpit, W as SystemMonitor, X as setEndpointHealth, Y as setActionHooks, Z as setRuntimeSampler, ct as providersCommand, et as createEndpointHealth, it as withWorkerAttribution, n as WORKER_CONFIG_COMMANDS, nt as loadWorkerWindows, q as cachedWorkerWindows, rt as sessionDisplayName, t as PROVIDER_EDIT_COMMANDS, tt as loadSessionMap, z as installWorkers } from "../worker-config-CdPmb4_2.mjs";
56
+ import { a as listConfigOp, i as getConfigValueOp, n as formatConfigGetOutput, o as setConfigValueOp, r as formatConfigSource, s as unsetConfigValueOp, t as MainConfigOpsError } from "../main-config-ops-C_fkINDv.mjs";
57
+ import { H as acquireRun, U as readRun, V as cockpitProbeSettings, k as readRuntimeCommands } from "../cockpit-actions-BgdKB9G3.mjs";
58
58
  import { n as PaiClient } from "../ipc-client-CmagIFLh.mjs";
59
- import { a as EMBED_PASS_BATCH_SIZE, c as liveYieldCheck, n as DEFAULT_EMBED_MAX_LOAD, o as formatEmbedStatus, r as DEFAULT_EMBED_MAX_MINUTES, s as lastRecordedEmbedPass } from "../embed-pass-CN1D8MXl.mjs";
60
- import { a as liveWorkersConfigShadows, i as totalUsageTokens, r as parseSessionUsage } from "../session-usage-CCmPFFa6.mjs";
61
- import "../fallback-CwPSCrX8.mjs";
62
- import { $t as readBodyFile, At as jobPaths, Ct as historyDir, D as migrateWorkQueue, Et as obsidianEnabled, Ft as sessionKeepaliveLedgerSummary, Gt as resolveDaemonPid, Ht as writeQuiet, Lt as describeQuiet, M as migrateSummaryCooldowns, Nt as loadSessionKeepaliveState, Qt as findNotesDir$1, Rt as nextOccurrence, Ut as LAUNCHD_LABEL, Xt as applyContinue, Yt as appendCheckpointToNote, Zt as findLatestNote, c as proposeFromTranscript, en as restartRouter, g as migrateKgBackfillState, h as backfillKgFromNotes, i as getLesson, jt as reapJob, kt as migrateIdentityFile, l as setState, n as LESSON_STATES, o as listLessons, p as reexecBackground, qt as readContextHandoverCache, r as addLesson, s as promoteLesson, t as LESSON_KINDS, wt as OBSIDIAN_DISABLED_MESSAGE, zt as readQuiet } from "../lessons-CFVU0cwA.mjs";
59
+ import { a as EMBED_PASS_BATCH_SIZE, c as liveYieldCheck, n as DEFAULT_EMBED_MAX_LOAD, o as formatEmbedStatus, r as DEFAULT_EMBED_MAX_MINUTES, s as lastRecordedEmbedPass } from "../embed-pass-DdTMn4DH.mjs";
60
+ import { a as liveWorkersConfigShadows, i as totalUsageTokens, r as parseSessionUsage } from "../session-usage-BRIWFYPS.mjs";
61
+ import "../fallback-CQ8_CuVu.mjs";
62
+ import { $t as readBodyFile, At as jobPaths, Ct as historyDir, D as migrateWorkQueue, Et as obsidianEnabled, Ft as sessionKeepaliveLedgerSummary, Gt as resolveDaemonPid, Ht as writeQuiet, Lt as describeQuiet, M as migrateSummaryCooldowns, Nt as loadSessionKeepaliveState, Qt as findNotesDir$1, Rt as nextOccurrence, Ut as LAUNCHD_LABEL, Xt as applyContinue, Yt as appendCheckpointToNote, Zt as findLatestNote, c as proposeFromTranscript, en as restartRouter, g as migrateKgBackfillState, h as backfillKgFromNotes, i as getLesson, jt as reapJob, kt as migrateIdentityFile, l as setState, n as LESSON_STATES, o as listLessons, p as reexecBackground, qt as readContextHandoverCache, r as addLesson, s as promoteLesson, t as LESSON_KINDS, wt as OBSIDIAN_DISABLED_MESSAGE, zt as readQuiet } from "../lessons-CdmqZD0G.mjs";
63
63
  import { n as queriesDirPath, t as migrateQueriesDir } from "../query-feedback-BWl2HRwN.mjs";
64
64
  import { appendFileSync, chmodSync, closeSync, copyFileSync, cpSync, createReadStream, createWriteStream, existsSync, fstatSync, lstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, readlinkSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, symlinkSync, unlinkSync, writeFileSync } from "node:fs";
65
65
  import { createHash, randomUUID } from "node:crypto";
@@ -830,7 +830,7 @@ function routerSamplerDeps(sched, engineStatusTimeoutMs = () => DEFAULT_RUNTIME_
830
830
  });
831
831
  return {
832
832
  inventory: async () => {
833
- const { currentInventory } = await import("../model-inventory-BXv15B0d.mjs");
833
+ const { currentInventory } = await import("../model-inventory-BYNrSTaY.mjs");
834
834
  return currentInventory();
835
835
  },
836
836
  sched,
@@ -845,7 +845,7 @@ function routerSamplerDeps(sched, engineStatusTimeoutMs = () => DEFAULT_RUNTIME_
845
845
  }
846
846
  },
847
847
  async rssMb(port) {
848
- const { processTreeRssMb } = await import("../model-inventory-BXv15B0d.mjs");
848
+ const { processTreeRssMb } = await import("../model-inventory-BYNrSTaY.mjs");
849
849
  const pid = (await exec("lsof", [
850
850
  "-ti",
851
851
  `tcp:${port}`,
@@ -1214,9 +1214,9 @@ const runCommand = {
1214
1214
  sampler.start();
1215
1215
  setRuntimeSampler(sampler);
1216
1216
  setActionHooks({ runLocalJob: async (kind, tier) => {
1217
- const { startTier, stopAll } = await import("../worker-config-BmcJ9R0U.mjs");
1218
- const { readLocalConfig } = await import("../local-tiers-DSlIYvvm.mjs");
1219
- const { workersYamlPath } = await import("../workers-config-DwzrtdYu.mjs");
1217
+ const { startTier, stopAll } = await import("../worker-config-CfV2dgSb.mjs");
1218
+ const { readLocalConfig } = await import("../local-tiers-X_dQfI4Q.mjs");
1219
+ const { workersYamlPath } = await import("../workers-config-2VipVOYk.mjs");
1220
1220
  const cfg = readLocalConfig(workersYamlPath());
1221
1221
  if (kind === "off") return void await stopAll(cfg);
1222
1222
  const t = cfg.tiers[tier];
@@ -1593,7 +1593,7 @@ const modelsCommand = {
1593
1593
  if (words[0] === "add") {
1594
1594
  const source = words[1];
1595
1595
  if (!source) throw new Error("usage: pai models add <hf-id|path> [--name n] [--download] [--try]");
1596
- const { addModel } = await import("../models-add-5yXTyz3g.mjs");
1596
+ const { addModel } = await import("../models-add-Dc7VXmcu.mjs");
1597
1597
  const r = await addModel({
1598
1598
  source,
1599
1599
  name: typeof ctx.opts.name === "string" ? ctx.opts.name : void 0,
@@ -1608,7 +1608,7 @@ const modelsCommand = {
1608
1608
  if (op) {
1609
1609
  const runtime = words[1];
1610
1610
  if (!runtime) throw new Error(`usage: pai models ${op} <runtime> (configured: ${Object.keys(readRuntimeCommands()).join(", ") || "none"})`);
1611
- const { defaultDeps, runtimeStartStop } = await import("../cockpit-actions-C73mJAJ8.mjs");
1611
+ const { defaultDeps, runtimeStartStop } = await import("../cockpit-actions-DNl0rKfW.mjs");
1612
1612
  const r = await runtimeStartStop(runtime, op, defaultDeps(), { model: typeof ctx.opts.model === "string" ? ctx.opts.model : void 0 });
1613
1613
  process.stdout.write(r.message + "\n");
1614
1614
  if (!r.ok) process.exitCode = 1;
@@ -8969,7 +8969,7 @@ function cmdLogs(opts) {
8969
8969
  return 0;
8970
8970
  }
8971
8971
  async function daemonServeCmd() {
8972
- const { serve } = await import("../daemon-176qA79N.mjs");
8972
+ const { serve } = await import("../daemon-iymy18Ie.mjs");
8973
8973
  const { loadConfig: lc, ensureConfigDir } = await import("../config-DHgPx3ER.mjs");
8974
8974
  ensureConfigDir();
8975
8975
  await serve(lc());
@@ -18656,7 +18656,7 @@ async function cmdUnregister(slug, opts = {}) {
18656
18656
  * deprecated alias that forwards here with a stderr notice.
18657
18657
  */
18658
18658
  async function projectListCmd(opts) {
18659
- const { cmdMain } = await import("../main-resolver-BKwI0I6H.mjs");
18659
+ const { cmdMain } = await import("../main-resolver-CN_sfG1R.mjs");
18660
18660
  await cmdMain(void 0, void 0, opts);
18661
18661
  return 0;
18662
18662
  }
@@ -20079,7 +20079,7 @@ async function registryScanCmd(opts) {
20079
20079
  return 0;
20080
20080
  }
20081
20081
  if (opts.filterReport) {
20082
- const { reportUnregistrable } = await import("../registrable-BwFiqazy.mjs");
20082
+ const { reportUnregistrable } = await import("../registrable-Ct0DKNKS.mjs");
20083
20083
  const r = await reportUnregistrable(await getRegistryBackend());
20084
20084
  console.log(`Registry rows: ${r.total}`);
20085
20085
  console.log(` matching the registration filter: ${r.matching} (${r.matchingMissing} with a missing path)`);
@@ -24464,7 +24464,7 @@ function auditFiles(paths) {
24464
24464
  * markdown copy — run 11 measured both present on the same turn, so both are
24465
24465
  * counted.
24466
24466
  */
24467
- function parseLines(path) {
24467
+ function parseLines$1(path) {
24468
24468
  const lines = [];
24469
24469
  for (const raw of readFileSync(path, "utf8").split("\n")) {
24470
24470
  if (!raw.trim()) continue;
@@ -24538,7 +24538,7 @@ function apiContextOf(usage) {
24538
24538
  */
24539
24539
  function turnBreakdown(path, turn) {
24540
24540
  if (!existsSync(path)) return null;
24541
- const lines = parseLines(path);
24541
+ const lines = parseLines$1(path);
24542
24542
  const byUuid = /* @__PURE__ */ new Map();
24543
24543
  for (const l of lines) if (l.uuid) byUuid.set(l.uuid, l);
24544
24544
  const seen = /* @__PURE__ */ new Set();
@@ -24644,7 +24644,7 @@ function firstTurnBreakdown(path) {
24644
24644
  if (!existsSync(path)) return empty;
24645
24645
  const tb = turnBreakdown(path, 1);
24646
24646
  if (!tb) return empty;
24647
- const lines = parseLines(path);
24647
+ const lines = parseLines$1(path);
24648
24648
  const byUuid = /* @__PURE__ */ new Map();
24649
24649
  let firstIndex = -1;
24650
24650
  for (let i = 0; i < lines.length; i++) {
@@ -27012,7 +27012,7 @@ async function auditScanCmd(opts) {
27012
27012
  console.error(err(" No transcript found."));
27013
27013
  return 1;
27014
27014
  }
27015
- const { rules, errors } = loadRules(userRuleDirs(process.cwd()));
27015
+ const { rules, errors } = loadRules(userRuleDirs(process.cwd()), { projectDirs: projectRuleDirs(process.cwd()) });
27016
27016
  for (const e of errors) console.error(dim$1(`rule: ${e}`));
27017
27017
  const findings = await scanTranscript(target, rules);
27018
27018
  if (opts.json) {
@@ -27506,6 +27506,26 @@ const EDIT_TOOLS = new Set([
27506
27506
  const HOOK_MARKER = "# PAI-GIT-NOTES: managed by `pai git setup`";
27507
27507
  const NOTES_REF = "refs/notes/pai";
27508
27508
  const LOOKBACK_MS = 6 * 3600 * 1e3;
27509
+ const MAX_CAPTURE_BYTES = 8 * 1024 * 1024;
27510
+ const HOOK_BUDGET_MS = 500;
27511
+ /** A refusal `pai git setup` reports to the user as-is. */
27512
+ var GitNotesError = class extends Error {};
27513
+ /** Call `onLine` for each line of `file`, reading in chunks; stops early when it returns false. */
27514
+ function eachLine(file, onLine) {
27515
+ const fd = openSync(file, "r");
27516
+ try {
27517
+ const buf = Buffer.alloc(64 * 1024);
27518
+ let rest = "";
27519
+ for (let n = readSync(fd, buf, 0, buf.length, null); n > 0; n = readSync(fd, buf, 0, buf.length, null)) {
27520
+ const parts = (rest + buf.toString("utf8", 0, n)).split("\n");
27521
+ rest = parts.pop() ?? "";
27522
+ for (const l of parts) if (!onLine(l)) return;
27523
+ }
27524
+ if (rest) onLine(rest);
27525
+ } finally {
27526
+ closeSync(fd);
27527
+ }
27528
+ }
27509
27529
  const real = (p) => {
27510
27530
  try {
27511
27531
  return realpathSync(p);
@@ -27531,43 +27551,47 @@ function jsonlFiles(dir, sinceMs, out = []) {
27531
27551
  return out;
27532
27552
  }
27533
27553
  /** Sessions whose Edit/Write-style tool events (after `sinceMs`) touched any of `paths`. */
27534
- function sessionsTouching(paths, sinceMs, captureDir) {
27554
+ function sessionsTouching(paths, sinceMs, captureDir, deadline = Infinity) {
27535
27555
  const wanted = new Map(paths.map((p) => [real(p), p]));
27536
27556
  const bySession = /* @__PURE__ */ new Map();
27537
27557
  for (const file of jsonlFiles(captureDir, sinceMs)) {
27538
- let text;
27558
+ if (Date.now() > deadline) break;
27539
27559
  try {
27540
- text = readFileSync(file, "utf8");
27560
+ if (statSync(file).size > MAX_CAPTURE_BYTES) continue;
27541
27561
  } catch {
27542
27562
  continue;
27543
27563
  }
27544
- for (const line of text.split("\n")) {
27545
- if (!line.includes("file_path") && !line.includes("notebook_path")) continue;
27546
- let e;
27547
- try {
27548
- e = JSON.parse(line);
27549
- } catch {
27550
- continue;
27551
- }
27552
- const tool = e.tool ?? e.payload?.tool_name;
27553
- if (!EDIT_TOOLS.has(tool)) continue;
27554
- const ts = typeof e.timestamp === "number" ? e.timestamp : Date.parse(e.timestamp);
27555
- if (Number.isFinite(ts) && ts < sinceMs) continue;
27556
- const input = e.input ?? e.payload?.tool_input ?? {};
27557
- const fp = input.file_path ?? input.notebook_path;
27558
- const sessionId = e.session ?? e.session_id;
27559
- if (typeof fp !== "string" || typeof sessionId !== "string") continue;
27560
- const orig = wanted.get(real(fp));
27561
- if (!orig) continue;
27562
- const workerId = e.workerId ?? e.worker_id ?? e.env?.PAI_WORKER_ID ?? e.payload?.env?.PAI_WORKER_ID;
27563
- const cur = bySession.get(sessionId) ?? {
27564
- sessionId,
27565
- files: []
27566
- };
27567
- if (typeof workerId === "string" && !cur.workerId) cur.workerId = workerId;
27568
- if (!cur.files.includes(orig)) cur.files.push(orig);
27569
- bySession.set(sessionId, cur);
27570
- }
27564
+ try {
27565
+ eachLine(file, (line) => {
27566
+ if (Date.now() > deadline) return false;
27567
+ if (!line.includes("file_path") && !line.includes("notebook_path")) return true;
27568
+ let e;
27569
+ try {
27570
+ e = JSON.parse(line);
27571
+ } catch {
27572
+ return true;
27573
+ }
27574
+ const tool = e.tool ?? e.payload?.tool_name;
27575
+ if (!EDIT_TOOLS.has(tool)) return true;
27576
+ const ts = typeof e.timestamp === "number" ? e.timestamp : Date.parse(e.timestamp);
27577
+ if (Number.isFinite(ts) && ts < sinceMs) return true;
27578
+ const input = e.input ?? e.payload?.tool_input ?? {};
27579
+ const fp = input.file_path ?? input.notebook_path;
27580
+ const sessionId = e.session ?? e.session_id;
27581
+ if (typeof fp !== "string" || typeof sessionId !== "string") return true;
27582
+ const orig = wanted.get(real(fp));
27583
+ if (!orig) return true;
27584
+ const workerId = e.workerId ?? e.worker_id ?? e.env?.PAI_WORKER_ID ?? e.payload?.env?.PAI_WORKER_ID;
27585
+ const cur = bySession.get(sessionId) ?? {
27586
+ sessionId,
27587
+ files: []
27588
+ };
27589
+ if (typeof workerId === "string" && !cur.workerId) cur.workerId = workerId;
27590
+ if (!cur.files.includes(orig)) cur.files.push(orig);
27591
+ bySession.set(sessionId, cur);
27592
+ return true;
27593
+ });
27594
+ } catch {}
27571
27595
  }
27572
27596
  return [...bySession.values()];
27573
27597
  }
@@ -27621,6 +27645,7 @@ const gitOk = (repo, args) => {
27621
27645
  };
27622
27646
  /** The post-commit work: note the sessions that edited the files of HEAD. Never throws. */
27623
27647
  function postCommitHook(repo, captureDir, env = process.env, now = Date.now()) {
27648
+ const deadline = now + HOOK_BUDGET_MS;
27624
27649
  try {
27625
27650
  if (/rebase/.test(env.GIT_REFLOG_ACTION ?? "")) return false;
27626
27651
  if (gitOk(repo, [
@@ -27642,7 +27667,8 @@ function postCommitHook(repo, captureDir, env = process.env, now = Date.now()) {
27642
27667
  "--name-only",
27643
27668
  "-r",
27644
27669
  "HEAD"
27645
- ]).split("\n").filter(Boolean).map((f) => join(top, f)), now - LOOKBACK_MS, captureDir));
27670
+ ]).split("\n").filter(Boolean).map((f) => join(top, f)), now - LOOKBACK_MS, captureDir, deadline));
27671
+ if (Date.now() > deadline) return false;
27646
27672
  return text ? writeNote(repo, "HEAD", text) : false;
27647
27673
  } catch {
27648
27674
  return false;
@@ -27659,13 +27685,17 @@ function hookPath(repo) {
27659
27685
  /** Install the post-commit hook, chaining an existing foreign hook as post-commit.pre-pai. */
27660
27686
  function setupGitNotes(repo) {
27661
27687
  const hook = hookPath(repo);
27688
+ const gitDirs = ["--git-dir", "--git-common-dir"].map((a) => real(resolve(repo, git(repo, ["rev-parse", a]))));
27689
+ const hookDir = real(dirname(hook));
27690
+ if (!gitDirs.some((d) => hookDir === d || hookDir.startsWith(d + sep))) throw new GitNotesError(`core.hooksPath points outside .git (${hook}); refusing to write a hook there. Unset it or install the hook yourself`);
27662
27691
  const old = `${hook}.pre-pai`;
27663
27692
  let chained = existsSync(old);
27664
27693
  if (existsSync(hook) && !readFileSync(hook, "utf8").includes(HOOK_MARKER)) {
27694
+ if (existsSync(old)) throw new GitNotesError(`${old} already exists; refusing to overwrite it. Move it away and re-run`);
27665
27695
  renameSync(hook, old);
27666
27696
  chained = true;
27667
27697
  }
27668
- writeFileSync(hook, `#!/bin/sh\n${HOOK_MARKER}\n${chained ? "d=$(dirname \"$0\")\n[ -x \"$d/post-commit.pre-pai\" ] && \"$d/post-commit.pre-pai\" \"$@\"\n" : ""}pai git hook post-commit || true\n`);
27698
+ writeFileSync(hook, `#!/bin/sh\n${HOOK_MARKER}\n${chained ? "d=$(dirname \"$0\")\n[ -x \"$d/post-commit.pre-pai\" ] && \"$d/post-commit.pre-pai\" \"$@\"\n" : ""}( pai git hook post-commit >/dev/null 2>&1 & )\n`);
27669
27699
  chmodSync(hook, 493);
27670
27700
  git(repo, [
27671
27701
  "config",
@@ -27732,7 +27762,8 @@ const gitCommand = {
27732
27762
  const r = setupGitNotes(repoOrFail());
27733
27763
  process.stdout.write(`Installed ${r.hook}${r.chained ? " (existing hook chained)" : ""}\n`);
27734
27764
  return 0;
27735
- } catch {
27765
+ } catch (e) {
27766
+ if (e instanceof GitNotesError) throw new CliError(e.message, "Fix it and re-run pai git setup");
27736
27767
  throw new CliError("Not a git repository", "Run it inside a repository");
27737
27768
  }
27738
27769
  }
@@ -28106,33 +28137,60 @@ function sessionFiles(dir) {
28106
28137
  return [];
28107
28138
  }
28108
28139
  }
28140
+ const CHUNK = 64 * 1024;
28141
+ /** Parsed lines of `text`; the first and last may be cut by the chunk edge, so `partialFirst`/`partialLast` drop them. */
28142
+ function parseLines(text, partialFirst, partialLast) {
28143
+ const lines = text.split("\n");
28144
+ if (partialFirst) lines.shift();
28145
+ if (partialLast) lines.pop();
28146
+ const out = [];
28147
+ for (const raw of lines) {
28148
+ if (!raw.trim()) continue;
28149
+ try {
28150
+ out.push(JSON.parse(raw));
28151
+ } catch {}
28152
+ }
28153
+ return out;
28154
+ }
28155
+ /** The session of one transcript, reading only its first and last 64 KB; null when the file vanished. */
28109
28156
  function toSession$1(harness, file, dir) {
28110
28157
  const id = file.slice(0, -6);
28158
+ const path = join(dir, file);
28111
28159
  let startedAt;
28112
28160
  let updatedAt;
28113
28161
  let cwd;
28162
+ let mtime;
28114
28163
  try {
28115
- for (const raw of readFileSync(join(dir, file), "utf8").split("\n")) {
28116
- if (!raw.trim()) continue;
28117
- let obj;
28164
+ const size = statSync(path).size;
28165
+ mtime = new Date(statSync(path).mtimeMs).toISOString();
28166
+ try {
28167
+ const fd = openSync(path, "r");
28118
28168
  try {
28119
- obj = JSON.parse(raw);
28120
- } catch {
28121
- continue;
28122
- }
28123
- if (typeof obj.cwd === "string" && obj.cwd) cwd ??= obj.cwd;
28124
- if (typeof obj.timestamp === "string" && obj.timestamp) {
28125
- startedAt ??= obj.timestamp;
28126
- updatedAt = obj.timestamp;
28169
+ const read = (pos, len) => {
28170
+ const buf = Buffer.alloc(len);
28171
+ return buf.toString("utf8", 0, readSync(fd, buf, 0, len, pos));
28172
+ };
28173
+ const head = parseLines(read(0, Math.min(size, CHUNK)), false, size > CHUNK);
28174
+ for (const obj of head) {
28175
+ if (typeof obj.cwd === "string" && obj.cwd) cwd ??= obj.cwd;
28176
+ if (typeof obj.timestamp === "string" && obj.timestamp) startedAt ??= obj.timestamp;
28177
+ if (cwd && startedAt) break;
28178
+ }
28179
+ const from = Math.max(0, size - CHUNK);
28180
+ const tail = parseLines(read(from, size - from), from > 0, false);
28181
+ for (const obj of tail) if (typeof obj.timestamp === "string" && obj.timestamp) updatedAt = obj.timestamp;
28182
+ } finally {
28183
+ closeSync(fd);
28127
28184
  }
28128
- }
28129
- } catch {}
28130
- const mtime = new Date(statSync(join(dir, file)).mtimeMs).toISOString();
28185
+ } catch {}
28186
+ } catch {
28187
+ return null;
28188
+ }
28131
28189
  return {
28132
28190
  harness,
28133
28191
  id,
28134
28192
  cwd,
28135
- path: join(dir, file),
28193
+ path,
28136
28194
  startedAt,
28137
28195
  updatedAt: updatedAt ?? mtime
28138
28196
  };
@@ -28150,7 +28208,10 @@ const claudeCodeAdapter = {
28150
28208
  for (const d of dirs) {
28151
28209
  const dir = join(projectsDir, d);
28152
28210
  if (!existsSync(dir)) continue;
28153
- for (const f of sessionFiles(dir)) out.push(toSession$1(this.name, f, dir));
28211
+ for (const f of sessionFiles(dir)) {
28212
+ const sess = toSession$1(this.name, f, dir);
28213
+ if (sess) out.push(sess);
28214
+ }
28154
28215
  }
28155
28216
  const since = opts.sinceMs !== void 0 ? Date.now() - opts.sinceMs : void 0;
28156
28217
  return out.filter((s) => since === void 0 || Date.parse(s.updatedAt) >= since).sort((a, b) => Date.parse(b.updatedAt) - Date.parse(a.updatedAt));
@@ -28511,9 +28572,11 @@ function splitSegments(command) {
28511
28572
  * Order is fixed: the first block hit wins, else the first confirm hit, else
28512
28573
  * the first warn hit. Text inside quotes is not a command, so rules test the
28513
28574
  * content with quoted strings removed; rules marked `quoted: true` also test
28514
- * it with only the quote marks removed (as detectAttack did before);
28515
- * confirm rules additionally test per-segment, so a quoted `git push -f` in a
28516
- * commit message stays inert while a quoted `+main` refspec still counts.
28575
+ * it as written and with only the quote marks removed — every builtin block
28576
+ * rule whose payload can sit inside `bash -c "..."` is marked, and anchors on
28577
+ * command position so a message that merely mentions the payload stays
28578
+ * allowed. Confirm rules test per-segment, so a quoted `git push -f` in a commit
28579
+ * message stays inert while a quoted `+main` refspec still counts.
28517
28580
  */
28518
28581
  /** Quoted strings removed: text inside a commit message or echo is not a command. */
28519
28582
  function dropQuoted(segment) {
@@ -28532,7 +28595,7 @@ function ruleRegex(rule) {
28532
28595
  const cached = regexCache.get(key);
28533
28596
  if (cached) return cached;
28534
28597
  try {
28535
- const re = new RegExp(rule.match, rule.flags ?? "");
28598
+ const re = new RegExp(rule.match, (rule.flags ?? "").replace(/[gy]/g, ""));
28536
28599
  regexCache.set(key, re);
28537
28600
  return re;
28538
28601
  } catch {
@@ -28603,7 +28666,13 @@ function sequenceHit(rule, steps) {
28603
28666
  if (step.tool && !new RegExp(step.tool).test(tool ?? "Bash")) return false;
28604
28667
  if (step.match.includes("\\1") && prior.length) {
28605
28668
  const cap = prior[0][1];
28606
- if (!cap || !new RegExp(step.match.replace(/\\1/g, cap), step.flags ?? "").test(content)) return false;
28669
+ if (!cap) return false;
28670
+ const lit = cap.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
28671
+ try {
28672
+ if (!new RegExp(step.match.replace(/\\1/g, () => lit), step.flags ?? "").test(content)) return false;
28673
+ } catch {
28674
+ return false;
28675
+ }
28607
28676
  continue;
28608
28677
  }
28609
28678
  const re = stepRegex(step);
@@ -28659,11 +28728,12 @@ function lintRules(rules) {
28659
28728
  //#endregion
28660
28729
  //#region src/cli/commands/rules.ts
28661
28730
  function listCmd(json) {
28662
- const { rules, errors } = listRules(userRuleDirs(process.cwd()));
28731
+ const { rules, errors, ignored } = listRules(userRuleDirs(process.cwd()), { projectDirs: projectRuleDirs(process.cwd()) });
28663
28732
  if (json) {
28664
28733
  console.log(JSON.stringify({
28665
28734
  rules,
28666
- errors
28735
+ errors,
28736
+ ignored
28667
28737
  }, null, 2));
28668
28738
  return 0;
28669
28739
  }
@@ -28679,10 +28749,11 @@ function listCmd(json) {
28679
28749
  r.severity === "off" ? "off" : "on"
28680
28750
  ])));
28681
28751
  for (const e of errors) console.log(err(`load error: ${e}`));
28752
+ for (const i of ignored) console.log(warn$1(`ignored: ${i}`));
28682
28753
  return 0;
28683
28754
  }
28684
28755
  function lintCmd(json) {
28685
- const { rules, errors } = listRules(userRuleDirs(process.cwd()));
28756
+ const { rules, errors } = listRules(userRuleDirs(process.cwd()), { projectDirs: projectRuleDirs(process.cwd()) });
28686
28757
  const enabled = rules.filter((r) => r.severity !== "off");
28687
28758
  const lints = lintRules(enabled);
28688
28759
  const failed = lints.filter((l) => !l.ok);