@tekmidian/pai 1.0.3 → 1.0.5

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 (147) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/dist/{auto-route-B7Yu6Uam.mjs → auto-route-DUYr57rs.mjs} +2 -2
  3. package/dist/auto-route-DWYK_0i0.mjs +11 -0
  4. package/dist/budget-DX-VIWGf.mjs +15 -0
  5. package/dist/{caller-identity-yLFb7CKq.mjs → caller-identity-Bim8JT-D.mjs} +3 -3
  6. package/dist/{capacity-DEveQdFV.mjs → capacity-CsZMkVyg.mjs} +7 -4
  7. package/dist/{chain-7n9Gx56r.mjs → chain-Dzz6xcKH.mjs} +5 -5
  8. package/dist/cli/index.mjs +114 -208
  9. package/dist/{cockpit-actions-BBHeyEZI.mjs → cockpit-actions-BTA1njMO.mjs} +31 -25
  10. package/dist/{cockpit-actions-DR9X514g.mjs → cockpit-actions-BgsiNcUY.mjs} +18 -18
  11. package/dist/cockpit-memory-DIrNs4xr.mjs +20 -0
  12. package/dist/config/defaults/config.yaml +9 -0
  13. package/dist/{config-XpZWOYOG.mjs → config-CST2uq1v.mjs} +29 -4
  14. package/dist/{config-Bu1_vbY8.mjs → config-DYbyEe4-.mjs} +2 -2
  15. package/dist/{config-DtENJ6cL.mjs → config-Dv3t7xnT.mjs} +1 -1
  16. package/dist/config-h5qK3fst.mjs +4 -0
  17. package/dist/{controls-CPoeudou.mjs → controls-OiVVbe-f.mjs} +18 -16
  18. package/dist/daemon/index.mjs +38 -37
  19. package/dist/{daemon-DPAo6WTa.mjs → daemon-C1dycZ3W.mjs} +35 -29
  20. package/dist/daemon-ieo0lnpq.mjs +46 -0
  21. package/dist/daemon-mcp/index.mjs +35 -35
  22. package/dist/detect-C0ZBXqDL.mjs +10 -0
  23. package/dist/{detect-9CZNO0yf.mjs → detect-CHuxFrLy.mjs} +2 -2
  24. package/dist/{embed-pass-DIWjA68P.mjs → embed-pass-DtVF2fOV.mjs} +4 -4
  25. package/dist/{embedding-gate-Cnk4YCyX.mjs → embedding-gate-B98PK_wz.mjs} +2 -2
  26. package/dist/{embedding-gate-6rZrWRXa.mjs → embedding-gate-CTAk8STe.mjs} +2 -2
  27. package/dist/{endreason-C577xIQz.mjs → endreason-BqyyU7BH.mjs} +20 -6
  28. package/dist/{factory-DjAAsqr_.mjs → factory-BV0MQA3T.mjs} +4 -4
  29. package/dist/{factory-Bsib-qDG.mjs → factory-DeASMV7Z.mjs} +4 -4
  30. package/dist/{fallback-DFlItw1Z.mjs → fallback-Bj2cyVk_.mjs} +230 -8
  31. package/dist/{health-Dnym-qcT.mjs → health-kufVIf6i.mjs} +4 -4
  32. package/dist/{helpers-BD6V-p9w.mjs → helpers-CvbYEKoD.mjs} +2 -2
  33. package/dist/{helpers-CMGjy_0N.mjs → helpers-WV8tdQHM.mjs} +5 -5
  34. package/dist/hooks/block-sleep-poll.mjs +1 -1
  35. package/dist/hooks/capture-all-events.mjs +21 -2
  36. package/dist/hooks/capture-tool-output.mjs +21 -2
  37. package/dist/hooks/load-project-context.mjs +7 -7
  38. package/dist/hooks/local-model-hint.mjs +1 -1
  39. package/dist/hooks/route-agents-to-worker.mjs +1 -1
  40. package/dist/hooks/security-validator.mjs +2 -2
  41. package/dist/hooks/worker-edit-repair.mjs +2 -2
  42. package/dist/hooks/worker-guard.mjs +8 -8
  43. package/dist/hooks/worker-note.mjs +2 -2
  44. package/dist/hooks/worker-pool-host.mjs +158 -55
  45. package/dist/hooks/worker-proxy.mjs +1 -1
  46. package/dist/hooks/worker-status-line.mjs +50 -22
  47. package/dist/hooks/worker-supervision.mjs +1 -1
  48. package/dist/hooks/worker-tool-name-repair.mjs +2 -2
  49. package/dist/index.mjs +8 -8
  50. package/dist/{indexer-backend-Cll7le4P.mjs → indexer-backend-B2vtFl38.mjs} +37 -234
  51. package/dist/{ipc-client-CaiGJnSM.mjs → ipc-client-CnYEF31R.mjs} +1 -1
  52. package/dist/{ipc-client-ZRmDKd5Z.mjs → ipc-client-DN7EvoVo.mjs} +1 -1
  53. package/dist/kill-tree-CXZ0WfVf.mjs +10 -0
  54. package/dist/{kill-tree-EWYaEk5v.mjs → kill-tree-CcpsRLCZ.mjs} +7 -7
  55. package/dist/{launch-Jh5NVeNe.mjs → launch-DpQPZGsT.mjs} +3 -3
  56. package/dist/{launch-CXVlZjHt.mjs → launch-UPQBoW2q.mjs} +3 -3
  57. package/dist/{local-candidate-DLdwQt0s.mjs → local-candidate-Cp_bw4kK.mjs} +3 -3
  58. package/dist/{local-instances-ZeRkkuS5.mjs → local-instances-B-c-CxzP.mjs} +4 -4
  59. package/dist/{local-instances-DOxSgT_L.mjs → local-instances-bdCNNSsL.mjs} +2 -2
  60. package/dist/{local-tiers-BE4jGaMa.mjs → local-tiers-BtdEEe5n.mjs} +2 -2
  61. package/dist/{local-tiers-DNMI5W86.mjs → local-tiers-OBqAAfOg.mjs} +3 -3
  62. package/dist/{main-config-ops-BEMpuhDz.mjs → main-config-ops-BYsK3BxM.mjs} +3 -3
  63. package/dist/{main-resolver-3Ns1HPmS.mjs → main-resolver-CAC3xfZM.mjs} +17 -17
  64. package/dist/{model-inventory-BFVSNFT3.mjs → model-inventory-BuTpi9a6.mjs} +13 -13
  65. package/dist/{models-add-C1QIc1DA.mjs → models-add-CJx2YAwh.mjs} +37 -36
  66. package/dist/operator-Bpxq_WB5.mjs +7 -0
  67. package/dist/{operator-CyuB3aVw.mjs → operator-DrwWItVt.mjs} +2 -2
  68. package/dist/{pai-marker-BcZyJguM.mjs → pai-marker-DLKJ9Yr5.mjs} +2 -2
  69. package/dist/{pane-audit-DKQt71s4.mjs → pane-audit-wv9UkyCe.mjs} +27 -9
  70. package/dist/{paths-CFHTloSe.mjs → paths-DBd78I7Z.mjs} +3 -3
  71. package/dist/{paths-CHifubDh.mjs → paths-DS5VQKoR.mjs} +3 -3
  72. package/dist/{planner-BmFACdLa.mjs → planner-K0mFrCpL.mjs} +28 -28
  73. package/dist/{pool-Dh-q3iJi.mjs → pool-BZ94nFuq.mjs} +2 -2
  74. package/dist/{pool-cli-BggU8GRp.mjs → pool-cli-B1eKySeN.mjs} +5 -5
  75. package/dist/{pool-cli-DQ6OzRy2.mjs → pool-cli-BjYQDfx6.mjs} +6 -6
  76. package/dist/{postgres-C6ti4haA.mjs → postgres-C-T5OWer.mjs} +19 -9
  77. package/dist/{postgres-BdBNkL_l.mjs → postgres-CBHY5PIi.mjs} +3 -3
  78. package/dist/{project-setup-jvfONJTQ.mjs → project-setup-pIPHZaXf.mjs} +26 -246
  79. package/dist/{providers-CblTFrhz.mjs → providers-Dzx5GAUI.mjs} +6 -6
  80. package/dist/providers-QJzpaNhX.mjs +16 -0
  81. package/dist/{query-feedback-BRfPtqki.mjs → query-feedback-DN52N9C5.mjs} +1 -1
  82. package/dist/{registrable-DpyTtajg.mjs → registrable-CXBBpUcz.mjs} +4 -4
  83. package/dist/registrable-Drn8wIDO.mjs +9 -0
  84. package/dist/render-C4KR8qQ8.mjs +13 -0
  85. package/dist/{render-BYmQkuLd.mjs → render-Cz3BWIBO.mjs} +8 -8
  86. package/dist/root-Bfb1zgwE.mjs +36 -0
  87. package/dist/{root-Xglu0OPD.mjs → root-bG48WVpW.mjs} +10 -10
  88. package/dist/route-table-ZVMNBsy7.mjs +15 -0
  89. package/dist/{routing-BAAST9vT.mjs → routing-BlD_tKjW.mjs} +136 -18
  90. package/dist/{routing-CENt4HH1.mjs → routing-D27jxj9x.mjs} +13 -13
  91. package/dist/{run-CSC7mgPf.mjs → run-AZVwceiU.mjs} +49 -27
  92. package/dist/{scan-C_Y5W9py.mjs → scan-C3uotg_f.mjs} +5 -5
  93. package/dist/{scope-D-h6F6DN.mjs → scope-D8HK6vU7.mjs} +4 -4
  94. package/dist/{session-8iqQDkqb.mjs → session-BAfypQb9.mjs} +26 -26
  95. package/dist/session-BcnhepLZ.mjs +35 -0
  96. package/dist/{session-scan-W-gbwJHM.mjs → session-scan-BmnjSReu.mjs} +5 -5
  97. package/dist/session-scan-CqUQdCac.mjs +9 -0
  98. package/dist/session-usage-oycSdiD3.mjs +337 -0
  99. package/dist/{sources-ESUkZaWv.mjs → sources-CiE3rZek.mjs} +1 -1
  100. package/dist/{status-ggJ7lgVg.mjs → status-COtzewKV.mjs} +3 -3
  101. package/dist/{status-Dm4dYciN.mjs → status-D_SWmOlH.mjs} +4 -4
  102. package/dist/{tool-errors-CJWODvlo.mjs → tool-errors-B2LnIqR0.mjs} +6 -6
  103. package/dist/{tool-errors-7E13StWd.mjs → tool-errors-DXJ70-sr.mjs} +2 -2
  104. package/dist/{viewer-mDXUNHNy.mjs → viewer-BgGRqXfD.mjs} +14 -14
  105. package/dist/viewer-CbGN2Ri4.mjs +22 -0
  106. package/dist/{wait-ByV0OyMZ.mjs → wait-ChpHKJZV.mjs} +3 -3
  107. package/dist/worker-config-D1KVAMp4.mjs +42 -0
  108. package/dist/{worker-config-CJhEMk19.mjs → worker-config-DgdT0iTB.mjs} +443 -40
  109. package/dist/workers-config-BhZBrR-Q.mjs +4 -0
  110. package/dist/{worktree-CRs2gyg0.mjs → worktree-BY--Rgmy.mjs} +5 -5
  111. package/dist/{zettelkasten-B_rRRRvD.mjs → zettelkasten-BHVx5zj-.mjs} +4 -4
  112. package/dist/{zettelkasten-BzMm8REH.mjs → zettelkasten-LoH9RBiN.mjs} +2 -2
  113. package/docs/cockpit.md +1 -0
  114. package/docs/commands/README.md +1 -0
  115. package/docs/commands/config.md +20 -0
  116. package/gemini-extension.json +1 -1
  117. package/package.json +1 -1
  118. package/pai-plugin.json +1 -1
  119. package/plugins/context-preservation/plugin.json +1 -1
  120. package/plugins/core/plugin.json +1 -1
  121. package/plugins/creative/plugin.json +1 -1
  122. package/plugins/observability/plugin.json +1 -1
  123. package/plugins/productivity/plugin.json +1 -1
  124. package/plugins/semantic-search/plugin.json +1 -1
  125. package/plugins/ui/plugin.json +1 -1
  126. package/plugins/zettelkasten/plugin.json +1 -1
  127. package/src/hooks/ts/capture-all-events.ts +15 -3
  128. package/src/hooks/ts/lib/raw-capture.ts +7 -0
  129. package/src/hooks/ts/post-tool-use/capture-tool-output.ts +13 -3
  130. package/dist/auto-route-CjjQqU1o.mjs +0 -11
  131. package/dist/budget-Dod6rnA9.mjs +0 -15
  132. package/dist/cockpit-memory--dnShXBA.mjs +0 -20
  133. package/dist/config-Cxi-aBf4.mjs +0 -4
  134. package/dist/daemon-DKdBNKfa.mjs +0 -45
  135. package/dist/detect-D1ziFFfA.mjs +0 -10
  136. package/dist/kill-tree-BG7dRVtp.mjs +0 -10
  137. package/dist/operator-BTqvTIc8.mjs +0 -7
  138. package/dist/providers-BeDiVEb-.mjs +0 -16
  139. package/dist/registrable-BzH4TObg.mjs +0 -9
  140. package/dist/render-CoMvwMPs.mjs +0 -13
  141. package/dist/root-FtJsxYnm.mjs +0 -36
  142. package/dist/route-table-B7zpoypi.mjs +0 -15
  143. package/dist/session-BeqAbNPd.mjs +0 -35
  144. package/dist/session-scan-BJI_ZO8M.mjs +0 -9
  145. package/dist/viewer-CqozWW39.mjs +0 -22
  146. package/dist/worker-config-DESkIjMF.mjs +0 -41
  147. package/dist/workers-config-f8KrkY4L.mjs +0 -4
