@tekmidian/pai 1.0.0 → 1.0.2

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 (218) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/README.md +67 -5
  3. package/dist/aibroker-client-BxzeEHPF.mjs +3 -0
  4. package/dist/{aibroker-client-CXEYBzbf.mjs → aibroker-client-CQPGqLxL.mjs} +1 -1
  5. package/dist/atomic-file-BorMa4T3.mjs +21 -0
  6. package/dist/{auto-route-D5SXrMpB.mjs → auto-route-B4azPk4l.mjs} +3 -3
  7. package/dist/auto-route-BjoMHKyI.mjs +11 -0
  8. package/dist/budget-Dod6rnA9.mjs +15 -0
  9. package/dist/{caller-identity-CVTuiLSs.mjs → caller-identity-yLFb7CKq.mjs} +6 -5
  10. package/dist/{capacity-DaXrVj3J.mjs → capacity-DEveQdFV.mjs} +3 -3
  11. package/dist/{chain-BcQlIlEd.mjs → chain-D-yvET_y.mjs} +5 -5
  12. package/dist/cli/index.mjs +1621 -357
  13. package/dist/cockpit-actions-BWunx3rY.mjs +20 -0
  14. package/dist/{cockpit-actions-ODmt8yF9.mjs → cockpit-actions-C8GlTzts.mjs} +84 -42
  15. package/dist/cockpit-memory-vTlFWV7F.mjs +20 -0
  16. package/dist/{config-BSXKyeJ1.mjs → config-Bu1_vbY8.mjs} +42 -3
  17. package/dist/{config-B955yYmo.mjs → config-Cxi-aBf4.mjs} +2 -2
  18. package/dist/{config-TaWmdTLx.mjs → config-DtENJ6cL.mjs} +1 -1
  19. package/dist/{config-D5chi2LO.mjs → config-XpZWOYOG.mjs} +2 -2
  20. package/dist/{controls-BGkK_Bdi.mjs → controls-BcKFHeG1.mjs} +37 -22
  21. package/dist/daemon/index.mjs +43 -42
  22. package/dist/{daemon-CorGh6Ub.mjs → daemon-ColVHwGZ.mjs} +103 -55
  23. package/dist/daemon-N7WhYi6I.mjs +45 -0
  24. package/dist/daemon-mcp/index.mjs +40 -39
  25. package/dist/{define-DGFu-sCf.mjs → define-CjJsmq-6.mjs} +1 -1
  26. package/dist/{detect-C1d5cUkT.mjs → detect-9CZNO0yf.mjs} +2 -2
  27. package/dist/detect-D1ziFFfA.mjs +10 -0
  28. package/dist/{embed-pass-CeQD8kRE.mjs → embed-pass-DIWjA68P.mjs} +5 -5
  29. package/dist/{embedding-gate-BHuBsgHD.mjs → embedding-gate-6rZrWRXa.mjs} +5 -5
  30. package/dist/{embedding-gate-Z7CJSOJk.mjs → embedding-gate-Cnk4YCyX.mjs} +3 -3
  31. package/dist/{embeddings-D4t6L-EH.mjs → embeddings-BVq3esBF.mjs} +1 -1
  32. package/dist/{embeddings-OF9Pt4by.mjs → embeddings-CIkJBKd-.mjs} +1 -1
  33. package/dist/{endreason-x1KOSrcO.mjs → endreason-C577xIQz.mjs} +7 -6
  34. package/dist/{env-DArqGq-Z.mjs → env-BE8mrsxr.mjs} +1 -1
  35. package/dist/factory-Bsib-qDG.mjs +9 -0
  36. package/dist/{factory-BtjbQ0np.mjs → factory-DjAAsqr_.mjs} +15 -13
  37. package/dist/{fallback-BIyEpPsQ.mjs → fallback-DFlItw1Z.mjs} +5 -5
  38. package/dist/{fmt-age-BiSHrTKN.mjs → fmt-age-ByDkvkoU.mjs} +1 -1
  39. package/dist/{health-C6jZWvRG.mjs → health-Dnym-qcT.mjs} +4 -4
  40. package/dist/{helpers-DFmYRCOa.mjs → helpers-BD6V-p9w.mjs} +2 -2
  41. package/dist/helpers-CMGjy_0N.mjs +10 -0
  42. package/dist/{helpers-CJpb_MNB.mjs → helpers-CRuBUas3.mjs} +87 -38
  43. package/dist/hooks/capture-all-events.mjs +52 -11
  44. package/dist/hooks/capture-session-summary.mjs +64 -47
  45. package/dist/hooks/capture-tool-output.mjs +49 -8
  46. package/dist/hooks/context-compression-hook.mjs +30 -10
  47. package/dist/hooks/initialize-session.mjs +1 -0
  48. package/dist/hooks/load-core-context.mjs +1 -1
  49. package/dist/hooks/load-project-context.mjs +32 -29
  50. package/dist/hooks/security-validator.mjs +45 -13
  51. package/dist/hooks/stop-hook.mjs +54 -16
  52. package/dist/hooks/supervision-banner.mjs +9 -0
  53. package/dist/hooks/sync-todo-to-md.mjs +147 -113
  54. package/dist/hooks/worker-edit-repair.mjs +2 -1
  55. package/dist/hooks/worker-guard.mjs +40 -16
  56. package/dist/hooks/worker-note.mjs +12 -5
  57. package/dist/hooks/worker-path-repair.mjs +1 -1
  58. package/dist/hooks/worker-pool-host.mjs +214 -116
  59. package/dist/hooks/worker-status-line.mjs +195 -114
  60. package/dist/index.d.mts +18 -0
  61. package/dist/index.mjs +12 -12
  62. package/dist/{indexer-backend-BM2CUSu8.mjs → indexer-backend-_a6UNhXJ.mjs} +149 -96
  63. package/dist/{ipc-client-BMqWw_gv.mjs → ipc-client-CaiGJnSM.mjs} +1 -1
  64. package/dist/{ipc-client-YYDD6zzU.mjs → ipc-client-ZRmDKd5Z.mjs} +1 -1
  65. package/dist/kill-tree-BG7dRVtp.mjs +10 -0
  66. package/dist/{kill-tree-BjYz5BxK.mjs → kill-tree-EWYaEk5v.mjs} +8 -8
  67. package/dist/{launch-CLp0OJxV.mjs → launch-CXVlZjHt.mjs} +8 -8
  68. package/dist/{launch-DgqQdAjI.mjs → launch-Jh5NVeNe.mjs} +3 -3
  69. package/dist/local-candidate-DLdwQt0s.mjs +112 -0
  70. package/dist/local-instances-DOxSgT_L.mjs +210 -0
  71. package/dist/local-instances-ZeRkkuS5.mjs +6 -0
  72. package/dist/{local-tiers-DPZYqv9m.mjs → local-tiers-BE4jGaMa.mjs} +2 -2
  73. package/dist/{local-tiers-DnBIAkbK.mjs → local-tiers-DNMI5W86.mjs} +3 -3
  74. package/dist/{main-config-ops-C0SflOWk.mjs → main-config-ops-BEMpuhDz.mjs} +3 -3
  75. package/dist/{main-resolver-DVPpSWVy.mjs → main-resolver-3Ns1HPmS.mjs} +18 -17
  76. package/dist/{migrate-BUJHadA8.mjs → migrate-DrA_OwlZ.mjs} +45 -14
  77. package/dist/min-max-DrSRUaWQ.mjs +16 -0
  78. package/dist/{model-inventory-Dasber3S.mjs → model-inventory-BFVSNFT3.mjs} +13 -12
  79. package/dist/{models-add-Bt7aUHDs.mjs → models-add-BtB3Se6f.mjs} +39 -38
  80. package/dist/operator-BTqvTIc8.mjs +7 -0
  81. package/dist/{operator-DZxcP-g8.mjs → operator-CyuB3aVw.mjs} +3 -3
  82. package/dist/{pai-marker-kIYuNt3c.mjs → pai-marker-DurzIbw8.mjs} +7 -6
  83. package/dist/{pane-audit-OGYrOAik.mjs → pane-audit-BQytYa60.mjs} +7 -7
  84. package/dist/{paths-DoRuFc60.mjs → paths-CFHTloSe.mjs} +3 -3
  85. package/dist/{paths-DoIyRnhx.mjs → paths-CHifubDh.mjs} +3 -3
  86. package/dist/{planner-DLGOYlVb.mjs → planner-BM27GBfC.mjs} +31 -30
  87. package/dist/{pool-CZ5MZaXg.mjs → pool-BRvoOkv6.mjs} +3 -3
  88. package/dist/{pool-cli-BxNSPzzY.mjs → pool-cli-B_YR8_Gl.mjs} +5 -5
  89. package/dist/{pool-cli-CbJfl37y.mjs → pool-cli-DkZTAlSW.mjs} +6 -6
  90. package/dist/postgres-BdBNkL_l.mjs +7 -0
  91. package/dist/{postgres-CDnd_k5f.mjs → postgres-C6ti4haA.mjs} +55 -34
  92. package/dist/{project-setup-DM4npnL3.mjs → project-setup-CfpApz5o.mjs} +131 -74
  93. package/dist/providers-BeDiVEb-.mjs +16 -0
  94. package/dist/{providers-UsKtLcUR.mjs → providers-CblTFrhz.mjs} +6 -6
  95. package/dist/{query-feedback-I-txSnld.mjs → query-feedback-BRfPtqki.mjs} +2 -2
  96. package/dist/registrable-C7b6givx.mjs +9 -0
  97. package/dist/{registrable-LrRIVYQc.mjs → registrable-Uzgmfyhz.mjs} +4 -4
  98. package/dist/render-Cc2j5QG9.mjs +13 -0
  99. package/dist/{render-BDbb4CF-.mjs → render-CwIrgxLi.mjs} +8 -8
  100. package/dist/{reranker-B4r4vykM.mjs → reranker-8g6xMwP7.mjs} +1 -1
  101. package/dist/{reranker-DxxMCtA0.mjs → reranker-CqCbpGnX.mjs} +1 -1
  102. package/dist/{root-BMeJuHOb.mjs → root-BWy0c2Lq.mjs} +11 -11
  103. package/dist/root-wC_6Fx0B.mjs +36 -0
  104. package/dist/route-table-B7zpoypi.mjs +15 -0
  105. package/dist/{router-L8Nu-OHF.mjs → router-CQSc3lk3.mjs} +17 -7
  106. package/dist/{router-D6Ec6Fid.mjs → router-DwHJRgG9.mjs} +1 -1
  107. package/dist/{routing-CUyiglfu.mjs → routing-BAAST9vT.mjs} +27 -308
  108. package/dist/{routing-ZuGlc0ge.mjs → routing-CENt4HH1.mjs} +13 -12
  109. package/dist/{run-ulAi5dFD.mjs → run-6Q9kCPem.mjs} +35 -33
  110. package/dist/{scan-B7I0gPe-.mjs → scan-ZQWm-_se.mjs} +6 -6
  111. package/dist/{local-candidate-jOjTNlOL.mjs → scheduler-CtUyWJ3O.mjs} +7 -109
  112. package/dist/scheduler-dmHXoRvm.mjs +3 -0
  113. package/dist/{scope-D5VSQxe4.mjs → scope-D-h6F6DN.mjs} +4 -4
  114. package/dist/{search-CPoE0830.mjs → search-RSyeQqj1.mjs} +18 -18
  115. package/dist/session-Bok2PqRS.mjs +35 -0
  116. package/dist/{session-CNXF6DLP.mjs → session-DVUExUnX.mjs} +55 -31
  117. package/dist/session-scan-BJI_ZO8M.mjs +9 -0
  118. package/dist/{session-scan-BDLEc4w1.mjs → session-scan-W-gbwJHM.mjs} +6 -6
  119. package/dist/{sources-CjhUKKtO.mjs → sources-ESUkZaWv.mjs} +1 -1
  120. package/dist/{status-DYydKQUI.mjs → status-Dm4dYciN.mjs} +4 -4
  121. package/dist/{status-CvVi9cDf.mjs → status-ggJ7lgVg.mjs} +17 -9
  122. package/dist/{stop-words-SdSL1WKH.mjs → stop-words-DSEYQdNe.mjs} +1 -1
  123. package/dist/{test-isolation-CoDeOVXb.mjs → test-isolation-lqSmYxr0.mjs} +1 -1
  124. package/dist/{timeouts-OwEONmc8.mjs → timeouts-1MLooEBB.mjs} +1 -1
  125. package/dist/{tool-errors-AeRQuG3Y.mjs → tool-errors-7E13StWd.mjs} +4 -3
  126. package/dist/{tool-errors-R5E0fCgf.mjs → tool-errors-CJWODvlo.mjs} +6 -6
  127. package/dist/{viewer-DtWj5Vti.mjs → viewer-DcpJwGKE.mjs} +15 -15
  128. package/dist/viewer-MWBVJP3u.mjs +22 -0
  129. package/dist/{wait-BMUR-U-U.mjs → wait-ByV0OyMZ.mjs} +3 -3
  130. package/dist/{worker-config-BLqa1yiD.mjs → worker-config-BDYNxbYz.mjs} +294 -92
  131. package/dist/worker-config-gmAq_-rI.mjs +41 -0
  132. package/dist/{workers-config-DEI9lrV4.mjs → workers-config-f8KrkY4L.mjs} +2 -2
  133. package/dist/{worktree-zmRf556h.mjs → worktree-CrnOqTBW.mjs} +37 -7
  134. package/dist/{zettelkasten-nigq7fqs.mjs → zettelkasten-B_rRRRvD.mjs} +5 -5
  135. package/dist/{zettelkasten-Cr_Xj0mG.mjs → zettelkasten-BzMm8REH.mjs} +29 -19
  136. package/docs/README.md +2 -0
  137. package/docs/cockpit.md +10 -4
  138. package/docs/commands/README.md +4 -4
  139. package/docs/commands/backup.md +2 -0
  140. package/docs/commands/install.md +29 -4
  141. package/docs/commands/providers.md +1 -1
  142. package/docs/commands/restore.md +4 -0
  143. package/docs/commands/setup.md +29 -4
  144. package/docs/commands/worker.md +1 -1
  145. package/docs/config.md +2 -0
  146. package/docs/features.md +299 -0
  147. package/docs/images/architecture.drawio +51 -0
  148. package/docs/images/architecture.svg +3 -0
  149. package/docs/images/cockpit-01-system-tokens.jpg +0 -0
  150. package/docs/images/cockpit-02-totals-cache.jpg +0 -0
  151. package/docs/images/cockpit-03-local-servers-models-pool.jpg +0 -0
  152. package/docs/images/cockpit-04-workers-memory.jpg +0 -0
  153. package/docs/images/cockpit-05-performance.jpg +0 -0
  154. package/docs/images/cockpit-06-runs-speed-routing.jpg +0 -0
  155. package/docs/images/cockpit-07-settings-registry.jpg +0 -0
  156. package/docs/install/index.md +29 -0
  157. package/docs/three-tier-coding.md +1 -1
  158. package/gemini-extension.json +1 -1
  159. package/package.json +1 -5
  160. package/pai-plugin.json +1 -1
  161. package/plugins/context-preservation/plugin.json +1 -1
  162. package/plugins/core/plugin.json +1 -1
  163. package/plugins/core/skills/setup/SKILL.md +41 -9
  164. package/plugins/creative/plugin.json +1 -1
  165. package/plugins/observability/plugin.json +1 -1
  166. package/plugins/productivity/plugin.json +1 -1
  167. package/plugins/semantic-search/plugin.json +1 -1
  168. package/plugins/ui/plugin.json +1 -1
  169. package/plugins/zettelkasten/plugin.json +1 -1
  170. package/src/hooks/session-autosave.sh +8 -1
  171. package/src/hooks/session-stop.sh +8 -1
  172. package/src/hooks/ts/capture-all-events.ts +7 -12
  173. package/src/hooks/ts/lib/context-fill.ts +2 -1
  174. package/src/hooks/ts/lib/path-repair.ts +1 -1
  175. package/src/hooks/ts/lib/project-utils/notify.ts +1 -0
  176. package/src/hooks/ts/lib/project-utils/session-notes.ts +23 -6
  177. package/src/hooks/ts/lib/raw-capture.ts +36 -0
  178. package/src/hooks/ts/lib/session-summary.ts +129 -0
  179. package/src/hooks/ts/lib/todo-sync.ts +120 -0
  180. package/src/hooks/ts/lib/worker-git-guard.ts +1 -1
  181. package/src/hooks/ts/post-tool-use/capture-tool-output.ts +6 -10
  182. package/src/hooks/ts/post-tool-use/sync-todo-to-md.ts +5 -105
  183. package/src/hooks/ts/pre-compact/context-compression-hook.ts +1 -1
  184. package/src/hooks/ts/pre-tool-use/security-validator.ts +35 -14
  185. package/src/hooks/ts/session-end/capture-session-summary.ts +20 -128
  186. package/src/hooks/ts/session-start/load-core-context.ts +3 -3
  187. package/src/hooks/ts/session-start/load-project-context.ts +18 -22
  188. package/src/hooks/ts/stop/stop-hook.ts +13 -5
  189. package/src/hooks/ztk-auto.sh +7 -2
  190. package/dist/aibroker-client-JjE74jo0.mjs +0 -3
  191. package/dist/auto-route-BRk8NEFv.mjs +0 -11
  192. package/dist/budget-DuhQ2zzG.mjs +0 -14
  193. package/dist/cockpit-actions-DcQ-ucU8.mjs +0 -19
  194. package/dist/cockpit-memory-KV45PPO2.mjs +0 -19
  195. package/dist/daemon-C7yt_ptC.mjs +0 -44
  196. package/dist/detect-DRUkmHnb.mjs +0 -10
  197. package/dist/factory-DAGG9_n8.mjs +0 -9
  198. package/dist/helpers-DPJEHPq6.mjs +0 -10
  199. package/dist/kill-tree-LV0Q7Mte.mjs +0 -10
  200. package/dist/operator-CfL0HiBK.mjs +0 -7
  201. package/dist/postgres-DgqWyqhN.mjs +0 -7
  202. package/dist/providers-CTu2s1z2.mjs +0 -15
  203. package/dist/registrable-D9aNZOTh.mjs +0 -9
  204. package/dist/render-BSfVlYHj.mjs +0 -13
  205. package/dist/root-xI9DqVIe.mjs +0 -35
  206. package/dist/route-table-HjvnLVEU.mjs +0 -14
  207. package/dist/session-BJHzmUg2.mjs +0 -34
  208. package/dist/session-scan-YORKE1NO.mjs +0 -9
  209. package/dist/viewer-B8709jDN.mjs +0 -22
  210. package/dist/worker-config-D8tRuvo7.mjs +0 -40
  211. package/docs/images/cockpit-limits-routing.jpg +0 -0
  212. package/docs/images/cockpit-models.jpg +0 -0
  213. package/docs/images/cockpit-usage.jpg +0 -0
  214. package/docs/images/cockpit-workers-system.jpg +0 -0
  215. package/scripts/build-docs.mjs +0 -41
  216. package/scripts/build-hooks.mjs +0 -311
  217. package/scripts/build-skill-stubs.mjs +0 -216
  218. package/scripts/copy-defaults.mjs +0 -46