@@ -1,40 +1,43 @@
1
1
  import { _ as warn, c as ok, i as err, n as dim } from "./utils-J2b9y8PC.mjs";
2
2
  import { g as paiHomePath, h as paiHomeDir, l as claudeHomeDir, t as aibrokerHomeDir, u as claudeProjectsDir } from "./runtime-paths-WsO9sJFc.mjs";
3
- import { Et as parseLedger, G as inlineWorkersYamlKeys, J as parseBuiltinAnthropic, K as migrateWorkersToYaml, Q as relocateWorkersYaml, R as isLoopbackUrl, T as parseProvider, W as initWorkersYaml, Y as parseWorkersYamlDocument, c as WorkersConfigError, et as workersYamlLegacyNotice, ft as parseEntry, it as yamlProviderToRaw, j as readWorkersSection, lt as findTier, m as isLocalProvider, o as PROVIDER_TAGS, p as getProviderOrNative, q as needsWorkersYamlRelocation, t as ANTHROPIC_NATIVE, tt as workersYamlPath, wt as appendLedger, y as nativeAnthropicProvider, z as loopbackUrl } from "./config-XpZWOYOG.mjs";
4
- import { D as readJsonStrict, O as writeJsonAtomic, f as readMainConfigRaw, m as deepMergeConfig, n as CONFIG_FILE, o as expandHome, u as paiConfigFilePath, v as shippedDefaultsDir, y as shippedMainDefaults } from "./config-Bu1_vbY8.mjs";
5
- import { i as ledgerPath, t as WORKER_ID_RE, u as workersLogDir } from "./paths-CHifubDh.mjs";
6
- import { E as worktreesStatsCached, l as formatWorktreesStats } from "./worktree-CRs2gyg0.mjs";
7
- import { T as ownsPidCached, b as loadStatusesCached, g as isLive, v as loadStatus } from "./status-ggJ7lgVg.mjs";
8
- import { C as describeMcp, _ as readPoolMetrics, f as poolMetricsPath, h as poolSettings, i as bundleBuildStamp, l as poolHostProbe, o as poolCarry, u as poolHostStale, v as readPoolState, x as warmOrCold } from "./pool-Dh-q3iJi.mjs";
9
- import { a as ownerSessionName } from "./scope-D-h6F6DN.mjs";
10
- import { $t as findLocal, Bt as routeRows, E as budgetCache, Ft as flowText, Gn as isTimeOrdered, Gt as setRoute, Ht as servingChip, I as buildSpeed, Kn as markTimeOrdered, Kt as setSessionRoute, L as percentile, Mt as clearSessionRoute, Ot as isTailnetOrLocalName, Rt as resolveSessionArg, Tt as duplicateModelIds, Vt as routeText, W as currentInventory, Xn as usageLogFile, Xt as clearPolicy, Yn as splitBySessionKind, Yt as POLICY_MODES, _n as pickLocal, at as readInventoryInput, cn as getProfile, en as onBattery, gn as localTierOrder, in as writePolicy, it as readInventory, jt as applyPolicyToRoutes, kt as loopbackRefusal, mn as currentLocalStatus, nn as readPolicy, rn as routeRun, rt as processTreeRssMb, tn as parseDuration, un as readProfiles, vn as probeLoopback, zt as routeChoices } from "./routing-BAAST9vT.mjs";
11
- import { C as stopLines, T as tierButtons, _ as readLocalConfig, a as LocalTierError, c as fetchServedModels, f as listensOnPort, g as planStart, h as parseServers, l as fmtRss, m as parseLocalConfig, u as healthUrl, v as resolveModelPath, x as stopCommandFor } from "./local-tiers-BE4jGaMa.mjs";
12
- import { _ as buildSlots, a as buildsDir, g as waitReason, l as listBuildsSync, m as ticketKind, n as breakStaleMutex, x as testSlots } from "./caller-identity-yLFb7CKq.mjs";
3
+ import { B as isLoopbackUrl, Et as appendLedger, J as migrateWorkersToYaml, K as initWorkersYaml, M as readWorkersSection, Ot as parseLedger, T as parseProvider, V as loopbackUrl, X as parseBuiltinAnthropic, Y as needsWorkersYamlRelocation, Z as parseWorkersYamlDocument, c as WorkersConfigError, dt as findTier, et as relocateWorkersYaml, m as isLocalProvider, mt as parseEntry, nt as workersYamlLegacyNotice, o as PROVIDER_TAGS, ot as yamlProviderToRaw, p as getProviderOrNative, q as inlineWorkersYamlKeys, rt as workersYamlPath, t as ANTHROPIC_NATIVE, y as nativeAnthropicProvider } from "./config-CST2uq1v.mjs";
4
+ import { O as readJsonStrict, f as readMainConfigRaw, k as writeJsonAtomic, m as deepMergeConfig, n as CONFIG_FILE, o as expandHome, u as paiConfigFilePath, v as shippedDefaultsDir, w as readDualFormatConfigRaw, y as shippedMainDefaults } from "./config-DYbyEe4-.mjs";
5
+ import { i as ledgerPath, t as WORKER_ID_RE, u as workersLogDir } from "./paths-DS5VQKoR.mjs";
6
+ import { E as worktreesStatsCached, l as formatWorktreesStats } from "./worktree-BY--Rgmy.mjs";
7
+ import { T as ownsPidCached, b as loadStatusesCached, g as isLive, v as loadStatus } from "./status-COtzewKV.mjs";
8
+ import { C as describeMcp, _ as readPoolMetrics, f as poolMetricsPath, h as poolSettings, i as bundleBuildStamp, l as poolHostProbe, o as poolCarry, u as poolHostStale, v as readPoolState, x as warmOrCold } from "./pool-BZ94nFuq.mjs";
9
+ import { a as ownerSessionName } from "./scope-D8HK6vU7.mjs";
10
+ import { $n as usageLogFile, $t as clearPolicy, E as budgetCache, Ft as clearSessionRoute, Gt as servingChip, Ht as routeChoices, I as buildSpeed, Jn as isTimeOrdered, Jt as setRoute, L as percentile, Mt as loopbackRefusal, Pt as applyPolicyToRoutes, Qn as splitBySessionKind, Qt as POLICY_MODES, Rt as flowText, Tt as duplicateModelIds, Ut as routeRows, Vt as resolveSessionArg, W as currentInventory, Wt as routeText, Yn as markTimeOrdered, Yt as setSessionRoute, _n as currentLocalStatus, an as readPolicy, at as readInventoryInput, bn as pickLocal, dn as getProfile, in as parseDuration, it as readInventory, jt as isTailnetOrLocalName, nn as findLocal, on as routeRun, pn as readProfiles, rn as onBattery, rt as processTreeRssMb, sn as writePolicy, xn as probeLoopback, yn as localTierOrder } from "./routing-BlD_tKjW.mjs";
11
+ import { C as stopLines, T as tierButtons, _ as readLocalConfig, a as LocalTierError, c as fetchServedModels, f as listensOnPort, g as planStart, h as parseServers, l as fmtRss, m as parseLocalConfig, u as healthUrl, v as resolveModelPath, x as stopCommandFor } from "./local-tiers-BtdEEe5n.mjs";
12
+ import { _ as buildSlots, a as buildsDir, g as waitReason, l as listBuildsSync, m as ticketKind, n as breakStaleMutex, x as testSlots } from "./caller-identity-Bim8JT-D.mjs";
13
13
  import { f as sharedScheduler, o as readSchedFile, u as schedPlain } from "./scheduler-CtUyWJ3O.mjs";