@@ -1,7 +1,6 @@
1
- import { L as isLoopbackHostname, tt as workersYamlPath } from "./config-D5chi2LO.mjs";
2
- import { _ as readLocalConfig } from "./local-tiers-DPZYqv9m.mjs";
3
- import { existsSync, mkdirSync, readFileSync, renameSync, writeFileSync } from "node:fs";
4
- import { dirname, join } from "node:path";
1
+ import { n as minOf } from "./min-max-DrSRUaWQ.mjs";
2
+ import { existsSync, readFileSync, renameSync, writeFileSync } from "node:fs";
3
+ import { join } from "node:path";
5
4
 
6
5
  //#region src/router/scheduler.ts
7
6
  /**
@@ -133,7 +132,7 @@ var RequestScheduler = class {
133
132
  if (eng.inflight) backlogged.add(eng.inflight.session);
134
133
  if (!backlogged.has(session)) {
135
134
  const others = [...backlogged].map((s) => ctr.get(s) ?? 0);
136
- const floor = others.length ? Math.min(...others) : 0;
135
+ const floor = others.length ? minOf(others) : 0;
137
136
  ctr.set(session, Math.max(ctr.get(session) ?? 0, floor));
138
137
  } else if (!ctr.has(session)) ctr.set(session, 0);
139
138
  const acct = this.acct(worker, session, engineName);
@@ -181,7 +180,7 @@ var RequestScheduler = class {
181
180
  let bestAt = Infinity;
182
181
  for (const s of sessions) {
183
182
  const c = ctr.get(s) ?? 0;
184
- const at = Math.min(...eng.waiting.filter((w) => w.session === s).map((w) => w.at));
183
+ const at = minOf(eng.waiting.filter((w) => w.session === s).map((w) => w.at));
185
184
  if (c < bestC || c === bestC && at < bestAt) {
186
185
  best = s;
187
186
  bestC = c;
@@ -390,106 +389,5 @@ function schedPlain(s, names) {
390
389
  }
391
390
 
392
391
  //#endregion
393
- //#region src/workers/local-status.ts
394
- /**
395
- * local-status.ts — the one authoritative answer to "which local model is
396
- * running?" (incident 2026-10-19: a session curled ports 8010/8011/8020, found
397
- * nothing, and went looking for how to start a model server while the running
398
- * one was never considered). The PAI daemon computes the answer every 30 s and
399
- * caches it in <logDir>/local-status.json; everything else only reads it:
400
- * `pai worker local`, the `local_status` MCP tool, resolveLocalProvider, the
401
- * prompt hint and the Bash guard. Readers fall back to a direct probe only
402
- * when the cache is missing or stale (daemon unreachable).
403
- */
404
- const LOCAL_STATUS_REFRESH_MS = 3e4;
405
- /** A cache older than this means the daemon is not refreshing it. */
406
- const LOCAL_STATUS_MAX_AGE_MS = 18e4;
407
- const localStatusPath = (logDir) => join(logDir, "local-status.json");
408
- const NO_SERVER_HINT = "do not start model servers";
409
- function localStatusLine(st) {
410
- if (st.running.length) return `local: ${st.running.map((r) => `${r.provider} (${r.model})`).join(", ")} running — use \`pai worker run --local\``;
411
- return `local: none running — local work is not available; ${NO_SERVER_HINT}`;
412
- }
413
- function writeLocalStatus(logDir, st) {
414
- const path = localStatusPath(logDir);
415
- mkdirSync(dirname(path), { recursive: true });
416
- const tmp = `${path}.${process.pid}.tmp`;
417
- writeFileSync(tmp, JSON.stringify(st) + "\n", "utf8");
418
- renameSync(tmp, path);
419
- }
420
- /** Like readLocalStatus, but says why there is no answer: missing, unparsable, stale (age) or bad shape. */
421
- function readLocalStatusWhy(logDir, now = Date.now(), maxAgeMs = LOCAL_STATUS_MAX_AGE_MS) {
422
- const path = localStatusPath(logDir);
423
- if (!existsSync(path)) return {
424
- status: null,
425
- reason: "status file missing"
426
- };
427
- let st;
428
- try {
429
- st = JSON.parse(readFileSync(path, "utf8"));
430
- } catch {
431
- return {
432
- status: null,
433
- reason: "status file unparsable"
434
- };
435
- }
436
- if (!st || typeof st !== "object") return {
437
- status: null,
438
- reason: "status file has a bad shape"
439
- };
440
- const raw = st.running;
441
- st.running = Array.isArray(raw) ? raw : raw && typeof raw === "object" ? [raw] : [];
442
- const at = Date.parse(st.at);
443
- if (Number.isNaN(at) || !Array.isArray(st.down) || !Array.isArray(st.disabled)) return {
444
- status: null,
445
- reason: "status file has a bad shape"
446
- };
447
- const age = now - at;
448
- if (age > maxAgeMs) return {
449
- status: null,
450
- reason: `status ${Math.round(age / 1e3)} s old (max ${Math.round(maxAgeMs / 1e3)} s)`
451
- };
452
- return { status: st };
453
- }
454
- /** The daemon's cached answer; null when absent, damaged or older than maxAgeMs. */
455
- function readLocalStatus(logDir, now = Date.now(), maxAgeMs = LOCAL_STATUS_MAX_AGE_MS) {
456
- return readLocalStatusWhy(logDir, now, maxAgeMs).status;
457
- }
458
- /** Text + JSON of the answer for the CLI and the MCP tool. */
459
- function localStatusReport(st) {
460
- const extra = (st.down.length ? ` down: ${st.down.join(", ")}.` : "") + (st.disabled.length ? ` disabled: ${st.disabled.join(", ")}.` : "");
461
- return {
462
- text: localStatusLine(st) + (extra ? `\n${extra.trim()}` : ""),
463
- json: st
464
- };
465
- }
466
-
467
- //#endregion
468
- //#region src/workers/local-candidate.ts
469
- /**
470
- * Providers a `local:` tier launches. `pai worker local <tier>` and the cockpit
471
- * start those without touching `enabled:`, so a running tier server is a
472
- * candidate for --local even when its provider entry is switched off.
473
- */
474
- function tierProviderNames(yamlPath = workersYamlPath()) {
475
- try {
476
- return Object.values(readLocalConfig(yamlPath).tiers).map((t) => t.provider);
477
- } catch {
478
- return [];
479
- }
480
- }
481
- function isLoopbackBaseUrl(url) {
482
- try {
483
- return isLoopbackHostname(new URL(url).hostname);
484
- } catch {
485
- return false;
486
- }
487
- }
488
- /** A loopback provider --local may run on: enabled, or launched by a tier. */
489
- function isLocalCandidate(p, name, tierProviders) {
490
- return (p.enabled || tierProviders.includes(name)) && isLoopbackBaseUrl(p.baseUrl);
491
- }
492
-
493
- //#endregion
494
- export { localStatusReport as a, mirrorTo as c, schedConfigFrom as d, schedEnabled as f, sharedScheduler as g, setSchedConfigSource as h, localStatusLine as i, newPrefill as l, schedPlain as m, tierProviderNames as n, readLocalStatus as o, schedLine as p, LOCAL_STATUS_REFRESH_MS as r, writeLocalStatus as s, isLocalCandidate as t, readSchedFile as u };
495
- //# sourceMappingURL=local-candidate-jOjTNlOL.mjs.map
392
+ export { newPrefill as a, schedEnabled as c, setSchedConfigSource as d, sharedScheduler as f, mirrorTo as i, schedLine as l, RequestScheduler as n, readSchedFile as o, SCHED_FILE as r, schedConfigFrom as s, DEFAULT_SCHED as t, schedPlain as u };
393
+ //# sourceMappingURL=scheduler-CtUyWJ3O.mjs.map
@@ -0,0 +1,3 @@
1
+ import { a as newPrefill, c as schedEnabled, d as setSchedConfigSource, f as sharedScheduler, i as mirrorTo, l as schedLine, n as RequestScheduler, o as readSchedFile, r as SCHED_FILE, s as schedConfigFrom, t as DEFAULT_SCHED, u as schedPlain } from "./scheduler-CtUyWJ3O.mjs";
2
+
3
+ export { DEFAULT_SCHED, RequestScheduler, SCHED_FILE, mirrorTo, newPrefill, readSchedFile, schedConfigFrom, schedEnabled, schedLine, schedPlain, setSchedConfigSource, sharedScheduler };
@@ -1,6 +1,6 @@
1
- import { j as readWorkersSection } from "./config-D5chi2LO.mjs";
2
- import { c as slotCurrentPath, u as workersLogDir } from "./paths-DoIyRnhx.mjs";
3
- import { _ as isTerminal, v as loadStatus } from "./status-CvVi9cDf.mjs";
1
+ import { j as readWorkersSection } from "./config-XpZWOYOG.mjs";
2
+ import { c as slotCurrentPath, u as workersLogDir } from "./paths-CHifubDh.mjs";
3
+ import { _ as isTerminal, v as loadStatus } from "./status-ggJ7lgVg.mjs";
4
4
  import { existsSync, mkdirSync, readFileSync, renameSync, rmSync, writeFileSync } from "node:fs";