14
- import { l as reorderQueue, o as providerCap, s as queueRows, u as reorderQueueTo } from "./capacity-DEveQdFV.mjs";
15
- import { a as instancesFromProcesses, d as reconcileInstances, i as instanceNumber, l as readInstances, p as writeInstances, r as instanceEngineKey, u as readLiveInstances } from "./local-instances-DOxSgT_L.mjs";
16
- import { i as localStatusLine, s as readLocalStatus } from "./local-candidate-DLdwQt0s.mjs";
14
+ import { l as reorderQueue, o as providerCap, s as queueRows, u as reorderQueueTo } from "./capacity-CsZMkVyg.mjs";
15
+ import { a as instancesFromProcesses, d as reconcileInstances, i as instanceNumber, l as readInstances, p as writeInstances, r as instanceEngineKey, u as readLiveInstances } from "./local-instances-bdCNNSsL.mjs";
16
+ import { i as localStatusLine, s as readLocalStatus } from "./local-candidate-Cp_bw4kK.mjs";
17
17
  import { t as LOCAL_PROBE_TIMEOUT_MS } from "./timeouts-1MLooEBB.mjs";
18
18
  import { n as OPT, t as CliError } from "./define-CjJsmq-6.mjs";
19
- import { c as resolveFromModule } from "./postgres-C6ti4haA.mjs";
20
- import { c as ensureProxyRunning, l as proxyPort, u as stopProxy } from "./launch-Jh5NVeNe.mjs";
21
- import { a as colorEnabled, f as renderTable, n as readBudget, o as makeStyle } from "./health-Dnym-qcT.mjs";
22
- import { H as testProvider, o as sessionWorkersLine } from "./run-CSC7mgPf.mjs";
23
- import { U as planRows, V as loadPlanStatuses, i as localIdleLine, n as markControlsHeld, s as readLocalIdle, t as clickrControlsArgv, yt as psTable } from "./controls-CPoeudou.mjs";
24
- import { n as diskBundleMtime, r as ensurePoolHost } from "./pool-cli-BggU8GRp.mjs";
25
- import { a as readAudit, d as loadPaneRunStatuses, f as paneRunRows } from "./pane-audit-DKQt71s4.mjs";
26
- import { b as useProvider, f as setClass, g as setWorkersEnabled, l as removeProvider, m as setProviderEnabled, p as setProviderCap, r as classTargetText, s as describeProviders, t as addProvider, v as unsetClass, y as updateProvider } from "./providers-CblTFrhz.mjs";
27
- import { A as cockpitMemoryPayload, B as cockpitLayout, N as liveMemoryDeps, O as embeddingRuntimeName, P as memoryJobProgress, S as runtimeJobProgress, V as cockpitProbeSettings, c as defaultDeps, g as readLabels, h as readCockpitJob, k as readRuntimeCommands, t as COCKPIT_ACTION_EVENT, v as runCockpitAction, x as runningRuntimeJobs } from "./cockpit-actions-BBHeyEZI.mjs";
28
- import { i as fallbackStatusText, n as fallbackOn, r as fallbackStatus, t as fallbackOff } from "./fallback-DFlItw1Z.mjs";
29
- import { appendFileSync, chmodSync, closeSync, copyFileSync, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
19
+ import { c as resolveFromModule } from "./postgres-C-T5OWer.mjs";
20
+ import { c as ensureProxyRunning, l as proxyPort, u as stopProxy } from "./launch-DpQPZGsT.mjs";
21
+ import { a as colorEnabled, f as renderTable, n as readBudget, o as makeStyle } from "./health-kufVIf6i.mjs";
22
+ import { H as testProvider, o as sessionWorkersLine } from "./run-AZVwceiU.mjs";
23
+ import { U as planRows, V as loadPlanStatuses, i as localIdleLine, n as markControlsHeld, s as readLocalIdle, t as clickrControlsArgv, yt as psTable } from "./controls-OiVVbe-f.mjs";
24
+ import { w as parseDenialText } from "./render-Cz3BWIBO.mjs";
25
+ import { n as diskBundleMtime, r as ensurePoolHost } from "./pool-cli-B1eKySeN.mjs";
26
+ import { a as readAudit, d as loadPaneRunStatuses, f as paneRunRows } from "./pane-audit-wv9UkyCe.mjs";
27
+ import { i as fallbackStatusText, n as fallbackOn, r as fallbackStatus, t as fallbackOff } from "./fallback-Bj2cyVk_.mjs";
28
+ import { b as useProvider, f as setClass, g as setWorkersEnabled, l as removeProvider, m as setProviderEnabled, p as setProviderCap, r as classTargetText, s as describeProviders, t as addProvider, v as unsetClass, y as updateProvider } from "./providers-Dzx5GAUI.mjs";
29
+ import { A as cockpitMemoryPayload, B as cockpitLayout, N as liveMemoryDeps, O as embeddingRuntimeName, P as memoryJobProgress, S as runtimeJobProgress, V as cockpitProbeSettings, c as defaultDeps, g as readLabels, h as readCockpitJob, k as readRuntimeCommands, t as COCKPIT_ACTION_EVENT, v as runCockpitAction, x as runningRuntimeJobs } from "./cockpit-actions-BTA1njMO.mjs";
30
+ import { n as isRealUserPrompt, s as workersConfigShadows, t as extractUserPromptText } from "./session-usage-oycSdiD3.mjs";
31
+ import { appendFileSync, chmodSync, closeSync, copyFileSync, createReadStream, existsSync, fstatSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, rmSync, rmdirSync, statSync, unlinkSync, writeFileSync } from "node:fs";
30
32
  import { createHash } from "node:crypto";
31
- import { basename, dirname, join, resolve } from "node:path";
33
+ import { basename, dirname, isAbsolute, join, normalize, relative, resolve } from "node:path";
32
34
  import chalk from "chalk";
33
35
  import { homedir, loadavg } from "node:os";
34
36
  import { execFile, execFileSync, spawn } from "node:child_process";
35
37
  import { fileURLToPath } from "node:url";
36
38
  import { LineCounter, isMap, isScalar, parse, parseDocument } from "yaml";
37
39
  import { connect, createServer } from "node:net";
40
+ import { createInterface } from "node:readline";
38
41
 
39
42
  //#region src/cli/commands/providers.ts
40
43
  /**
@@ -228,6 +231,37 @@ function pathFromMessage(msg) {
228
231
  text: m[2]
229
232
  };
230
233
  }
234
+ /** Shadowed/unused keys of `text` against config.yaml: unchanged ones warn, a new or changed one is refused (the effective value lives elsewhere). */
235
+ function shadowFindings(text, current, ctx, at) {
236
+ const out = {
237
+ errors: [],
238
+ warnings: []
239
+ };
240
+ const parse = (t) => {
241
+ const v = parseDocument(t, { uniqueKeys: false }).toJS() ?? {};
242
+ return typeof v === "object" && v !== null && !Array.isArray(v) ? v : {};
243
+ };
244
+ let main = {};
245
+ try {
246
+ main = readDualFormatConfigRaw(ctx.mainConfigPath ?? paiConfigFilePath());
247
+ } catch {}
248
+ const before = new Map(workersConfigShadows(main, parse(current)).filter((s) => s.file === "workers.yaml").map((s) => [s.key, JSON.stringify(s.value)]));
249
+ for (const s of workersConfigShadows(main, parse(text))) {
250
+ if (s.file !== "workers.yaml") continue;
251
+ const path = s.key.split(".");
252
+ if (before.get(s.key) === JSON.stringify(s.value)) out.warnings.push({
253
+ path: s.key,
254
+ line: at(path),
255
+ message: s.message
256
+ });
257
+ else out.errors.push({
258
+ path: s.key,
259
+ line: at(path),
260
+ message: `${s.message}; not saved here`
261
+ });
262
+ }
263
+ return out;
264
+ }
231
265
  /**
232
266
  * Validate registry YAML text. `current` (the text on disk) scopes the
233
267
  * port-in-use and removal checks to what the edit changes.
@@ -329,6 +363,8 @@ function validateRegistry(yamlText, ctx, current = "") {
329
363
  "model"
330
364
  ], `model file not found: ${t.model}`);
331
365
  }
366
+ const shadow = shadowFindings(yamlText, current, ctx, at);
367
+ errors.push(...shadow.errors);
332
368
  const running = (ctx.running?.() ?? []).filter((i) => i.state === "starting" || i.state === "ready");
333
369
  for (const name of Object.keys(before)) {
334
370
  if (tiers[name]) continue;
@@ -337,7 +373,10 @@ function validateRegistry(yamlText, ctx, current = "") {
337
373
  }
338
374
  const provNames = new Set(Object.keys(providers));
339
375
  for (const inst of running) if (inst.origin === "registered" && !provNames.has(inst.provider)) add(["providers"], `cannot remove provider "${inst.provider}": instance ${inst.id} is running`);
340
- return { errors };
376
+ return {
377
+ errors,
378
+ warnings: shadow.warnings
379
+ };
341
380
  }
342
381
  /**
343
382
  * Every providers.<name> entry carries an explicit `enabled:` so a search for `enabled: true` finds
@@ -416,7 +455,7 @@ function validateRequest(yamlText, baseHash, ctx) {
416
455
  }],
417
456
  diff: []
418
457
  };
419
- const { errors } = validateRegistry(yamlText, ctx, cur);
458
+ const { errors, warnings } = validateRegistry(yamlText, ctx, cur);
420
459
  let shown = yamlText;
421
460
  if (!errors.length) {
422
461
  if (ctx.explicitEnabled) shown = withExplicitEnabled(shown);
@@ -425,6 +464,7 @@ function validateRequest(yamlText, baseHash, ctx) {
425
464
  return {
426
465
  ok: errors.length === 0,
427
466
  errors,
467
+ warnings,
428
468
  diff: diffLines(cur, shown)
429
469
  };
430
470
  }
@@ -1469,6 +1509,7 @@ main.win .cbody>.tw{padding:6px 10px}.wt-auto>.sp{padding:6px 10px}
1469
1509
  .wc-svg{overflow:hidden}.wc-svg svg{display:block}.wc-leg{overflow:hidden;padding:0 10px}main.win .cbody:has(.wt-svg,.wc-svg){overflow:hidden}
1470
1510
  .wr{padding:6px 10px;min-width:0}.wr-top{display:flex;flex-wrap:wrap;gap:6px 10px;align-items:center}.wr-sel{flex:none}.wr .rtcls{font-size:11px}.wr-sess{margin-top:4px}.wr-sess .rtsess{display:flex;flex-wrap:wrap;gap:4px 8px;align-items:center;margin-left:12px}
1471
1511
  .wmd{padding:6px 10px;min-width:0}.wmd-top{display:flex;flex-wrap:wrap;gap:6px;align-items:center}.wmd-g{display:grid;grid-template-columns:repeat(auto-fit,minmax(130px,1fr));gap:6px 10px;margin-top:6px}.wmdt{font-size:11px;color:var(--dim)}.wmdv{font-size:18px}.wmds{font-size:11px}.wmd-n{margin-top:4px}.wmd-i .linst{margin-top:3px}.wmd-in{font:inherit;min-width:120px}.wmd-e .eprow{padding:2px 0}
1512
+ .wr-row[data-sess]{cursor:pointer}.sd{margin-top:8px;border-top:1px solid var(--bd,rgba(128,128,128,.3));padding-top:6px}.sd-h{display:flex;flex-wrap:wrap;gap:4px 10px;align-items:center}.sd-h a{text-decoration:none}.sd-h a.on{font-weight:600;text-decoration:underline}.sd-x{margin-left:auto}
1472
1513
  ${winSelectCss()}
1473
1514
  ${winGridCss()}
1474
1515
  `;
@@ -4177,11 +4218,25 @@ function wmdModelActs(id){
4177
4218
  run:function(){var m=wmdModel(id);runIt("more","local.scale",{target:m.tier,count:m.instances.length+1})}}
4178
4219
  ];
4179
4220
  }
4221
+ /** "parallel N" with -/+ for a provider that has a concurrency cap; over the server's slot count a warning tooltip. */
4222
+ function wmdParallel(m){
4223
+ if(!m.maxConcurrent||!m.provider)return"";
4224
+ var over=m.slots&&m.maxConcurrent>m.slots,min=m.capMin||1,max=m.capMax||16;
4225
+ return' <span class="num wmd-par'+(over?" warn":"")+'"'+(over?' title="above the server\'s '+m.slots+' slots: extra runs queue at the server"':' title="runs the provider admits in parallel"')+'>parallel '+m.maxConcurrent+(m.slots?" / "+m.slots+" slots":"")+
4226
+ ' <button type="button" class="b wmd-par-b" data-p="'+esc(m.provider)+'" data-d="-1"'+(m.maxConcurrent<=min?" disabled":"")+' title="one parallel run fewer">\u2212</button>'+
4227
+ '<button type="button" class="b wmd-par-b" data-p="'+esc(m.provider)+'" data-d="1"'+(m.maxConcurrent>=max?" disabled":"")+' title="one parallel run more">+</button></span>';
4228
+ }
4180
4229
  Win.registerType("model",{minW:300,minH:90,defaultH:120,
4181
4230
  mount:function(ctx){
4182
4231
  ctx.body.innerHTML='<div class="wmd"><div class="wmd-top" data-k="badges"></div><div class="dim wmd-n" data-k="note"></div><div class="wmd-i" data-k="inst"></div></div>';
4183
4232
  ctx.body.addEventListener("click",function(ev){
4184
4233
  var b=ev.target;
4234
+ if(b&&b.classList&&b.classList.contains("wmd-par-b")){
4235
+ b.disabled=true;
4236
+ winHost().fetch("/cockpit/providers/"+encodeURIComponent(b.getAttribute("data-p"))+"/concurrency",{method:"POST",headers:{"content-type":"application/json"},body:JSON.stringify({delta:Number(b.getAttribute("data-d"))}),cache:"no-store"})
4237
+ .then(function(){if(typeof loadModels==="function")loadModels()},function(){b.disabled=false});
4238
+ return;
4239
+ }
4185
4240
  if(!b||!b.classList||!b.classList.contains("wmd-stop"))return;
4186
4241
  WinA.winClick(b,ctx.id,"local.stop",{target:b.getAttribute("data-id"),value:b.getAttribute("data-busy")!=="0"?"confirm":undefined},winHost());
4187
4242
  });
@@ -4190,7 +4245,7 @@ Win.registerType("model",{minW:300,minH:90,defaultH:120,
4190
4245
  var m=wmdModel(ctx.id);
4191
4246
  if(!m){ctx.status("stale","no longer reported");return}
4192
4247
  var n=m.instances.length;
4193
- ctx.html("badges",'<span class="badge">'+esc(m.engine)+'</span> <span class="badge mstate">'+esc(m.state)+'</span> '+(WMD&&WMD.inv&&WMD.inv.localDefaultTier===m.tier?'<span class="badge ok" title="the running model local work goes to (pai worker run --local)">local default</span> ':"")+'<span class="num" title="running instances / max instances">instances '+n+" / "+m.maxInstances+'</span> <span class="num" title="requests in flight / the provider maxConcurrent (none = no cap)">requests '+m.instances.reduce(function(a,x){return a+(x.inflight||0)},0)+(m.maxConcurrent?" / "+m.maxConcurrent:"")+"</span>");
4248
+ ctx.html("badges",'<span class="badge">'+esc(m.engine)+'</span> <span class="badge mstate">'+esc(m.state)+'</span> '+(WMD&&WMD.inv&&WMD.inv.localDefaultTier===m.tier?'<span class="badge ok" title="the running model local work goes to (pai worker run --local)">local default</span> ':"")+'<span class="num" title="running instances / max instances">instances '+n+" / "+m.maxInstances+'</span> <span class="num" title="requests in flight / the provider maxConcurrent (none = no cap)">requests '+m.instances.reduce(function(a,x){return a+(x.inflight||0)},0)+(m.maxConcurrent?" / "+m.maxConcurrent:"")+"</span>"+wmdParallel(m));
4194
4249
  ctx.html("note",(m.weightsBytes?'<span class="num" title="weight size on disk">'+gbm(m.weightsBytes/1048576)+" GB</span> · ":"")+'<span title="'+esc(m.file)+'">'+esc(String(m.file).replace(/^.*\//,""))+"</span> · :"+m.port);
4195
4250
  ctx.list("inst",m.instances,function(i){return i.id},function(){var d=document.createElement("div");d.className="linst";return d},function(d,i){
4196
4251
  var h='<span class="ok">'+esc(i.id)+'</span> <span class="dim">:'+i.port+(i.pid!=null?" · pid "+i.pid:"")+" · "+(i.inflight||0)+' in flight</span> <button type="button" class="b wmd-stop" data-act="local.stop" data-id="'+esc(i.id)+'" data-busy="'+(i.inflight||0)+'" title="stop instance '+esc(i.id)+' (asks to confirm when requests are in flight)">stop</button>';
@@ -5147,12 +5202,16 @@ WCHX.speed={
5147
5202
  resize:function(){}
5148
5203
  };
5149
5204
  function wtFit(ctx){fitTables(ctx.body)}
5150
- /** Row-level disclosures: a click on a fold or "+N more" row stores its state and re-feeds the page's data. */
5205
+ /** Row-level disclosures: a click on a fold or "+N more" row stores its state and re-feeds the page's data; a click on a session row opens its detail panel (SESS_OPEN), a tab or close button changes it. */
5151
5206
  function wtWire(ctx){
5152
5207
  ctx.body.addEventListener("click",function(e){
5153
- var t=e.target&&e.target.closest?e.target.closest("[data-wrfold],[data-sessmore]"):null;
5208
+ var t=e.target&&e.target.closest?e.target.closest("[data-wrfold],[data-sessmore],[data-sess],[data-sesstab],[data-sessclose]"):null;
5154
5209
  if(!t||!ctx.body.contains(t))return;
5155
5210
  e.preventDefault();
5211
+ var redraw=function(){Win.update("data",data)};
5212
+ if(t.hasAttribute("data-sess"))return sessDetailOpen(t.getAttribute("data-sess"),redraw);
5213
+ if(t.hasAttribute("data-sesstab")){SESS_TAB=t.getAttribute("data-sesstab");return redraw()}
5214
+ if(t.hasAttribute("data-sessclose")){SESS_OPEN=null;return redraw()}
5156
5215
  if(t.hasAttribute("data-wrfold")){var f=wrFolded(),k=t.getAttribute("data-wrfold");if(f[k])delete f[k];else f[k]=1;try{localStorage.setItem(WR_FOLD_KEY,JSON.stringify(f))}catch(x){}}
5157
5216
  else{try{localStorage.setItem(SESS_MORE_KEY,t.getAttribute("data-sessmore"))}catch(x){}}
5158
5217
  Win.update("data",data);
@@ -5493,7 +5552,7 @@ function runHead(timeLab){
5493
5552
  }
5494
5553
  function runRow(o){
5495
5554
  var pc=o.w>0?Math.max(2,Math.round(o.w/o.max*100)):0;
5496
- return'<div class="wr-row" title="'+esc(o.full)+'"><i class="wr-dot wr-'+o.st+'" title="'+esc(o.dotTitle)+'"></i><span class="wr-lab">'+esc(o.lab)+'</span><span class="badge" title="'+esc((o.models||[]).join(", ")||"no model")+'">'+esc(o.model)+'</span><span class="wr-bar" title="tokens: '+fmt(o.w)+'"><i style="width:'+pc+'%"></i></span><span class="wr-n">'+(o.w?fmt(o.w):"–")+'</span><span class="wr-du">'+o.du+'</span><span class="wr-hit '+hitCls(o.hit)+'" title="cache hit">'+(o.hit==null?"–":pct(o.hit))+'</span><span class="wr-fl">'+(o.extra||"")+'</span></div>'
5555
+ return'<div class="wr-row"'+(o.sid?' data-sess="'+esc(o.sid)+'"':'')+' title="'+esc(o.full)+'"><i class="wr-dot wr-'+o.st+'" title="'+esc(o.dotTitle)+'"></i><span class="wr-lab">'+esc(o.lab)+'</span><span class="badge" title="'+esc((o.models||[]).join(", ")||"no model")+'">'+esc(o.model)+'</span><span class="wr-bar" title="tokens: '+fmt(o.w)+'"><i style="width:'+pc+'%"></i></span><span class="wr-n">'+(o.w?fmt(o.w):"–")+'</span><span class="wr-du">'+o.du+'</span><span class="wr-hit '+hitCls(o.hit)+'" title="cache hit">'+(o.hit==null?"–":pct(o.hit))+'</span><span class="wr-fl">'+(o.extra||"")+'</span></div>'
5497
5556
  }
5498
5557
  /** Sessions by tokens: one runRow per session (dot: error red, worker verdict colour, active in the last 5 min blue, else dim), rows past the top N folded into one expandable row (state in localStorage like folds). */
5499
5558
  var SESS_MORE_KEY="pai.cockpit.sessmore";
@@ -5506,14 +5565,38 @@ function sessionsHtml(d){
5506
5565
  var lab=s.name||s.session.slice(0,8);
5507
5566
  var full=lab+" · "+s.session+(s.worker?" · worker "+s.worker+" · "+(s.verdict||"worker"):"")+"\n"+s.requests+" req · fresh in "+fmt(s.input+s.cacheWrite)+" · out "+fmt(s.output)+" · hit "+pct(s.hitRatio)+" · busts "+(s.busts||0)+" · errors "+(s.errors||0)+" · last "+ago(s.lastTs);
5508
5567
  var ex=(s.busts?'<span class="chip warn" title="cache busts">'+s.busts+'</span>':'')+(s.errors?'<span class="chip bad" title="errors">'+s.errors+'</span>':'');
5509
- return runRow({st:st,lab:lab,full:full,dotTitle:s.verdict||(recent?"active":"idle"),model:ms[0]||"–",models:ms,w:t,max:max,du:ago(s.lastTs),hit:s.requests?s.hitRatio:null,extra:ex});
5568
+ return runRow({sid:s.session,st:st,lab:lab,full:full,dotTitle:s.verdict||(recent?"active":"idle"),model:ms[0]||"–",models:ms,w:t,max:max,du:ago(s.lastTs),hit:s.requests?s.hitRatio:null,extra:ex});
5510
5569
  }
5511
5570
  var shown=open?all:all.slice(0,top),rest=all.slice(top),h=shown.map(row).join("");
5512
5571
  if(rest.length){
5513
5572
  var rt=rest.reduce(function(a,s){return a+tot(s)},0);
5514
5573
  h+='<div class="wr-row wr-span"><a href="#" class="dim" data-sessmore="'+(open?"0":"1")+'">'+(open?"show fewer sessions":"+"+rest.length+" more sessions ("+fmt(rt)+" tokens)")+'</a></div>';
5515
5574
  }
5516
- return'<div class="wr-cq"><div class="wr-tbl">'+runHead("age")+'<div class="wr-group">'+h+'</div></div></div>';
5575
+ return'<div class="wr-cq"><div class="wr-tbl">'+runHead("age")+'<div class="wr-group">'+h+'</div></div></div>'+(typeof sessDetailHtml==="function"?sessDetailHtml():"");
5576
+ }
5577
+ /** Session drill-down state: the opened id, its tab and the fetched detail (survives the poll redraw; the panel is part of the sessions html). */
5578
+ var SESS_OPEN=null,SESS_TAB="timeline",SESS_DET=null;
5579
+ /** One tab of the opened session's detail, drawn with table(). */
5580
+ function sessDetailBody(d,tab){
5581
+ if(tab==="files")return table(["file","edits .n","~lines .n"],d.filesChanged.map(function(f){return[esc(f.path),f.edits,f.approxLinesChanged]}));
5582
+ if(tab==="skills")return table(["skill","time"],d.skills.map(function(k){return[esc(k.name),esc(ago(k.ts))]}));
5583
+ if(tab==="mcp")return table(["server","calls .n","failures .n"],d.mcp.map(function(m){return[esc(m.server),m.calls,m.failures]}));
5584
+ if(tab==="denials")return table(["time","tool","reason"],d.denials.map(function(x){return[esc(ago(x.ts)),esc(x.tool),esc(x.reason)]}));
5585
+ return table(["# .n","time","prompt","tools","edits","cmds .n"],d.turns.map(function(t){return[t.idx+1,esc(ago(t.ts)),esc(t.prompt),esc(t.tools.map(function(x){return x.name+"×"+x.count}).join(", ")),esc(t.edits.join(", ")),t.commands]}));
5586
+ }
5587
+ /** The detail panel under the sessions table: tabs Timeline / Files / Skills / MCP / Denials and a close button; empty when no session is open. */
5588
+ function sessDetailHtml(){
5589
+ if(!SESS_OPEN)return"";
5590
+ var d=SESS_DET&&SESS_DET.id===SESS_OPEN?SESS_DET:null,tabs=[["timeline","Timeline"],["files","Files"],["skills","Skills"],["mcp","MCP"],["denials","Denials"]];
5591
+ var head='<div class="sd-h"><b title="'+esc(SESS_OPEN)+'">'+esc(SESS_OPEN.slice(0,8))+'</b>'+tabs.map(function(t){return'<a href="#" data-sesstab="'+t[0]+'"'+(t[0]===SESS_TAB?' class="on"':'')+'>'+t[1]+(d&&t[0]!=="timeline"?" ("+(t[0]==="files"?d.filesChanged:t[0]==="skills"?d.skills:t[0]==="mcp"?d.mcp:d.denials).length+")":"")+'</a>'}).join("")+'<a href="#" class="dim sd-x" data-sessclose="1" title="close">close ✕</a></div>';
5592
+ var meta=d?'<div class="dim">'+esc(d.cwd)+(d.models.length?" · "+esc(d.models.join(", ")):"")+(d.turnCount>d.turns.length?" · last "+d.turns.length+" of "+d.turnCount+" turns":"")+'</div>':"";
5593
+ return'<div class="sd" data-sd="'+esc(SESS_OPEN)+'">'+head+meta+(d?sessDetailBody(d,SESS_TAB):'<span class="dim">'+(SESS_DET&&SESS_DET.error?esc(SESS_DET.error):"loading…")+'</span>')+'</div>';
5594
+ }
5595
+ /** Opens (or closes, on a second click) a session's detail and fetches it; the panel redraws with the sessions card. */
5596
+ function sessDetailOpen(id,redraw){
5597
+ if(SESS_OPEN===id){SESS_OPEN=null;redraw();return}
5598
+ SESS_OPEN=id;SESS_DET=null;redraw();
5599
+ fetch("/api/session/"+encodeURIComponent(id)+"/detail",{cache:"no-store"}).then(function(r){return r.json().then(function(j){if(!r.ok)throw new Error(j.error||"HTTP "+r.status);return j})}).then(function(j){if(SESS_OPEN===id){SESS_DET=j;redraw()}},function(e){if(SESS_OPEN===id){SESS_DET={id:id,error:String(e.message||e)};redraw()}});
5517
5600
  }
5518
5601
  /** Worker runs grouped under the spawning session: newest run first, groups by their newest run; weighted tokens per run on one scale shared by all rows. */
5519
5602
  function workerGroups(ws,W){
@@ -6491,6 +6574,264 @@ function selectorChoices(workers, endpoints) {
6491
6574
  ];
6492
6575
  }
6493
6576
 
6577
+ //#endregion
6578
+ //#region src/hooks/ts/lib/build-gate.ts
6579
+ /** Tiny reader for the two keys of builds.yaml: flow `[a, b]` or block `- a` lists. */
6580
+ function parseBuildsYaml(text) {
6581
+ const res = {
6582
+ doors: [],
6583
+ patterns: []
6584
+ };
6585
+ let key = null;
6586
+ const unq = (s) => s.trim().replace(/^(['"])(.*)\1$/, "$2");
6587
+ for (const raw of text.split("\n")) {
6588
+ const line = raw.replace(/(^|\s)#.*$/, "");
6589
+ if (!line.trim()) continue;
6590
+ const m = /^(doors|patterns)\s*:\s*(.*)$/.exec(line);
6591
+ if (m) {
6592
+ key = m[1];
6593
+ const rest = m[2].trim();
6594
+ if (rest.startsWith("[")) {
6595
+ res[key].push(...rest.replace(/^\[|\]$/g, "").split(",").map(unq).filter(Boolean));
6596
+ key = null;
6597
+ }
6598
+ continue;
6599
+ }
6600
+ const li = /^\s*-\s+(.*)$/.exec(line);
6601
+ if (li && key) res[key].push(unq(li[1]));
6602
+ else if (!/^\s/.test(line)) key = null;
6603
+ }
6604
+ return res;
6605
+ }
6606
+ /** The nearest `.pai/builds.yaml` at or above `cwd`. */
6607
+ function loadBuildsConfig(cwd) {
6608
+ let dir = resolve(cwd);
6609
+ for (;;) {
6610
+ const f = join(dir, ".pai", "builds.yaml");
6611
+ if (existsSync(f)) try {
6612
+ return {
6613
+ root: dir,
6614
+ ...parseBuildsYaml(readFileSync(f, "utf8"))
6615
+ };
6616
+ } catch {
6617
+ return null;
6618
+ }
6619
+ const up = dirname(dir);
6620
+ if (up === dir) return null;
6621
+ dir = up;
6622
+ }
6623
+ }
6624
+
6625
+ //#endregion
6626
+ //#region src/hooks/ts/lib/loop-guard.ts
6627
+ const LOOP_MAX_REPEATS = 4;
6628
+ /** Consecutive same-template read-only Bash calls without a worktree change after which the next one is denied (env PAI_LOOP_READ_STREAK overrides). */
6629
+ const LOOP_READ_STREAK = Number(process.env.PAI_LOOP_READ_STREAK) > 0 ? Number(process.env.PAI_LOOP_READ_STREAK) : 15;
6630
+ const 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).";
6631
+ const LOOP_DENY_REASON = `loop guard: you ran this command ${LOOP_MAX_REPEATS} times with the same result and nothing changed. Stop repeating it. ${SELF}`;
6632
+ /** Total polling time per command key after which a "still running" helper is treated as an ordinary repeat again. */
6633
+ const WAIT_CAP_MS = 45 * 6e4;
6634
+ /** Untracked files up to this size are hashed by content; larger ones by size + mtime. */
6635
+ const FP_FULL_READ_BYTES = 256 * 1024;
6636
+ /** Content bytes read per fingerprint across all untracked files; past it files are hashed by size + mtime. */
6637
+ const FP_TOTAL_BYTES = 4 * 1024 * 1024;
6638
+ const 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;
6639
+ const MASKED_LINE = "[line masked: looks like a secret]";
6640
+ /** Result text with lines that look like secrets replaced by a marker. */
6641
+ function maskSecrets(text) {
6642
+ return text.split("\n").map((l) => SECRET_LINE.test(l) ? MASKED_LINE : l).join("\n");
6643
+ }
6644
+
6645
+ //#endregion
6646
+ //#region src/router/session-detail.ts
6647
+ /**
6648
+ * session-detail.ts — one session's drill-down for the cockpit: turns, files
6649
+ * changed, skills, MCP calls and hook denials, read from the Claude Code
6650
+ * transcript (<projects dir>/<encoded cwd>/<session id>.jsonl) by streaming it
6651
+ * line by line. Prompt text is secret-masked.
6652
+ */
6653
+ /** Session ids the endpoint accepts: no path separators, no dots. */
6654
+ const SESSION_ID_RE = /^[A-Za-z0-9-]{8,64}$/;
6655
+ const PROMPT_CHARS = 300;
6656
+ /** The transcript file of a session id, or null. */
6657
+ function findTranscript(id, projectsDir = claudeProjectsDir()) {
6658
+ if (!SESSION_ID_RE.test(id) || !existsSync(projectsDir)) return null;
6659
+ let dirs = [];
6660
+ try {
6661
+ dirs = readdirSync(projectsDir);
6662
+ } catch {
6663
+ return null;
6664
+ }
6665
+ for (const d of dirs) {
6666
+ const f = join(projectsDir, d, `${id}.jsonl`);
6667
+ if (existsSync(f)) return f;
6668
+ }
6669
+ return null;
6670
+ }
6671
+ const lineCount = (s) => typeof s === "string" && s ? s.split("\n").length : 0;
6672
+ /** Text of a tool_result's content: a string or the text blocks joined. */
6673
+ function resultText(c) {
6674
+ if (typeof c === "string") return c;
6675
+ if (Array.isArray(c)) return c.map((b) => b && typeof b === "object" && typeof b.text === "string" ? b.text : "").join("\n");
6676
+ return "";
6677
+ }
6678
+ /** Lines written by one Edit / Write / MultiEdit input. */
6679
+ function changedLines(name, input) {
6680
+ if (name === "Write") return lineCount(input.content);
6681
+ if (name === "Edit") return lineCount(input.new_string);
6682
+ if (name === "MultiEdit" && Array.isArray(input.edits)) return input.edits.reduce((a, e) => a + lineCount(e?.new_string), 0);
6683
+ return 0;
6684
+ }
6685
+ /** Skill name a user line announces ("/name" command tag or "Launching skill: name"), or null. */
6686
+ function loadedSkill(text) {
6687
+ const cmd = text.match(/<command-name>\/?([^<\s]+)<\/command-name>/);
6688
+ if (cmd) return cmd[1];
6689
+ const l = text.match(/^Launching skill: (\S+)/);
6690
+ return l ? l[1] : null;
6691
+ }
6692
+ /** Streams the session's transcript into a SessionDetail; null when the id has no transcript. */
6693
+ async function sessionDetail(id, opts = {}) {
6694
+ const file = findTranscript(id, opts.projectsDir);
6695
+ if (!file) return null;
6696
+ const maxTurns = Math.max(1, opts.maxTurns ?? cockpitLayout().sessionDetailTurns);
6697
+ const out = {
6698
+ id,
6699
+ cwd: "",
6700
+ models: [],
6701
+ turns: [],
6702
+ turnCount: 0,
6703
+ filesChanged: [],
6704
+ skills: [],
6705
+ mcp: [],
6706
+ denials: []
6707
+ };
6708
+ const models = /* @__PURE__ */ new Set();
6709
+ const files = /* @__PURE__ */ new Map();
6710
+ const mcp = /* @__PURE__ */ new Map();
6711
+ const toolOf = /* @__PURE__ */ new Map();
6712
+ const mcpOf = /* @__PURE__ */ new Map();
6713
+ let cur = null;
6714
+ const close = () => {
6715
+ if (!cur) return;
6716
+ cur.turn.tools = [...cur.tools].map(([name, count]) => ({
6717
+ name,
6718
+ count
6719
+ }));
6720
+ cur.turn.edits = [...cur.edits];
6721
+ out.turns.push(cur.turn);
6722
+ if (out.turns.length > maxTurns) out.turns.shift();
6723
+ cur = null;
6724
+ };
6725
+ const rl = createInterface({
6726
+ input: createReadStream(file, { encoding: "utf8" }),
6727
+ crlfDelay: Infinity
6728
+ });
6729
+ for await (const raw of rl) {
6730
+ if (!raw) continue;
6731
+ let obj;
6732
+ try {
6733
+ obj = JSON.parse(raw);
6734
+ } catch {
6735
+ continue;
6736
+ }
6737
+ const ts = obj.timestamp ?? "";
6738
+ if (!out.cwd && typeof obj.cwd === "string") out.cwd = obj.cwd;
6739
+ const content = obj.message?.content;
6740
+ if (obj.type === "user") {
6741
+ if (isRealUserPrompt(obj)) {
6742
+ close();
6743
+ const text = extractUserPromptText(obj);
6744
+ const skill = loadedSkill(text);
6745
+ if (skill) out.skills.push({
6746
+ name: skill,
6747
+ ts
6748
+ });
6749
+ cur = {
6750
+ turn: {
6751
+ idx: out.turnCount++,
6752
+ ts,
6753
+ prompt: maskSecrets(text).slice(0, PROMPT_CHARS),
6754
+ tools: [],
6755
+ edits: [],
6756
+ commands: 0
6757
+ },
6758
+ tools: /* @__PURE__ */ new Map(),
6759
+ edits: /* @__PURE__ */ new Set()
6760
+ };
6761
+ continue;
6762
+ }
6763
+ const blocks = Array.isArray(content) ? content : [];
6764
+ for (const b of blocks) {
6765
+ if (b.type === "text" && typeof b.text === "string" && obj.isMeta) {
6766
+ const skill = loadedSkill(b.text);
6767
+ if (skill) out.skills.push({
6768
+ name: skill,
6769
+ ts
6770
+ });
6771
+ }
6772
+ if (b.type !== "tool_result") continue;
6773
+ const text = resultText(b.content);
6774
+ const server = b.tool_use_id ? mcpOf.get(b.tool_use_id) : void 0;
6775
+ if (server && b.is_error) mcp.get(server).failures++;
6776
+ const d = parseDenialText(text, b.tool_use_id && toolOf.get(b.tool_use_id) || "?");
6777
+ if (d) out.denials.push({
6778
+ ts,
6779
+ tool: d.tool,
6780
+ reason: maskSecrets(d.reason).slice(0, 200)
6781
+ });
6782
+ }
6783
+ continue;
6784
+ }
6785
+ if (obj.type !== "assistant") continue;
6786
+ if (obj.message?.model) models.add(obj.message.model);
6787
+ if (!Array.isArray(content)) continue;
6788
+ for (const b of content) {
6789
+ if (b.type !== "tool_use" || !b.name) continue;
6790
+ const input = b.input ?? {};
6791
+ if (b.id) toolOf.set(b.id, b.name);
6792
+ if (cur) cur.tools.set(b.name, (cur.tools.get(b.name) ?? 0) + 1);
6793
+ if (b.name === "Bash" && cur) cur.turn.commands++;
6794
+ if (b.name === "Skill" && typeof input.skill === "string") out.skills.push({
6795
+ name: input.skill,
6796
+ ts
6797
+ });
6798
+ if (b.name.startsWith("mcp__")) {
6799
+ const server = b.name.split("__")[1];
6800
+ if (server) {
6801
+ const m = mcp.get(server) ?? {
6802
+ calls: 0,
6803
+ failures: 0
6804
+ };
6805
+ m.calls++;
6806
+ mcp.set(server, m);
6807
+ if (b.id) mcpOf.set(b.id, server);
6808
+ }
6809
+ }
6810
+ if ((b.name === "Edit" || b.name === "Write" || b.name === "MultiEdit") && typeof input.file_path === "string") {
6811
+ const f = files.get(input.file_path) ?? {
6812
+ edits: 0,
6813
+ approxLinesChanged: 0
6814
+ };
6815
+ f.edits++;
6816
+ f.approxLinesChanged += changedLines(b.name, input);
6817
+ files.set(input.file_path, f);
6818
+ cur?.edits.add(input.file_path);
6819
+ }
6820
+ }
6821
+ }
6822
+ close();
6823
+ out.models = [...models];
6824
+ out.filesChanged = [...files].map(([path, f]) => ({
6825
+ path,
6826
+ ...f
6827
+ })).sort((a, b) => b.approxLinesChanged - a.approxLinesChanged);
6828
+ out.mcp = [...mcp].map(([server, m]) => ({
6829
+ server,
6830
+ ...m
6831
+ })).sort((a, b) => b.calls - a.calls);
6832
+ return out;
6833
+ }
6834
+
6494
6835
  //#endregion
6495
6836
  //#region src/router/cockpit-layout-default.ts
6496
6837
  /**
@@ -7335,7 +7676,20 @@ async function cockpitModelsPayload() {
7335
7676
  function registryModelsNow() {
7336
7677
  try {
7337
7678
  const providers = readWorkersSection().workers.providers;
7338
- return registryModels(readLocalConfig(workersYamlPath()), localInstanceRows(), weightsBytes, (t) => providers[t.provider]?.maxConcurrent);
7679
+ const { concurrencyMin, concurrencyMax } = cockpitLayout();
7680
+ const cfg = readLocalConfig(workersYamlPath());
7681
+ return registryModels(cfg, localInstanceRows(), weightsBytes, (t) => providers[t.provider]?.maxConcurrent).map((m) => {
7682
+ const provider = cfg.tiers[m.tier]?.provider;
7683
+ const p = provider ? providers[provider] : void 0;
7684
+ if (m.maxConcurrent === void 0 || !provider || !p) return m;
7685
+ return {
7686
+ ...m,
7687
+ provider,
7688
+ ...p.conversationSlots !== void 0 ? { slots: p.conversationSlots } : {},
7689
+ capMin: concurrencyMin,
7690
+ capMax: concurrencyMax
7691
+ };
7692
+ });
7339
7693
  } catch {
7340
7694
  return [];
7341
7695
  }
@@ -7855,7 +8209,8 @@ function cockpitBuildId() {
7855
8209
  */
7856
8210
  function handleCockpit(req, res, limits, readRows = cachedRows(), sessionMap = loadSessionMap, system, workerWindows = loadWorkerWindows, readPool = cachedPoolCarry(), readPoolPanel = sharedPoolPanel, queueLogDir = workersLogDir) {
7857
8211
  const url = new URL(req.url ?? "/", "http://localhost");
7858
- if (url.pathname !== "/cockpit" && !url.pathname.startsWith("/cockpit/")) return false;
8212
+ const detail = url.pathname.match(/^\/api\/session\/([^/]*)\/detail$/);
8213
+ if (!detail && url.pathname !== "/cockpit" && !url.pathname.startsWith("/cockpit/")) return false;
7859
8214
  const send = (status, type, body) => {
7860
8215
  res.writeHead(status, {
7861
8216
  "content-type": type,
@@ -7864,6 +8219,12 @@ function handleCockpit(req, res, limits, readRows = cachedRows(), sessionMap = l
7864
8219
  });
7865
8220
  res.end(body);
7866
8221
  };
8222
+ if (detail) {
8223
+ if (req.method !== "GET") return send(405, "text/plain", "GET only"), true;
8224
+ if (!SESSION_ID_RE.test(detail[1])) return send(400, "application/json", "{\"error\":\"invalid session id\"}"), true;
8225
+ sessionDetail(detail[1]).then((d) => d ? send(200, "application/json", JSON.stringify(d)) : send(404, "application/json", "{\"error\":\"no such session\"}"), (e) => send(500, "application/json", JSON.stringify({ error: e.message })));
8226
+ return true;
8227
+ }
7867
8228
  if (req.method === "POST" && (url.pathname === "/cockpit/queue/next" || url.pathname === "/cockpit/queue/front" || url.pathname === "/cockpit/queue/up" || url.pathname === "/cockpit/queue/move")) {
7868
8229
  if (!sameOriginAction(req)) return send(403, "application/json", JSON.stringify({
7869
8230
  ok: false,
@@ -7917,6 +8278,48 @@ function handleCockpit(req, res, limits, readRows = cachedRows(), sessionMap = l
7917
8278
  })));
7918
8279
  return true;
7919
8280
  }
8281
+ const concurrency = req.method === "POST" ? /^\/cockpit\/providers\/([^/]+)\/concurrency$/.exec(url.pathname) : null;
8282
+ if (concurrency) {
8283
+ if (!sameOriginAction(req)) return send(403, "application/json", JSON.stringify({
8284
+ ok: false,
8285
+ message: "cross-origin action refused"
8286
+ })), true;
8287
+ const name = decodeURIComponent(concurrency[1]);
8288
+ readJsonObject(readBody, req).then((b) => {
8289
+ const { delta } = b;
8290
+ if (delta !== 1 && delta !== -1) return send(400, "application/json", JSON.stringify({
8291
+ ok: false,
8292
+ message: "delta must be +1 or -1"
8293
+ }));
8294
+ try {
8295
+ const cur = readWorkersSection().workers.providers[name]?.maxConcurrent;
8296
+ if (cur === void 0) return send(404, "application/json", JSON.stringify({
8297
+ ok: false,
8298
+ message: `provider "${name}" has no concurrency cap`
8299
+ }));
8300
+ const { concurrencyMin, concurrencyMax } = cockpitLayout();
8301
+ const next = Math.min(concurrencyMax, Math.max(concurrencyMin, cur + delta));
8302
+ if (next !== cur) setProviderCap(name, next);
8303
+ send(200, "application/json", JSON.stringify({
8304
+ ok: true,
8305
+ provider: name,
8306
+ maxConcurrent: next,
8307
+ min: concurrencyMin,
8308
+ max: concurrencyMax,
8309
+ clamped: next !== cur + delta
8310
+ }));
8311
+ } catch (e) {
8312
+ send(409, "application/json", JSON.stringify({
8313
+ ok: false,
8314
+ message: e.message
8315
+ }));
8316
+ }
8317
+ }).catch((e) => send(bodyErrorStatus(e), "application/json", JSON.stringify({
8318
+ ok: false,
8319
+ message: e.message
8320
+ })));
8321
+ return true;
8322
+ }
7920
8323
  if (req.method === "POST" && url.pathname === "/cockpit/action") {
7921
8324
  if (!sameOriginAction(req)) return send(403, "application/json", JSON.stringify({
7922
8325
  ok: false,
@@ -10271,9 +10674,9 @@ async function stopInstance(cfg, target, opts = {}, deps = {}) {
10271
10674
  */
10272
10675
  async function cliInflight(cfg, deps = {}) {
10273
10676
  const [{ engineInflight }, { readSchedFile }, { instanceEngineKey }] = await Promise.all([
10274
- import("./cockpit-actions-DR9X514g.mjs"),
10677
+ import("./cockpit-actions-BgsiNcUY.mjs"),
10275
10678
  import("./scheduler-dmHXoRvm.mjs"),
10276
- import("./local-instances-ZeRkkuS5.mjs")
10679
+ import("./local-instances-B-c-CxzP.mjs")
10277
10680
  ]);
10278
10681
  const now = deps.now ?? Date.now();
10279
10682
  const snap = readSchedFile(deps.startDir ?? logDir(), now);
@@ -10691,7 +11094,7 @@ const workerPoolCommand = {
10691
11094
  async run(ctx) {
10692
11095
  try {
10693
11096
  const action = ctx.args.ACTION;
10694
- const { poolOn, poolOff, poolStatusText } = await import("./pool-cli-DQ6OzRy2.mjs");
11097
+ const { poolOn, poolOff, poolStatusText } = await import("./pool-cli-BjYQDfx6.mjs");
10695
11098
  if (action === void 0 || action === "status") return void out(await poolStatusText(logDir()));
10696
11099
  if (action === "on") return void (await poolOn(logDir())).forEach((l) => out(l));
10697
11100
  if (action === "off") return void (await poolOff(logDir())).forEach((l) => out(l));
@@ -10867,5 +11270,5 @@ const WORKER_CONFIG_COMMANDS = [
10867
11270
  ];
10868
11271
 
10869
11272
  //#endregion
10870
- export { exportDefaultLayout as $, workerMcpCommand as A, mergeSettings as B, workerBenchCommand as C, workerFallbackCommand as D, workerControlsCommand as E, workerProvidersCommand as F, cachedRows as G, canBind as H, workerProxyCommand as I, handleCockpit as J, cachedSessionMap as K, workerRolesCommand as L, workerOnCommand as M, workerPolicyCommand as N, workerInstallCommand as O, workerPoolCommand as P, warmCockpit as Q, workerRouteCommand as R, stopInstance as S, workerConfigCommand as T, sizeOnDiskGb as U, allocatePort as V, SystemMonitor as W, setEndpointHealth as X, setActionHooks as Y, setRuntimeSampler as Z, portOpen as _, collectEnv as a, defaultRegistryCtx as at, startTier as b, currentInstances as c, providersCommand as ct, isUp as d, createEndpointHealth as et, killInstance as f, portListeners as g, parseCostTier as h, cliInflight as i, withWorkerAttribution as it, workerOffCommand as j, workerLocalCommand as k, fail as l, listServers as m, WORKER_CONFIG_COMMANDS as n, loadWorkerWindows as nt, collectTags as o, hashText as ot, launchDetached as p, cachedWorkerWindows as q, buildClassTarget as r, sessionDisplayName as rt, controlsArgv as s, saveRegistry as st, PROVIDER_EDIT_COMMANDS as t, loadSessionMap as tt, healthOk as u, serverLine as v, workerClassesCommand as w, stopAll as x, startInstance as y, installWorkers as z };
10871
- //# sourceMappingURL=worker-config-CJhEMk19.mjs.map
11273
+ export { exportDefaultLayout as $, workerMcpCommand as A, mergeSettings as B, workerBenchCommand as C, workerFallbackCommand as D, workerControlsCommand as E, workerProvidersCommand as F, cachedRows as G, canBind as H, workerProxyCommand as I, handleCockpit as J, cachedSessionMap as K, workerRolesCommand as L, workerOnCommand as M, workerPolicyCommand as N, workerInstallCommand as O, workerPoolCommand as P, warmCockpit as Q, workerRouteCommand as R, stopInstance as S, workerConfigCommand as T, sizeOnDiskGb as U, allocatePort as V, SystemMonitor as W, setEndpointHealth as X, setActionHooks as Y, setRuntimeSampler as Z, portOpen as _, collectEnv as a, withWorkerAttribution as at, startTier as b, currentInstances as c, saveRegistry as ct, isUp as d, loadBuildsConfig as et, killInstance as f, portListeners as g, parseCostTier as h, cliInflight as i, sessionDisplayName as it, workerOffCommand as j, workerLocalCommand as k, fail as l, providersCommand as lt, listServers as m, WORKER_CONFIG_COMMANDS as n, loadSessionMap as nt, collectTags as o, defaultRegistryCtx as ot, launchDetached as p, cachedWorkerWindows as q, buildClassTarget as r, loadWorkerWindows as rt, controlsArgv as s, hashText as st, PROVIDER_EDIT_COMMANDS as t, createEndpointHealth as tt, healthOk as u, serverLine as v, workerClassesCommand as w, stopAll as x, startInstance as y, installWorkers as z };
11274
+ //# sourceMappingURL=worker-config-DgdT0iTB.mjs.map