5
5
  import { dirname, join } from "node:path";
6
6
  import { homedir } from "node:os";
@@ -221,4 +221,4 @@ function terminalHasName(name, term, registryPath = AIBROKER_REGISTRY) {
221
221
 
222
222
  //#endregion
223
223
  export { ownerSessionName as a, scopeKey as c, terminalHasName as d, workerInScope as f, itermUuid as i, sessionMapPath as l, currentTabKey as n, resolveSession as o, currentWorkerId as p, itermForClaudeSession as r, resolveSpawnerSession as s, AIBROKER_REGISTRY as t, sessionTag as u };
224
- //# sourceMappingURL=scope-D5VSQxe4.mjs.map
224
+ //# sourceMappingURL=scope-D-h6F6DN.mjs.map
@@ -1,4 +1,4 @@
1
- import { t as STOP_WORDS } from "./stop-words-SdSL1WKH.mjs";
1
+ import { t as STOP_WORDS } from "./stop-words-DSEYQdNe.mjs";
2
2
 
3
3
  //#region src/memory/search.ts
4
4
  /**
@@ -8,6 +8,20 @@ import { t as STOP_WORDS } from "./stop-words-SdSL1WKH.mjs";
8
8
  * back into buildFtsQuery()/isQuerySyntaxError() from this module.
9
9
  */
10
10
  /**
11
+ * Did SQLite reject the QUERY, or fail at the STORE?
12
+ *
13
+ * Only the first justifies an empty result. FTS5 reports a bad MATCH expression
14
+ * with a recognisable message; a missing table, a corrupt index or a locked
15
+ * database do not, and must not be reported as "nothing found".
16
+ *
17
+ * Matching on message text is unlovely, and the alternative — treating every
18
+ * failure as empty — is what produced a confidently wrong answer to a human.
19
+ */
20
+ function isQuerySyntaxError(e) {
21
+ const msg = e instanceof Error ? e.message : String(e);
22
+ return /fts5|malformed MATCH|syntax error|unterminated string|no such column/i.test(msg);
23
+ }
24
+ /**
11
25
  * Convert a free-text query into an FTS5 query string.
12
26
  *
13
27
  * Strategy:
@@ -21,24 +35,10 @@ import { t as STOP_WORDS } from "./stop-words-SdSL1WKH.mjs";
21
35
  * scoring naturally ranks chunks where more terms match higher, so the most
22
36
  * relevant chunks still surface at the top.
23
37
  *
24
- * Example: "Synchrotech interview follow-up Gilles"
25
- * → `"synchrotech" OR "interview" OR "follow" OR "gilles"`
38
+ * Example: "Acme interview follow-up Alice"
39
+ * → `"acme" OR "interview" OR "follow" OR "alice"`
26
40
  * → chunks matching any term, ranked by how many terms match
27
41
  */
28
- /**
29
- * Did SQLite reject the QUERY, or fail at the STORE?
30
- *
31
- * Only the first justifies an empty result. FTS5 reports a bad MATCH expression
32
- * with a recognisable message; a missing table, a corrupt index or a locked
33
- * database do not, and must not be reported as "nothing found".
34
- *
35
- * Matching on message text is unlovely, and the alternative — treating every
36
- * failure as empty — is what produced a confidently wrong answer to a human.
37
- */
38
- function isQuerySyntaxError(e) {
39
- const msg = e instanceof Error ? e.message : String(e);
40
- return /fts5|malformed MATCH|syntax error|unterminated string|no such column/i.test(msg);
41
- }
42
42
  function buildFtsQuery(query) {
43
43
  const tokens = query.toLowerCase().split(/[\s\p{P}]+/u).filter(Boolean).filter((t) => t.length >= 2).filter((t) => !STOP_WORDS.has(t)).map((t) => `"${t.replace(/"/g, "\"\"")}"`);
44
44
  if (tokens.length === 0) return `"${query.replace(/"/g, "\"\"")}"`;
@@ -104,4 +104,4 @@ function applyRecencyBoost(results, halfLifeDays = 90) {
104
104
 
105
105
  //#endregion
106
106
  export { populateSlugs as i, buildFtsQuery as n, isQuerySyntaxError as r, applyRecencyBoost as t };
107
- //# sourceMappingURL=search-CPoE0830.mjs.map
107
+ //# sourceMappingURL=search-RSyeQqj1.mjs.map
@@ -0,0 +1,35 @@
1
+ import "./utils-J2b9y8PC.mjs";
2
+ import "./migrate-DrA_OwlZ.mjs";
3
+ import "./config-XpZWOYOG.mjs";
4
+ import "./config-Bu1_vbY8.mjs";
5
+ import "./paths-CHifubDh.mjs";
6
+ import "./worktree-CrnOqTBW.mjs";
7
+ import "./status-ggJ7lgVg.mjs";
8
+ import "./pool-BRvoOkv6.mjs";
9
+ import "./registrable-Uzgmfyhz.mjs";
10
+ import "./pai-marker-DurzIbw8.mjs";
11
+ import "./helpers-CRuBUas3.mjs";
12
+ import "./scope-D-h6F6DN.mjs";
13
+ import "./routing-BAAST9vT.mjs";
14
+ import "./tool-errors-7E13StWd.mjs";
15
+ import "./wait-ByV0OyMZ.mjs";
16
+ import "./local-tiers-BE4jGaMa.mjs";
17
+ import "./caller-identity-yLFb7CKq.mjs";
18
+ import "./capacity-DEveQdFV.mjs";
19
+ import "./local-instances-DOxSgT_L.mjs";
20
+ import "./local-candidate-DLdwQt0s.mjs";
21
+ import "./factory-DjAAsqr_.mjs";
22
+ import "./postgres-C6ti4haA.mjs";
23
+ import "./embedding-gate-6rZrWRXa.mjs";
24
+ import "./embeddings-BVq3esBF.mjs";
25
+ import "./router-CQSc3lk3.mjs";
26
+ import "./detect-9CZNO0yf.mjs";
27
+ import "./helpers-BD6V-p9w.mjs";
28
+ import "./scan-ZQWm-_se.mjs";
29
+ import { a as newTop, c as planOpen, d as runNewDefault, f as sessionCommand, i as lsCommand, l as renameTop, n as collectRows, o as oneLine, p as sessionDir, r as collectView, s as openTop, t as applyProfileChat, u as rowsTable } from "./session-DVUExUnX.mjs";
30
+ import "./launch-Jh5NVeNe.mjs";
31
+ import "./health-Dnym-qcT.mjs";
32
+ import "./launch-CXVlZjHt.mjs";
33
+ import "./session-scan-W-gbwJHM.mjs";
34
+
35
+ export { runNewDefault };
@@ -1,24 +1,24 @@
1
1
  import { _ as warn, a as fmtDate, c as ok, d as scaffoldProjectDirs, f as shortenPath, i as err, l as renderTable, n as dim, o as header, p as slugFromPath, r as encodeDir, s as now, t as bold, u as resolvePath } from "./utils-J2b9y8PC.mjs";
2
2
  import { u as claudeProjectsDir } from "./runtime-paths-WsO9sJFc.mjs";
3
- import { b as nativeOrchestratorModel, j as readWorkersSection, p as getProviderOrNative, t as ANTHROPIC_NATIVE, vt as stripModelVariant, wt as appendLedger } from "./config-D5chi2LO.mjs";
4
- import { i as ledgerPath, u as workersLogDir } from "./paths-DoIyRnhx.mjs";
5
- import { A as trustProjectPath } from "./pool-CZ5MZaXg.mjs";
6
- import { a as unregistrableReason } from "./registrable-LrRIVYQc.mjs";
7
- import { n as ensurePaiMarker } from "./pai-marker-kIYuNt3c.mjs";
8
- import { t as STOP_WORDS } from "./stop-words-SdSL1WKH.mjs";
9
- import { bt as routeVerdictLine, on as SESSION_NAME_ENV, sn as getProfile, x as SESSION_WORKER_PROVIDER_ENV } from "./routing-CUyiglfu.mjs";
10
- import { n as OPT, t as CliError } from "./define-DGFu-sCf.mjs";
11
- import { i as getRegistryBackend } from "./factory-BtjbQ0np.mjs";
12
- import { n as formatDetection, r as formatDetectionJson, t as detectProject } from "./detect-C1d5cUkT.mjs";
13
- import { a as getSessionCount, c as upsertTag$1, i as getProjectTags, n as getProject$1, o as requireProject, r as getProjectAliases, s as resolveIdentifier, t as getLastSessionDate } from "./helpers-DFmYRCOa.mjs";
14
- import { a as resolveHome, n as loadScanConfig } from "./scan-B7I0gPe-.mjs";
15
- import { n as buildLaunchPlan, o as launchableProviderNames, s as maskLaunchEnv, t as LaunchError } from "./launch-DgqQdAjI.mjs";
16
- import { a as colorEnabled, f as renderTable$1, i as saveBudgetSnapshot, n as readBudget, o as makeStyle, r as readBudgetSnapshot, t as providerHealth } from "./health-C6jZWvRG.mjs";
17
- import { d as printExitDir, i as probeResume, u as transcriptModelFor } from "./launch-CLp0OJxV.mjs";
18
- import { n as fetchLiveSessions } from "./aibroker-client-CXEYBzbf.mjs";
19
- import { a as resolveSessionByNameOrId, s as scanSessions, t as fmtAge } from "./session-scan-BDLEc4w1.mjs";
3
+ import { b as nativeOrchestratorModel, j as readWorkersSection, p as getProviderOrNative, t as ANTHROPIC_NATIVE, vt as stripModelVariant, wt as appendLedger } from "./config-XpZWOYOG.mjs";
4
+ import { i as ledgerPath, u as workersLogDir } from "./paths-CHifubDh.mjs";
5
+ import { A as trustProjectPath } from "./pool-BRvoOkv6.mjs";
6
+ import { a as unregistrableReason } from "./registrable-Uzgmfyhz.mjs";
7
+ import { n as ensurePaiMarker } from "./pai-marker-DurzIbw8.mjs";
8
+ import { t as STOP_WORDS } from "./stop-words-DSEYQdNe.mjs";
9
+ import { cn as getProfile, sn as SESSION_NAME_ENV, x as SESSION_WORKER_PROVIDER_ENV, xt as routeVerdictLine } from "./routing-BAAST9vT.mjs";
10
+ import { n as OPT, t as CliError } from "./define-CjJsmq-6.mjs";
11
+ import { i as getRegistryBackend } from "./factory-DjAAsqr_.mjs";
12
+ import { n as formatDetection, r as formatDetectionJson, t as detectProject } from "./detect-9CZNO0yf.mjs";
13
+ import { a as getSessionCount, c as upsertTag$1, i as getProjectTags, n as getProject$1, o as requireProject, r as getProjectAliases, s as resolveIdentifier, t as getLastSessionDate } from "./helpers-BD6V-p9w.mjs";
14
+ import { a as resolveHome, n as loadScanConfig } from "./scan-ZQWm-_se.mjs";
15
+ import { n as buildLaunchPlan, o as launchableProviderNames, s as maskLaunchEnv, t as LaunchError } from "./launch-Jh5NVeNe.mjs";
16
+ import { a as colorEnabled, f as renderTable$1, i as saveBudgetSnapshot, n as readBudget, o as makeStyle, r as readBudgetSnapshot, t as providerHealth } from "./health-Dnym-qcT.mjs";
17
+ import { d as printExitDir, i as probeResume, u as transcriptModelFor } from "./launch-CXVlZjHt.mjs";
18
+ import { n as fetchLiveSessions } from "./aibroker-client-CQPGqLxL.mjs";
19
+ import { a as resolveSessionByNameOrId, s as scanSessions, t as fmtAge } from "./session-scan-W-gbwJHM.mjs";
20
20
  import { existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
21
- import { basename, join, resolve } from "node:path";
21
+ import { basename, dirname, join, resolve } from "node:path";
22
22
  import chalk from "chalk";
23
23
  import { homedir } from "node:os";
24
24
  import { spawnSync } from "node:child_process";
@@ -1066,7 +1066,7 @@ async function getSessionTags(registryBackend, sessionId) {
1066
1066
  * Session CRUD commands: list, info, rename, slug, tag, route, active, auto-route.
1067
1067
  */
1068
1068
  async function cmdList(projectSlug, opts) {
1069
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1069
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1070
1070
  const registryBackend = await getRegistryBackend();
1071
1071
  const limit = parseInt(opts.limit ?? "20", 10);
1072
1072
  let project;
@@ -1131,7 +1131,7 @@ async function cmdList(projectSlug, opts) {
1131
1131
  console.log(dim(` ${rows.length} session(s) shown (limit: ${limit})`));
1132
1132
  }
1133
1133
  async function cmdInfo(projectSlug, sessionNumber) {
1134
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1134
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1135
1135
  const registryBackend = await getRegistryBackend();
1136
1136
  const project = await getProject(registryBackend, projectSlug);
1137
1137
  if (!project) {
@@ -1155,9 +1155,20 @@ async function cmdInfo(projectSlug, sessionNumber) {
1155
1155
  console.log();
1156
1156
  }
1157
1157
  async function cmdRename(projectSlug, numberOrLatest, newSlug) {
1158
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1158
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1159
1159
  await cmdRenameWith(await getRegistryBackend(), projectSlug, numberOrLatest, newSlug);
1160
1160
  }
1161
+ /** Strips path separators and ".." so a title can never leave the notes dir. */
1162
+ function sanitizeTitle(title) {
1163
+ return title.replace(/[\\/]/g, " ").replace(/\.{2,}/g, " ").replace(/\s+/g, " ").trim();
1164
+ }
1165
+ /** Target path for a rename; throws unless it stays inside notesDir and does not clobber another note. */
1166
+ function checkedRenameTarget(notesDir, oldPath, newFilename) {
1167
+ const newPath = join(notesDir, newFilename);
1168
+ if (resolve(dirname(newPath)) !== resolve(notesDir)) throw new Error(`target escapes the notes directory: ${newFilename}`);
1169
+ if (newPath !== oldPath && existsSync(newPath)) throw new Error(`refusing to overwrite existing note: ${newFilename}`);
1170
+ return newPath;
1171
+ }
1161
1172
  async function cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSlug) {
1162
1173
  const project = await getProject(registryBackend, projectSlug);
1163
1174
  if (!project) {
@@ -1172,10 +1183,23 @@ async function cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSl
1172
1183
  process.exitCode = 1;
1173
1184
  return;
1174
1185
  }
1186
+ newSlug = sanitizeTitle(newSlug);
1187
+ if (!newSlug) {
1188
+ console.error(err("Title is empty after removing path separators."));
1189
+ process.exitCode = 1;
1190
+ return;
1191
+ }
1175
1192
  const titleSlug = toTitleCase(newSlug);
1176
1193
  const newFilename = formatFilename(session.number, session.date, titleSlug);
1177
1194
  const oldPath = join(notesDir, session.filename);
1178
- const newPath = join(notesDir, newFilename);
1195
+ let newPath;
1196
+ try {
1197
+ newPath = checkedRenameTarget(notesDir, oldPath, newFilename);
1198
+ } catch (e) {
1199
+ console.error(err(e instanceof Error ? e.message : String(e)));
1200
+ process.exitCode = 1;
1201
+ return;
1202
+ }
1179
1203
  if (existsSync(oldPath)) {
1180
1204
  if (oldPath !== newPath) try {
1181
1205
  renameSync(oldPath, newPath);
@@ -1218,7 +1242,7 @@ async function cmdRenameWith(registryBackend, projectSlug, numberOrLatest, newSl
1218
1242
  console.log();
1219
1243
  }
1220
1244
  async function cmdSlug(projectSlug, numberOrLatest, opts) {
1221
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1245
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1222
1246
  const registryBackend = await getRegistryBackend();
1223
1247
  const project = await getProject(registryBackend, projectSlug);
1224
1248
  if (!project) {
@@ -1248,7 +1272,7 @@ async function cmdSlug(projectSlug, numberOrLatest, opts) {
1248
1272
  }
1249
1273
  }
1250
1274
  async function cmdTag(projectSlug, sessionNumber, rawTags) {
1251
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1275
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1252
1276
  const registryBackend = await getRegistryBackend();
1253
1277
  const project = await getProject(registryBackend, projectSlug);
1254
1278
  if (!project) {
@@ -1288,7 +1312,7 @@ async function cmdTag(projectSlug, sessionNumber, rawTags) {
1288
1312
  console.log();
1289
1313
  }
1290
1314
  async function cmdRoute(projectSlug, sessionNumber, targetProjectSlug, opts) {
1291
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1315
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1292
1316
  const registryBackend = await getRegistryBackend();
1293
1317
  const project = await getProject(registryBackend, projectSlug);
1294
1318
  if (!project) {
@@ -1330,7 +1354,7 @@ async function cmdRoute(projectSlug, sessionNumber, targetProjectSlug, opts) {
1330
1354
  console.log();
1331
1355
  }
1332
1356
  async function cmdActive(opts) {
1333
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
1357
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
1334
1358
  const registryBackend = await getRegistryBackend();
1335
1359
  const minutes = parseInt(opts.minutes ?? "60", 10);
1336
1360
  const cutoff = Date.now() - minutes * 60 * 1e3;
@@ -1417,9 +1441,9 @@ async function cmdActive(opts) {
1417
1441
  ], rows));
1418
1442
  }
1419
1443
  async function cmdAutoRoute(opts) {
1420
- const { autoRoute, formatAutoRouteJson } = await import("./auto-route-BRk8NEFv.mjs");
1421
- const { getRegistryBackend, createStorageBackend } = await import("./factory-DAGG9_n8.mjs");
1422
- const { loadConfig } = await import("./config-TaWmdTLx.mjs");
1444
+ const { autoRoute, formatAutoRouteJson } = await import("./auto-route-BjoMHKyI.mjs");
1445
+ const { getRegistryBackend, createStorageBackend } = await import("./factory-Bsib-qDG.mjs");
1446
+ const { loadConfig } = await import("./config-DtENJ6cL.mjs");
1423
1447
  const config = loadConfig();
1424
1448
  const registryBackend = await getRegistryBackend();
1425
1449
  const federation = await createStorageBackend(config);
@@ -1830,7 +1854,7 @@ const newCommand = {
1830
1854
  const name = ctx.opts.name;
1831
1855
  const withSetup = ctx.opts.with;
1832
1856
  if (withSetup) {
1833
- const { runNewWith } = await import("./root-xI9DqVIe.mjs");
1857
+ const { runNewWith } = await import("./root-wC_6Fx0B.mjs");
1834
1858
  return runNewWith({
1835
1859
  dir,
1836
1860
  with: withSetup,
@@ -1936,4 +1960,4 @@ const renameTop = {
1936
1960
 
1937
1961
  //#endregion
1938
1962
  export { cmdAdd as A, cmdRebind as B, assertAvailable as C, execHarness as D, dryRunText as E, cmdEdit as F, cmdUnarchive as H, cmdGo as I, cmdInfo$1 as L, cmdArchive as M, cmdConsolidate as N, looksLikePath as O, cmdDetect as P, cmdList$1 as R, legacy as S, buildHarness as T, findMovedPath as U, cmdTag$1 as V, cmdList as _, newTop as a, cmdSlug as b, planOpen as c, runNewDefault as d, sessionCommand as f, cmdInfo as g, cmdAutoRoute as h, lsCommand as i, cmdAlias as j, prepareDir as k, renameTop as l, cmdActive as m, collectRows as n, oneLine as o, sessionDir as p, collectView as r, openTop as s, applyProfileChat as t, rowsTable as u, cmdRename as v, modelFor as w, cmdTag as x, cmdRoute as y, cmdMove as z };
1939
- //# sourceMappingURL=session-CNXF6DLP.mjs.map
1963
+ //# sourceMappingURL=session-DVUExUnX.mjs.map
@@ -0,0 +1,9 @@
1
+ import "./utils-J2b9y8PC.mjs";
2
+ import "./config-XpZWOYOG.mjs";
3
+ import "./config-Bu1_vbY8.mjs";
4
+ import "./paths-CHifubDh.mjs";
5
+ import "./status-ggJ7lgVg.mjs";
6
+ import "./scope-D-h6F6DN.mjs";
7
+ import { a as resolveSessionByNameOrId, c as transcriptCustomTitle, i as resolveFriendlyName, n as loadBrokerNames, o as scanCacheFilePath, r as migrateSessionScanCache, s as scanSessions, t as fmtAge } from "./session-scan-W-gbwJHM.mjs";
8
+
9
+ export { loadBrokerNames, transcriptCustomTitle };
@@ -1,9 +1,9 @@
1
1
  import { h as smartDecodeDir } from "./utils-J2b9y8PC.mjs";
2
2
  import { _ as resolvePaiFile, f as legacyConfigDir, g as paiHomePath, l as claudeHomeDir, m as migratePaiFile, u as claudeProjectsDir } from "./runtime-paths-WsO9sJFc.mjs";
3
- import { j as readWorkersSection } from "./config-D5chi2LO.mjs";
4
- import { u as workersLogDir } from "./paths-DoIyRnhx.mjs";
5
- import { t as fmtAge$1 } from "./fmt-age-BiSHrTKN.mjs";
6
- import { i as itermUuid, l as sessionMapPath, t as AIBROKER_REGISTRY } from "./scope-D5VSQxe4.mjs";
3
+ import { j as readWorkersSection } from "./config-XpZWOYOG.mjs";
4
+ import { u as workersLogDir } from "./paths-CHifubDh.mjs";
5
+ import { t as fmtAge$1 } from "./fmt-age-ByDkvkoU.mjs";
6
+ import { i as itermUuid, l as sessionMapPath, t as AIBROKER_REGISTRY } from "./scope-D-h6F6DN.mjs";
7
7
  import { closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, readdirSync, realpathSync, renameSync, statSync, writeFileSync } from "node:fs";
8
8
  import { basename, join } from "node:path";
9
9
 
@@ -137,7 +137,7 @@ function loadBrokerNames(registryPath = AIBROKER_REGISTRY, mapPath) {
137
137
  /** Build encoded_dir → root_path map from PAI registry (authoritative cwd). */
138
138
  async function buildRegistryRootPathMap() {
139
139
  try {
140
- const { getRegistryBackend } = await import("./factory-DAGG9_n8.mjs");
140
+ const { getRegistryBackend } = await import("./factory-Bsib-qDG.mjs");
141
141
  const projects = await (await getRegistryBackend()).listProjects();
142
142
  const map = /* @__PURE__ */ new Map();
143
143
  for (const p of projects) if (p.encoded_dir) map.set(p.encoded_dir, p.root_path);
@@ -870,4 +870,4 @@ function transcriptCustomTitle(claudeSessionId, projectsDir = CLAUDE_PROJECTS_DI
870
870
 
871
871
  //#endregion
872
872
  export { resolveSessionByNameOrId as a, transcriptCustomTitle as c, resolveFriendlyName as i, loadBrokerNames as n, scanCacheFilePath as o, migrateSessionScanCache as r, scanSessions as s, fmtAge as t };
873
- //# sourceMappingURL=session-scan-BDLEc4w1.mjs.map
873
+ //# sourceMappingURL=session-scan-W-gbwJHM.mjs.map
@@ -114,4 +114,4 @@ function tail(s, n) {
114
114
 
115
115
  //#endregion
116
116
  export { cmdMemorySources };
117
- //# sourceMappingURL=sources-CjhUKKtO.mjs.map
117
+ //# sourceMappingURL=sources-ESUkZaWv.mjs.map
@@ -1,6 +1,6 @@
1
- import "./config-D5chi2LO.mjs";
2
- import "./config-BSXKyeJ1.mjs";
3
- import "./paths-DoIyRnhx.mjs";
4
- import { A as setWorkerLabel, C as nowStamp, D as pidAlive, E as parseSleepSecs, M as spawnTimeOf, N as statusTmpPath, O as reconcileStatuses, P as waitForTerminalStatus, S as newWorkerId, T as ownsPidCached, _ as isTerminal, a as UNLABELED, b as loadStatusesCached, c as contextFooter, d as describeTool, f as elapsedOf, g as isLive, h as isChatPane, i as TERMINAL_RECHECK_MS, j as setWorkerNote, k as saveStatus, l as contextLabel, m as fmtTokens, n as OWNS_TTL_MS, o as ageOf, p as fmtContextK, r as SLEEP_FLOOR_SECS, s as alive, t as LOST_GRACE_MS, u as contextPercent, v as loadStatus, w as ownsPid, x as markStartFailed, y as loadStatuses } from "./status-CvVi9cDf.mjs";
1
+ import "./config-XpZWOYOG.mjs";
2
+ import "./config-Bu1_vbY8.mjs";
3
+ import "./paths-CHifubDh.mjs";
4
+ import { A as setWorkerLabel, C as nowStamp, D as pidAlive, E as parseSleepSecs, M as spawnTimeOf, N as statusTmpPath, O as reconcileStatuses, P as waitForTerminalStatus, S as newWorkerId, T as ownsPidCached, _ as isTerminal, a as UNLABELED, b as loadStatusesCached, c as contextFooter, d as describeTool, f as elapsedOf, g as isLive, h as isChatPane, i as TERMINAL_RECHECK_MS, j as setWorkerNote, k as saveStatus, l as contextLabel, m as fmtTokens, n as OWNS_TTL_MS, o as ageOf, p as fmtContextK, r as SLEEP_FLOOR_SECS, s as alive, t as LOST_GRACE_MS, u as contextPercent, v as loadStatus, w as ownsPid, x as markStartFailed, y as loadStatuses } from "./status-ggJ7lgVg.mjs";
5
5
 
6
6
  export { loadStatus };
@@ -1,10 +1,10 @@
1
- import { f as readMainConfigRaw } from "./config-BSXKyeJ1.mjs";
2
- import { l as statusPath } from "./paths-DoIyRnhx.mjs";
1
+ import { f as readMainConfigRaw } from "./config-Bu1_vbY8.mjs";
2
+ import { l as statusPath } from "./paths-CHifubDh.mjs";
3
3
  import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
4
+ import { createHash } from "node:crypto";
4
5
  import { join } from "node:path";
5
6
  import { execFileSync, spawnSync } from "node:child_process";
6
7
  import { parse } from "yaml";
7
- import { createHash } from "node:crypto";
8
8
 
9
9
  //#region src/workers/args.ts
10
10
  /**
@@ -259,16 +259,24 @@ function resolveToken() {
259
259
  return process.env.FORGE_TOKEN || process.env.AIBROKER_FORGE_TOKEN || void 0;
260
260
  }
261
261
  /** Real transport: curl; the token goes in on stdin so it never shows in ps. */
262
- const curlHttp = (method, url, token, body, timeoutMs) => {
263
- const cfg = [
264
- `url = "${url}"`,
265
- `request = "${method}"`,
266
- `header = "Authorization: token ${token}"`,
262
+ /** Escape a value for a double-quoted curl config string; newlines would inject directives. */
263
+ function curlQuote(v) {
264
+ if (/[\r\n]/.test(v)) throw new ForgeError("refusing newline in curl config value");
265
+ return v.replace(/\\/g, "\\\\").replace(/"/g, "\\\"");
266
+ }
267
+ function buildCurlConfig(method, url, token, timeoutMs) {
268
+ return [
269
+ `url = "${curlQuote(url)}"`,
270
+ `request = "${curlQuote(method)}"`,
271
+ `header = "Authorization: token ${curlQuote(token)}"`,
267
272
  `header = "Content-Type: application/json"`,
268
273
  `max-time = ${Math.max(.5, timeoutMs / 1e3)}`,
269
274
  `silent`,
270
275
  `write-out = "\\n%{http_code}"`
271
276
  ].join("\n");
277
+ }
278
+ const curlHttp = (method, url, token, body, timeoutMs) => {
279
+ const cfg = buildCurlConfig(method, url, token, timeoutMs);
272
280
  const r = spawnSync("curl", body !== void 0 ? [
273
281
  "-K",
274
282
  "-",
@@ -913,4 +921,4 @@ function describeTool(name, inp) {
913
921
 
914
922
  //#endregion
915
923
  export { isFlagToken as $, setWorkerLabel as A, loadStatusConfig as B, nowStamp as C, pidAlive as D, parseSleepSecs as E, ForgeError as F, writeSectionToForge as G, setClaim as H, PROJECT_CONFIG_REL as I, loadPreamble as J, PREAMBLE_MAX_BYTES as K, formatStale as L, spawnTimeOf as M, statusTmpPath as N, reconcileStatuses as O, waitForTerminalStatus as P, appendSystemPromptArgs as Q, listClaims as R, newWorkerId as S, ownsPidCached as T, upsertSection as U, parseStatusConfig as V, writeContinueToForge as W, preambleLine as X, preambleBlock as Y, projectRoot as Z, isTerminal as _, UNLABELED as a, loadStatusesCached as b, contextFooter as c, describeTool as d, longInlinePromptHint as et, elapsedOf as f, isLive as g, isChatPane as h, TERMINAL_RECHECK_MS as i, setWorkerNote as j, saveStatus as k, contextLabel as l, fmtTokens as m, OWNS_TTL_MS as n, shortText as nt, ageOf as o, fmtContextK as p, PREAMBLE_REL as q, SLEEP_FLOOR_SECS as r, stripPromptValues as rt, alive as s, LOST_GRACE_MS as t, parseRunnerArgs as tt, contextPercent as u, loadStatus as v, ownsPid as w, markStartFailed as x, loadStatuses as y, listStale as z };
916
- //# sourceMappingURL=status-CvVi9cDf.mjs.map
924
+ //# sourceMappingURL=status-ggJ7lgVg.mjs.map
@@ -323,4 +323,4 @@ const TITLE_STOP_WORDS = STOP_WORDS;
323
323
 
324
324
  //#endregion
325
325
  export { TITLE_STOP_WORDS as n, STOP_WORDS as t };
326
- //# sourceMappingURL=stop-words-SdSL1WKH.mjs.map
326
+ //# sourceMappingURL=stop-words-DSEYQdNe.mjs.map
@@ -39,4 +39,4 @@ function assertTestWriteAllowed(path) {
39
39
 
40
40
  //#endregion
41
41
  export { isTestRunner as n, assertTestWriteAllowed as t };
42
- //# sourceMappingURL=test-isolation-CoDeOVXb.mjs.map
42
+ //# sourceMappingURL=test-isolation-lqSmYxr0.mjs.map
@@ -11,4 +11,4 @@ const TAILSCALE_STATUS_TIMEOUT_MS = 3e3;
11
11
 
12
12
  //#endregion
13
13
  export { TAILSCALE_STATUS_TIMEOUT_MS as n, LOCAL_PROBE_TIMEOUT_MS as t };
14
- //# sourceMappingURL=timeouts-OwEONmc8.mjs.map
14
+ //# sourceMappingURL=timeouts-1MLooEBB.mjs.map
@@ -1,4 +1,5 @@
1
- import { n as bashExitCode, r as isExpectedWaitExit } from "./wait-BMUR-U-U.mjs";
1
+ import { t as maxOf } from "./min-max-DrSRUaWQ.mjs";
2
+ import { n as bashExitCode, r as isExpectedWaitExit } from "./wait-ByV0OyMZ.mjs";
2
3
  import { appendFileSync, closeSync, existsSync, mkdirSync, openSync, readFileSync, readSync, statSync } from "node:fs";
3
4
  import { join } from "node:path";
4
5
 
@@ -582,10 +583,10 @@ function errorsTable(groups) {
582
583
  hhmm(g.first),
583
584
  hhmm(g.last)
584
585
  ]);
585
- const w = rows[0].map((_, i) => Math.max(...rows.map((r) => r[i].length)));
586
+ const w = rows[0].map((_, i) => maxOf(rows.map((r) => r[i].length)));
586
587
  return rows.map((r) => r.map((c, i) => c.padEnd(w[i])).join(" ")).join("\n");
587
588
  }
588
589
 
589
590
  //#endregion
590
591
  export { toolErrorSigTag as C, toolErrorsPath as E, summarizeToolInput as S, toolErrorText as T, lastCommand as _, SAME_WORKER_WINDOW_MS as a, readToolErrors as b, classifyToolError as c, detectToolErrors as d, errorsTable as f, isBenignBash as g, harnessToolErrorTexts as h, SAME_WORKER_MIN as i, clipRaw as l, groupToolErrors as m, CROSS_WORKER_WINDOW_MS as n, TOOL_ERRORS_FILE as o, grantedToolNames as p, RESEND_MS as r, benignNote as s, CROSS_WORKER_MIN as t, detectRunningWorkerErrors as u, normalizeError as v, toolErrorSummary as w, recordToolError as x, parseSince as y };
591
- //# sourceMappingURL=tool-errors-AeRQuG3Y.mjs.map
592
+ //# sourceMappingURL=tool-errors-7E13StWd.mjs.map
@@ -1,8 +1,8 @@
1
- import "./config-D5chi2LO.mjs";
2
- import "./config-BSXKyeJ1.mjs";
3
- import "./paths-DoIyRnhx.mjs";
4
- import "./status-CvVi9cDf.mjs";
5
- import { C as toolErrorSigTag, E as toolErrorsPath, S as summarizeToolInput, T as toolErrorText, _ as lastCommand, a as SAME_WORKER_WINDOW_MS, b as readToolErrors, c as classifyToolError, d as detectToolErrors, f as errorsTable, g as isBenignBash, h as harnessToolErrorTexts, i as SAME_WORKER_MIN, l as clipRaw, m as groupToolErrors, n as CROSS_WORKER_WINDOW_MS, o as TOOL_ERRORS_FILE, p as grantedToolNames, r as RESEND_MS, s as benignNote, t as CROSS_WORKER_MIN, u as detectRunningWorkerErrors, v as normalizeError, w as toolErrorSummary, x as recordToolError, y as parseSince } from "./tool-errors-AeRQuG3Y.mjs";
6
- import "./wait-BMUR-U-U.mjs";
1
+ import "./config-XpZWOYOG.mjs";
2
+ import "./config-Bu1_vbY8.mjs";
3
+ import "./paths-CHifubDh.mjs";
4
+ import "./status-ggJ7lgVg.mjs";
5
+ import { C as toolErrorSigTag, E as toolErrorsPath, S as summarizeToolInput, T as toolErrorText, _ as lastCommand, a as SAME_WORKER_WINDOW_MS, b as readToolErrors, c as classifyToolError, d as detectToolErrors, f as errorsTable, g as isBenignBash, h as harnessToolErrorTexts, i as SAME_WORKER_MIN, l as clipRaw, m as groupToolErrors, n as CROSS_WORKER_WINDOW_MS, o as TOOL_ERRORS_FILE, p as grantedToolNames, r as RESEND_MS, s as benignNote, t as CROSS_WORKER_MIN, u as detectRunningWorkerErrors, v as normalizeError, w as toolErrorSummary, x as recordToolError, y as parseSince } from "./tool-errors-7E13StWd.mjs";
6
+ import "./wait-ByV0OyMZ.mjs";
7
7
 
8
8
  export { errorsTable, groupToolErrors, parseSince, readToolErrors };