@tekmidian/pai 1.0.0 → 1.0.3

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 (219) 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-B7Yu6Uam.mjs} +3 -3
  7. package/dist/auto-route-CjjQqU1o.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-7n9Gx56r.mjs} +5 -5
  12. package/dist/cli/index.mjs +1628 -370
  13. package/dist/{cockpit-actions-ODmt8yF9.mjs → cockpit-actions-BBHeyEZI.mjs} +84 -42
  14. package/dist/cockpit-actions-DR9X514g.mjs +20 -0
  15. package/dist/cockpit-memory--dnShXBA.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-CPoeudou.mjs} +37 -22
  21. package/dist/daemon/index.mjs +43 -42
  22. package/dist/daemon-DKdBNKfa.mjs +45 -0
  23. package/dist/{daemon-CorGh6Ub.mjs → daemon-DPAo6WTa.mjs} +103 -55
  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 +329 -231
  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-Cll7le4P.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-C1QIc1DA.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-BcZyJguM.mjs} +7 -6
  83. package/dist/{pane-audit-OGYrOAik.mjs → pane-audit-DKQt71s4.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-BmFACdLa.mjs} +31 -30
  87. package/dist/{pool-CZ5MZaXg.mjs → pool-Dh-q3iJi.mjs} +45 -6
  88. package/dist/{pool-cli-BxNSPzzY.mjs → pool-cli-BggU8GRp.mjs} +5 -5
  89. package/dist/{pool-cli-CbJfl37y.mjs → pool-cli-DQ6OzRy2.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-jvfONJTQ.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-BzH4TObg.mjs +9 -0
  97. package/dist/{registrable-LrRIVYQc.mjs → registrable-DpyTtajg.mjs} +4 -4
  98. package/dist/{render-BDbb4CF-.mjs → render-BYmQkuLd.mjs} +8 -8
  99. package/dist/render-CoMvwMPs.mjs +13 -0
  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-FtJsxYnm.mjs +36 -0
  103. package/dist/{root-BMeJuHOb.mjs → root-Xglu0OPD.mjs} +11 -11
  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-CSC7mgPf.mjs} +35 -33
  110. package/dist/{scan-B7I0gPe-.mjs → scan-C_Y5W9py.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-CNXF6DLP.mjs → session-8iqQDkqb.mjs} +55 -31
  116. package/dist/session-BeqAbNPd.mjs +35 -0
  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-CqozWW39.mjs +22 -0
  128. package/dist/{viewer-DtWj5Vti.mjs → viewer-mDXUNHNy.mjs} +15 -15
  129. package/dist/{wait-BMUR-U-U.mjs → wait-ByV0OyMZ.mjs} +3 -3
  130. package/dist/{worker-config-BLqa1yiD.mjs → worker-config-CJhEMk19.mjs} +294 -92
  131. package/dist/worker-config-DESkIjMF.mjs +41 -0
  132. package/dist/{workers-config-DEI9lrV4.mjs → workers-config-f8KrkY4L.mjs} +2 -2
  133. package/dist/{worktree-zmRf556h.mjs → worktree-CRs2gyg0.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.png +0 -0
  149. package/docs/images/architecture.svg +3 -0
  150. package/docs/images/cockpit-01-system-tokens.jpg +0 -0
  151. package/docs/images/cockpit-02-totals-cache.jpg +0 -0
  152. package/docs/images/cockpit-03-local-servers-models-pool.jpg +0 -0
  153. package/docs/images/cockpit-04-workers-memory.jpg +0 -0
  154. package/docs/images/cockpit-05-performance.jpg +0 -0
  155. package/docs/images/cockpit-06-runs-speed-routing.jpg +0 -0
  156. package/docs/images/cockpit-07-settings-registry.jpg +0 -0
  157. package/docs/install/index.md +29 -0
  158. package/docs/three-tier-coding.md +1 -1
  159. package/gemini-extension.json +1 -1
  160. package/package.json +1 -5
  161. package/pai-plugin.json +1 -1
  162. package/plugins/context-preservation/plugin.json +1 -1
  163. package/plugins/core/plugin.json +1 -1
  164. package/plugins/core/skills/setup/SKILL.md +41 -9
  165. package/plugins/creative/plugin.json +1 -1
  166. package/plugins/observability/plugin.json +1 -1
  167. package/plugins/productivity/plugin.json +1 -1
  168. package/plugins/semantic-search/plugin.json +1 -1
  169. package/plugins/ui/plugin.json +1 -1
  170. package/plugins/zettelkasten/plugin.json +1 -1
  171. package/src/hooks/session-autosave.sh +8 -1
  172. package/src/hooks/session-stop.sh +8 -1
  173. package/src/hooks/ts/capture-all-events.ts +7 -12
  174. package/src/hooks/ts/lib/context-fill.ts +2 -1
  175. package/src/hooks/ts/lib/path-repair.ts +1 -1
  176. package/src/hooks/ts/lib/project-utils/notify.ts +1 -0
  177. package/src/hooks/ts/lib/project-utils/session-notes.ts +23 -6
  178. package/src/hooks/ts/lib/raw-capture.ts +36 -0
  179. package/src/hooks/ts/lib/session-summary.ts +129 -0
  180. package/src/hooks/ts/lib/todo-sync.ts +120 -0
  181. package/src/hooks/ts/lib/worker-git-guard.ts +1 -1
  182. package/src/hooks/ts/post-tool-use/capture-tool-output.ts +6 -10
  183. package/src/hooks/ts/post-tool-use/sync-todo-to-md.ts +5 -105
  184. package/src/hooks/ts/pre-compact/context-compression-hook.ts +1 -1
  185. package/src/hooks/ts/pre-tool-use/security-validator.ts +35 -14
  186. package/src/hooks/ts/session-end/capture-session-summary.ts +20 -128
  187. package/src/hooks/ts/session-start/load-core-context.ts +3 -3
  188. package/src/hooks/ts/session-start/load-project-context.ts +18 -22
  189. package/src/hooks/ts/stop/stop-hook.ts +13 -5
  190. package/src/hooks/ztk-auto.sh +7 -2
  191. package/dist/aibroker-client-JjE74jo0.mjs +0 -3
  192. package/dist/auto-route-BRk8NEFv.mjs +0 -11
  193. package/dist/budget-DuhQ2zzG.mjs +0 -14
  194. package/dist/cockpit-actions-DcQ-ucU8.mjs +0 -19
  195. package/dist/cockpit-memory-KV45PPO2.mjs +0 -19
  196. package/dist/daemon-C7yt_ptC.mjs +0 -44
  197. package/dist/detect-DRUkmHnb.mjs +0 -10
  198. package/dist/factory-DAGG9_n8.mjs +0 -9
  199. package/dist/helpers-DPJEHPq6.mjs +0 -10
  200. package/dist/kill-tree-LV0Q7Mte.mjs +0 -10
  201. package/dist/operator-CfL0HiBK.mjs +0 -7
  202. package/dist/postgres-DgqWyqhN.mjs +0 -7
  203. package/dist/providers-CTu2s1z2.mjs +0 -15
  204. package/dist/registrable-D9aNZOTh.mjs +0 -9
  205. package/dist/render-BSfVlYHj.mjs +0 -13
  206. package/dist/root-xI9DqVIe.mjs +0 -35
  207. package/dist/route-table-HjvnLVEU.mjs +0 -14
  208. package/dist/session-BJHzmUg2.mjs +0 -34
  209. package/dist/session-scan-YORKE1NO.mjs +0 -9
  210. package/dist/viewer-B8709jDN.mjs +0 -22
  211. package/dist/worker-config-D8tRuvo7.mjs +0 -40
  212. package/docs/images/cockpit-limits-routing.jpg +0 -0
  213. package/docs/images/cockpit-models.jpg +0 -0
  214. package/docs/images/cockpit-usage.jpg +0 -0
  215. package/docs/images/cockpit-workers-system.jpg +0 -0
  216. package/scripts/build-docs.mjs +0 -41
  217. package/scripts/build-hooks.mjs +0 -311
  218. package/scripts/build-skill-stubs.mjs +0 -216
  219. package/scripts/copy-defaults.mjs +0 -46
@@ -9332,6 +9332,21 @@ function resolveToken() {
9332
9332
  }
9333
9333
  return process.env.FORGE_TOKEN || process.env.AIBROKER_FORGE_TOKEN || void 0;
9334
9334
  }
9335
+ function curlQuote(v) {
9336
+ if (/[\r\n]/.test(v)) throw new ForgeError("refusing newline in curl config value");
9337
+ return v.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
9338
+ }
9339
+ function buildCurlConfig(method, url, token, timeoutMs) {
9340
+ return [
9341
+ `url = "${curlQuote(url)}"`,
9342
+ `request = "${curlQuote(method)}"`,
9343
+ `header = "Authorization: token ${curlQuote(token)}"`,
9344
+ `header = "Content-Type: application/json"`,
9345
+ `max-time = ${Math.max(0.5, timeoutMs / 1e3)}`,
9346
+ `silent`,
9347
+ `write-out = "\\n%{http_code}"`
9348
+ ].join("\n");
9349
+ }
9335
9350
  function forgeClient(cwd2, cfg, deps) {
9336
9351
  const token = deps.token ?? resolveToken();
9337
9352
  if (!token) throw new ForgeError("no forge token");
@@ -9416,15 +9431,7 @@ var init_forge_sink = __esm({
9416
9431
  ForgeError = class extends Error {
9417
9432
  };
9418
9433
  curlHttp = (method, url, token, body, timeoutMs) => {
9419
- const cfg = [
9420
- `url = "${url}"`,
9421
- `request = "${method}"`,
9422
- `header = "Authorization: token ${token}"`,
9423
- `header = "Content-Type: application/json"`,
9424
- `max-time = ${Math.max(0.5, timeoutMs / 1e3)}`,
9425
- `silent`,
9426
- `write-out = "\\n%{http_code}"`
9427
- ].join("\n");
9434
+ const cfg = buildCurlConfig(method, url, token, timeoutMs);
9428
9435
  const argv = body !== void 0 ? ["-K", "-", "--data-raw", body] : ["-K", "-"];
9429
9436
  const r = spawnSync("curl", argv, { input: cfg, encoding: "utf8", timeout: timeoutMs + 500, maxBuffer: 16 * 1024 * 1024 });
9430
9437
  if (r.error || r.status !== 0) throw new ForgeError(`curl failed (${r.error?.message ?? `exit ${r.status}`})`);
@@ -9688,6 +9695,27 @@ var init_scope = __esm({
9688
9695
  }
9689
9696
  });
9690
9697
 
9698
+ // src/config/atomic-file.ts
9699
+ import { mkdirSync as mkdirSync5, renameSync as renameSync6, rmSync as rmSync2, writeFileSync as writeFileSync5 } from "node:fs";
9700
+ import { randomBytes } from "node:crypto";
9701
+ import { dirname as dirname6 } from "node:path";
9702
+ function writeFileAtomic(path, text) {
9703
+ mkdirSync5(dirname6(path), { recursive: true });
9704
+ const tmp = `${path}.${process.pid}.${randomBytes(4).toString("hex")}.tmp`;
9705
+ try {
9706
+ writeFileSync5(tmp, text, "utf8");
9707
+ renameSync6(tmp, path);
9708
+ } catch (e) {
9709
+ rmSync2(tmp, { force: true });
9710
+ throw e;
9711
+ }
9712
+ }
9713
+ var init_atomic_file = __esm({
9714
+ "src/config/atomic-file.ts"() {
9715
+ "use strict";
9716
+ }
9717
+ });
9718
+
9691
9719
  // src/workers/scratch.ts
9692
9720
  var init_scratch = __esm({
9693
9721
  "src/workers/scratch.ts"() {
@@ -9735,7 +9763,7 @@ var init_pool = __esm({
9735
9763
 
9736
9764
  // src/workers/worktree.ts
9737
9765
  import { execFile, execFileSync as execFileSync5, spawnSync as spawnSync2 } from "node:child_process";
9738
- import { existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync5, readFileSync as readFileSync10, mkdtempSync, writeFileSync as writeFileSync5, readdirSync as readdirSync3, readlinkSync, realpathSync, rmSync as rmSync2, statSync as statSync3 } from "node:fs";
9766
+ import { existsSync as existsSync10, lstatSync, mkdirSync as mkdirSync6, readFileSync as readFileSync10, mkdtempSync, writeFileSync as writeFileSync6, readdirSync as readdirSync3, readlinkSync, realpathSync, rmSync as rmSync3, statSync as statSync3 } from "node:fs";
9739
9767
  function runGit(cwd2, args, env, timeout = 3e4) {
9740
9768
  try {
9741
9769
  return execFileSync5("git", ["-C", cwd2, ...args], {
@@ -9804,7 +9832,7 @@ var init_fmt_age = __esm({
9804
9832
  });
9805
9833
 
9806
9834
  // src/workers/pending.ts
9807
- import { existsSync as existsSync11, readFileSync as readFileSync11, statSync as statSync4, writeFileSync as writeFileSync6 } from "node:fs";
9835
+ import { existsSync as existsSync11, readFileSync as readFileSync11, statSync as statSync4 } from "node:fs";
9808
9836
  import { join as join10 } from "node:path";
9809
9837
  function toplevel(dir) {
9810
9838
  try {
@@ -9854,7 +9882,7 @@ function pendingCountCached(logDir, cwd2, ttlMs = 6e4, now = Date.now()) {
9854
9882
  if (hit && now - hit.at < ttlMs) return hit.n;
9855
9883
  const n = pendingResults(logDir, cwd2, now).length;
9856
9884
  try {
9857
- writeFileSync6(file, JSON.stringify({ ...cache, [cwd2]: { at: now, n } }));
9885
+ writeFileAtomic(file, JSON.stringify({ ...cache, [cwd2]: { at: now, n } }));
9858
9886
  } catch {
9859
9887
  }
9860
9888
  return n;
@@ -9862,6 +9890,7 @@ function pendingCountCached(logDir, cwd2, ttlMs = 6e4, now = Date.now()) {
9862
9890
  var init_pending = __esm({
9863
9891
  "src/workers/pending.ts"() {
9864
9892
  "use strict";
9893
+ init_atomic_file();
9865
9894
  init_status();
9866
9895
  init_paths();
9867
9896
  init_worktree();
@@ -9869,6 +9898,23 @@ var init_pending = __esm({
9869
9898
  }
9870
9899
  });
9871
9900
 
9901
+ // src/utils/min-max.ts
9902
+ function minOf(values) {
9903
+ let m = Infinity;
9904
+ for (const v of values) if (v < m) m = v;
9905
+ return m;
9906
+ }
9907
+ function maxOf(values) {
9908
+ let m = -Infinity;
9909
+ for (const v of values) if (v > m) m = v;
9910
+ return m;
9911
+ }
9912
+ var init_min_max = __esm({
9913
+ "src/utils/min-max.ts"() {
9914
+ "use strict";
9915
+ }
9916
+ });
9917
+
9872
9918
  // src/builds/config.ts
9873
9919
  var init_config4 = __esm({
9874
9920
  "src/builds/config.ts"() {
@@ -9881,6 +9927,7 @@ var init_config4 = __esm({
9881
9927
  var init_queue = __esm({
9882
9928
  "src/builds/queue.ts"() {
9883
9929
  "use strict";
9930
+ init_min_max();
9884
9931
  init_pai_home();
9885
9932
  init_config4();
9886
9933
  }
@@ -10141,6 +10188,7 @@ var init_tree = __esm({
10141
10188
  var init_endreason = __esm({
10142
10189
  "src/workers/endreason.ts"() {
10143
10190
  "use strict";
10191
+ init_atomic_file();
10144
10192
  init_paths();
10145
10193
  init_ledger();
10146
10194
  init_status();
@@ -10583,7 +10631,7 @@ var init_pailot_guard = __esm({
10583
10631
 
10584
10632
  // src/workers/run-events.ts
10585
10633
  import { spawn } from "node:child_process";
10586
- import { existsSync as existsSync12, mkdirSync as mkdirSync6, openSync, readdirSync as readdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
10634
+ import { existsSync as existsSync12, mkdirSync as mkdirSync7, openSync, readdirSync as readdirSync4, readFileSync as readFileSync13, writeFileSync as writeFileSync7 } from "node:fs";
10587
10635
  var realDetachDeps;
10588
10636
  var init_run_events = __esm({
10589
10637
  "src/workers/run-events.ts"() {
@@ -10653,6 +10701,7 @@ var init_local_idle = __esm({
10653
10701
  var init_scheduler = __esm({
10654
10702
  "src/router/scheduler.ts"() {
10655
10703
  "use strict";
10704
+ init_min_max();
10656
10705
  }
10657
10706
  });
10658
10707
 
@@ -10701,6 +10750,7 @@ var CROSS_WORKER_WINDOW_MS, SAME_WORKER_WINDOW_MS, RESEND_MS, API_AUTH_EVIDENCE;
10701
10750
  var init_tool_errors = __esm({
10702
10751
  "src/workers/tool-errors.ts"() {
10703
10752
  "use strict";
10753
+ init_min_max();
10704
10754
  init_heredoc();
10705
10755
  init_render_decision();
10706
10756
  init_wait();
@@ -10773,35 +10823,14 @@ var init_viewer = __esm({
10773
10823
  }
10774
10824
  });
10775
10825
 
10776
- // src/config/atomic-file.ts
10777
- import { mkdirSync as mkdirSync7, renameSync as renameSync6, rmSync as rmSync3, writeFileSync as writeFileSync8 } from "node:fs";
10778
- import { dirname as dirname6 } from "node:path";
10779
- function writeFileAtomic(path, text) {
10780
- mkdirSync7(dirname6(path), { recursive: true });
10781
- const tmp = `${path}.${process.pid}.tmp`;
10782
- try {
10783
- writeFileSync8(tmp, text, "utf8");
10784
- renameSync6(tmp, path);
10785
- } catch (e) {
10786
- rmSync3(tmp, { force: true });
10787
- throw e;
10788
- }
10789
- }
10790
- var init_atomic_file = __esm({
10791
- "src/config/atomic-file.ts"() {
10792
- "use strict";
10793
- }
10794
- });
10795
-
10796
10826
  // src/router/usage.ts
10797
- var MAX_LINE, MAX_JSON, USAGE_CACHE_WINDOW_MS;
10827
+ var MAX_LINE, MAX_JSON;
10798
10828
  var init_usage = __esm({
10799
10829
  "src/router/usage.ts"() {
10800
10830
  "use strict";
10801
10831
  init_pai_home();
10802
10832
  MAX_LINE = 256 * 1024;
10803
10833
  MAX_JSON = 4 * 1024 * 1024;
10804
- USAGE_CACHE_WINDOW_MS = 7 * 864e5;
10805
10834
  }
10806
10835
  });
10807
10836
 
@@ -10841,6 +10870,7 @@ var init_parking = __esm({
10841
10870
  var init_local_instances = __esm({
10842
10871
  "src/workers/local-instances.ts"() {
10843
10872
  "use strict";
10873
+ init_min_max();
10844
10874
  init_local_tiers();
10845
10875
  }
10846
10876
  });
@@ -10894,7 +10924,7 @@ var init_local_provider = __esm({
10894
10924
  });
10895
10925
 
10896
10926
  // src/workers/session-profile-store.ts
10897
- import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync14, renameSync as renameSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync9 } from "node:fs";
10927
+ import { existsSync as existsSync13, mkdirSync as mkdirSync8, readFileSync as readFileSync14, renameSync as renameSync7, unlinkSync as unlinkSync2, writeFileSync as writeFileSync8 } from "node:fs";
10898
10928
  import { dirname as dirname7 } from "node:path";
10899
10929
  function cleanTarget(v) {
10900
10930
  if (!v || typeof v !== "object") return void 0;
@@ -10933,7 +10963,7 @@ function cleanProfile(v) {
10933
10963
  function writeAtomic(path, profiles) {
10934
10964
  mkdirSync8(dirname7(path), { recursive: true });
10935
10965
  const tmp = `${path}.tmp-${process.pid}`;
10936
- writeFileSync9(tmp, (0, import_yaml9.stringify)(profiles));
10966
+ writeFileSync8(tmp, (0, import_yaml9.stringify)(profiles));
10937
10967
  renameSync7(tmp, path);
10938
10968
  }
10939
10969
  function migrateLegacy(path, profiles) {
@@ -12206,7 +12236,7 @@ var require_utils_webcrypto = __commonJS({
12206
12236
  var nodeCrypto = __require("crypto");
12207
12237
  module.exports = {
12208
12238
  postgresMd5PasswordHash,
12209
- randomBytes,
12239
+ randomBytes: randomBytes2,
12210
12240
  deriveKey,
12211
12241
  sha256: sha2562,
12212
12242
  hashByName,
@@ -12216,7 +12246,7 @@ var require_utils_webcrypto = __commonJS({
12216
12246
  var webCrypto = nodeCrypto.webcrypto || globalThis.crypto;
12217
12247
  var subtleCrypto = webCrypto.subtle;
12218
12248
  var textEncoder = new TextEncoder();
12219
- function randomBytes(length) {
12249
+ function randomBytes2(length) {
12220
12250
  return webCrypto.getRandomValues(Buffer.alloc(length));
12221
12251
  }
12222
12252
  async function md5(string) {
@@ -16449,12 +16479,11 @@ function bufferToVector(buf) {
16449
16479
  return floats;
16450
16480
  }
16451
16481
  function buildPgTsQuery(query) {
16452
- 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, "''").replace(/[&|!():]/g, "")).filter(Boolean);
16453
- if (tokens.length === 0) {
16454
- const raw = query.replace(/[^a-z0-9]/gi, " ").trim().split(/\s+/).filter(Boolean).join(" | ");
16455
- return raw || "";
16456
- }
16457
- return tokens.join(" | ");
16482
+ const words = query.toLowerCase().match(/[\p{L}\p{N}_]+/gu) ?? [];
16483
+ const long = words.filter((t) => t.length >= 2);
16484
+ const tokens = long.filter((t) => !STOP_WORDS.has(t));
16485
+ const chosen = tokens.length > 0 ? tokens : long;
16486
+ return chosen.map((t) => `'${t}'`).join(" | ");
16458
16487
  }
16459
16488
  var init_helpers = __esm({
16460
16489
  "src/storage/postgres/helpers.ts"() {
@@ -16496,6 +16525,7 @@ async function searchKeyword(pool, query, opts) {
16496
16525
  const limitParam = `$${paramIdx}`;
16497
16526
  const sql = `
16498
16527
  SELECT
16528
+ id,
16499
16529
  project_id,
16500
16530
  path,
16501
16531
  start_line,
@@ -16503,6 +16533,8 @@ async function searchKeyword(pool, query, opts) {
16503
16533
  text AS snippet,
16504
16534
  tier,
16505
16535
  source,
16536
+ updated_at,
16537
+ last_accessed_at,
16506
16538
  ts_rank(fts_vector, to_tsquery('simple', $1)) AS rank_score
16507
16539
  FROM pai_chunks
16508
16540
  WHERE ${conditions.join(" AND ")}
@@ -16511,7 +16543,9 @@ async function searchKeyword(pool, query, opts) {
16511
16543
  `;
16512
16544
  try {
16513
16545
  const result = await pool.query(sql, params);
16546
+ const minScore = opts?.minScore ?? 0;
16514
16547
  return result.rows.map((row) => ({
16548
+ chunkId: row.id,
16515
16549
  projectId: row.project_id,
16516
16550
  path: row.path,
16517
16551
  startLine: row.start_line,
@@ -16519,8 +16553,10 @@ async function searchKeyword(pool, query, opts) {
16519
16553
  snippet: row.snippet,
16520
16554
  score: row.rank_score,
16521
16555
  tier: row.tier,
16522
- source: row.source
16523
- }));
16556
+ source: row.source,
16557
+ updatedAt: Number(row.updated_at),
16558
+ lastAccessedAt: row.last_accessed_at != null ? Number(row.last_accessed_at) : void 0
16559
+ })).filter((r) => r.score >= minScore);
16524
16560
  } catch (e) {
16525
16561
  process.stderr.write(`[pai-postgres] searchKeyword error: ${e}
16526
16562
  `);
@@ -17164,7 +17200,7 @@ function splitBySections(lines) {
17164
17200
  const splitAt = new Set(headings.filter((h) => h.level <= 3).map((h) => h.line));
17165
17201
  const flush = () => {
17166
17202
  const text = current2.map((l) => l.text).join("\n");
17167
- sections.push({ lines: current2, tokens: estimateTokens(text), headingPath: currentPath });
17203
+ sections.push({ lines: current2, tokens: sizeOf(text), headingPath: currentPath });
17168
17204
  current2 = [];
17169
17205
  };
17170
17206
  for (const line of lines) {
@@ -17183,7 +17219,7 @@ function splitByParagraphs(block) {
17183
17219
  for (const line of block.lines) {
17184
17220
  if (line.text.trim() === "" && current2.length > 0) {
17185
17221
  const text = current2.map((l) => l.text).join("\n");
17186
- paragraphs.push({ lines: [...current2], tokens: estimateTokens(text), headingPath: block.headingPath });
17222
+ paragraphs.push({ lines: [...current2], tokens: sizeOf(text), headingPath: block.headingPath });
17187
17223
  current2 = [];
17188
17224
  } else {
17189
17225
  current2.push(line);
@@ -17191,44 +17227,68 @@ function splitByParagraphs(block) {
17191
17227
  }
17192
17228
  if (current2.length > 0) {
17193
17229
  const text = current2.map((l) => l.text).join("\n");
17194
- paragraphs.push({ lines: current2, tokens: estimateTokens(text), headingPath: block.headingPath });
17230
+ paragraphs.push({ lines: current2, tokens: sizeOf(text), headingPath: block.headingPath });
17195
17231
  }
17196
17232
  return paragraphs.length > 0 ? paragraphs : [block];
17197
17233
  }
17198
- function splitBySentences(block, maxTokens) {
17199
- const fullText = block.lines.map((l) => l.text).join(" ");
17200
- const sentenceRe = /(?<=[.!?])\s+(?=[A-Z"'])/g;
17201
- const sentences = fullText.split(sentenceRe);
17234
+ function sizeOf(text) {
17235
+ return Math.max(estimateTokens(text), Math.ceil(text.length / MAX_CHARS_PER_TOKEN));
17236
+ }
17237
+ function splitLine(text, lineNo, budget) {
17238
+ if (sizeOf(text) <= budget) return [{ text, lineNo, join: "" }];
17239
+ const maxChars = budget * MAX_CHARS_PER_TOKEN;
17240
+ const pieces = [];
17241
+ const push = (t, join23) => {
17242
+ if (t) pieces.push({ text: t, lineNo, join: join23 });
17243
+ };
17244
+ let acc = "";
17245
+ const emit = () => {
17246
+ push(acc, pieces.length > 0 ? " " : "");
17247
+ acc = "";
17248
+ };
17249
+ const addWord = (word) => {
17250
+ if (acc && sizeOf(acc + " " + word) > budget) emit();
17251
+ if (sizeOf(word) > budget) {
17252
+ if (acc) emit();
17253
+ for (let i = 0; i < word.length; i += maxChars) {
17254
+ push(word.slice(i, i + maxChars), i === 0 ? pieces.length > 0 ? " " : "" : "");
17255
+ }
17256
+ return;
17257
+ }
17258
+ acc = acc ? acc + " " + word : word;
17259
+ };
17260
+ for (const sentence of text.split(/(?<=[.!?])\s+(?=[A-Z"'])/)) {
17261
+ if (acc && sizeOf(acc + " " + sentence) > budget) emit();
17262
+ if (sizeOf(sentence) <= budget) {
17263
+ acc = acc ? acc + " " + sentence : sentence;
17264
+ } else {
17265
+ for (const word of sentence.split(/\s+/).filter(Boolean)) addWord(word);
17266
+ }
17267
+ }
17268
+ emit();
17269
+ return pieces;
17270
+ }
17271
+ function splitOversized(block, budget) {
17202
17272
  const result = [];
17203
- let accText = "";
17204
- const startLine = block.lines[0]?.lineNo ?? 1;
17205
- const endLine = block.lines[block.lines.length - 1]?.lineNo ?? startLine;
17206
- const totalLines = endLine - startLine + 1;
17207
- const linesPerSentence = Math.max(1, Math.floor(totalLines / Math.max(1, sentences.length)));
17208
- let sentenceIdx = 0;
17209
- let approxLine = startLine;
17273
+ let cur = [];
17274
+ let curText = "";
17210
17275
  const flush = () => {
17211
- if (!accText.trim()) return;
17212
- const endApprox = Math.min(approxLine + linesPerSentence - 1, endLine);
17213
- result.push({
17214
- lines: [{ text: accText.trim(), lineNo: approxLine }],
17215
- tokens: estimateTokens(accText),
17216
- headingPath: block.headingPath
17217
- });
17218
- approxLine = endApprox + 1;
17219
- accText = "";
17276
+ if (cur.length > 0) result.push({ lines: cur, tokens: sizeOf(curText), headingPath: block.headingPath });
17277
+ cur = [];
17278
+ curText = "";
17220
17279
  };
17221
- for (const sentence of sentences) {
17222
- sentenceIdx++;
17223
- const candidateText = accText ? accText + " " + sentence : sentence;
17224
- if (estimateTokens(candidateText) > maxTokens && accText) {
17225
- flush();
17226
- accText = sentence;
17227
- } else {
17228
- accText = candidateText;
17280
+ const add = (piece, sep) => {
17281
+ const last = cur[cur.length - 1];
17282
+ if (last && piece.join && last.lineNo === piece.lineNo) last.text += piece.join + piece.text;
17283
+ else cur.push({ text: piece.text, lineNo: piece.lineNo });
17284
+ curText += (curText ? sep : "") + piece.text;
17285
+ };
17286
+ for (const line of block.lines) {
17287
+ for (const piece of splitLine(line.text, line.lineNo, budget)) {
17288
+ if (cur.length > 0 && sizeOf(curText + "\n" + piece.text) > budget) flush();
17289
+ add(piece, piece.join ? piece.join : "\n");
17229
17290
  }
17230
17291
  }
17231
- void sentenceIdx;
17232
17292
  flush();
17233
17293
  return result.length > 0 ? result : [block];
17234
17294
  }
@@ -17247,7 +17307,8 @@ function buildOverlapPrefix(lastChunk, overlapTokens) {
17247
17307
  return kept.map((text, idx) => ({ text, lineNo: Math.max(lastChunk.startLine, startLine + idx) }));
17248
17308
  }
17249
17309
  function stripPrivateTags(content) {
17250
- return content.replace(/<private>[\s\S]*?<\/private>/gi, "");
17310
+ const blank = (m) => m.replace(/[^\n]/g, "");
17311
+ return content.replace(/<private>[\s\S]*?<\/private>/gi, blank).replace(/<private>[\s\S]*$/i, blank);
17251
17312
  }
17252
17313
  function breadcrumb(path) {
17253
17314
  return path.length > 0 ? `[${path.join(" > ")}]
@@ -17267,7 +17328,7 @@ function chunkMarkdown(content, opts) {
17267
17328
  const sections = splitBySections(lines);
17268
17329
  const finalBlocks = [];
17269
17330
  for (const section of sections) {
17270
- const budget = Math.max(1, maxTokens - estimateTokens(breadcrumb(section.headingPath)));
17331
+ const budget = Math.max(1, maxTokens - sizeOf(breadcrumb(section.headingPath)));
17271
17332
  if (section.tokens <= budget) {
17272
17333
  finalBlocks.push(section);
17273
17334
  continue;
@@ -17278,8 +17339,7 @@ function chunkMarkdown(content, opts) {
17278
17339
  finalBlocks.push(para);
17279
17340
  continue;
17280
17341
  }
17281
- const sentences = splitBySentences(para, budget);
17282
- finalBlocks.push(...sentences);
17342
+ finalBlocks.push(...splitOversized(para, budget));
17283
17343
  }
17284
17344
  }
17285
17345
  const chunks = [];
@@ -17304,7 +17364,7 @@ function chunkMarkdown(content, opts) {
17304
17364
  }
17305
17365
  return chunks;
17306
17366
  }
17307
- var CHUNKER_VERSION, DEFAULT_MAX_TOKENS, DEFAULT_OVERLAP;
17367
+ var CHUNKER_VERSION, DEFAULT_MAX_TOKENS, DEFAULT_OVERLAP, MAX_CHARS_PER_TOKEN;
17308
17368
  var init_chunker = __esm({
17309
17369
  "src/memory/chunker.ts"() {
17310
17370
  "use strict";
@@ -17312,6 +17372,7 @@ var init_chunker = __esm({
17312
17372
  CHUNKER_VERSION = 2;
17313
17373
  DEFAULT_MAX_TOKENS = 400;
17314
17374
  DEFAULT_OVERLAP = 80;
17375
+ MAX_CHARS_PER_TOKEN = 6;
17315
17376
  }
17316
17377
  });
17317
17378
 
@@ -17485,8 +17546,9 @@ var init_retry = __esm({
17485
17546
  // src/memory/indexer/async.ts
17486
17547
  import { readFileSync as readFileSync15, statSync as statSync5, existsSync as existsSync16 } from "node:fs";
17487
17548
  import { join as join14, relative, basename as basename4 } from "node:path";
17488
- async function indexFileWithBackend(backend, projectId, rootPath, relativePath, source, tier) {
17549
+ async function indexFileWithBackend(backend, projectId, rootPath, relativePath, source, tier, pathPrefix = "") {
17489
17550
  const absPath = join14(rootPath, relativePath);
17551
+ const dbPath = pathPrefix + relativePath;
17490
17552
  let content;
17491
17553
  let stat;
17492
17554
  try {
@@ -17498,17 +17560,17 @@ async function indexFileWithBackend(backend, projectId, rootPath, relativePath,
17498
17560
  const hash = fileContentHash(content);
17499
17561
  const mtime = Math.floor(stat.mtimeMs);
17500
17562
  const size = stat.size;
17501
- const existingHash = await backend.getFileHash(projectId, relativePath);
17563
+ const existingHash = await backend.getFileHash(projectId, dbPath);
17502
17564
  if (existingHash === hash) return false;
17503
- await backend.deleteChunksForFile(projectId, relativePath);
17565
+ await backend.deleteChunksForFile(projectId, dbPath);
17504
17566
  const rawChunks = chunkMarkdown(content);
17505
17567
  const updatedAt = Date.now();
17506
17568
  const chunks = rawChunks.map((c, i) => ({
17507
- id: chunkId(projectId, relativePath, i, c.startLine, c.endLine),
17569
+ id: chunkId(projectId, dbPath, i, c.startLine, c.endLine),
17508
17570
  projectId,
17509
17571
  source,
17510
17572
  tier,
17511
- path: relativePath,
17573
+ path: dbPath,
17512
17574
  startLine: c.startLine,
17513
17575
  endLine: c.endLine,
17514
17576
  hash: c.hash,
@@ -17517,7 +17579,7 @@ async function indexFileWithBackend(backend, projectId, rootPath, relativePath,
17517
17579
  embedding: null
17518
17580
  }));
17519
17581
  await backend.insertChunks(chunks);
17520
- await backend.upsertFile({ projectId, path: relativePath, source, tier, hash, mtime, size });
17582
+ await backend.upsertFile({ projectId, path: dbPath, source, tier, hash, mtime, size });
17521
17583
  return true;
17522
17584
  }
17523
17585
  async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotesDir) {
@@ -17561,6 +17623,7 @@ async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotes
17561
17623
  embedding: null
17562
17624
  };
17563
17625
  try {
17626
+ if ((await backend.getChunkIds(projectId, syntheticPath)).length > 0) continue;
17564
17627
  await backend.insertChunks([titleChunk]);
17565
17628
  } catch {
17566
17629
  }
@@ -17599,6 +17662,7 @@ async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotes
17599
17662
  embedding: null
17600
17663
  };
17601
17664
  try {
17665
+ if ((await backend.getChunkIds(projectId, syntheticPath)).length > 0) continue;
17602
17666
  await backend.insertChunks([titleChunk]);
17603
17667
  } catch {
17604
17668
  }
@@ -17608,19 +17672,19 @@ async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotes
17608
17672
  const claudeProjectDir = claudeNotesDir.slice(0, -"/Notes".length);
17609
17673
  const claudeMemoryMd = join14(claudeProjectDir, "MEMORY.md");
17610
17674
  if (existsSync16(claudeMemoryMd)) {
17611
- filesToIndex.push({ absPath: claudeMemoryMd, rootBase: claudeProjectDir, source: "memory", tier: "evergreen" });
17675
+ filesToIndex.push({ absPath: claudeMemoryMd, rootBase: claudeProjectDir, source: "memory", tier: "evergreen", pathPrefix: CLAUDE_MEMORY_PREFIX });
17612
17676
  }
17613
17677
  const claudeMemoryDir = join14(claudeProjectDir, "memory");
17614
17678
  for (const absPath of walkMdFiles(claudeMemoryDir)) {
17615
17679
  const relPath = relative(claudeProjectDir, absPath);
17616
17680
  const tier = detectTier(relPath);
17617
- filesToIndex.push({ absPath, rootBase: claudeProjectDir, source: "memory", tier });
17681
+ filesToIndex.push({ absPath, rootBase: claudeProjectDir, source: "memory", tier, pathPrefix: CLAUDE_MEMORY_PREFIX });
17618
17682
  }
17619
17683
  }
17620
17684
  }
17621
17685
  await yieldToEventLoop();
17622
17686
  let filesSinceYield = 0;
17623
- for (const { absPath, rootBase, source, tier } of filesToIndex) {
17687
+ for (const { absPath, rootBase, source, tier, pathPrefix = "" } of filesToIndex) {
17624
17688
  if (filesSinceYield >= INDEX_YIELD_EVERY) {
17625
17689
  await yieldToEventLoop();
17626
17690
  filesSinceYield = 0;
@@ -17628,9 +17692,9 @@ async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotes
17628
17692
  filesSinceYield++;
17629
17693
  const relPath = relative(rootBase, absPath);
17630
17694
  try {
17631
- const changed = await indexFileWithBackend(backend, projectId, rootBase, relPath, source, tier);
17695
+ const changed = await indexFileWithBackend(backend, projectId, rootBase, relPath, source, tier, pathPrefix);
17632
17696
  if (changed) {
17633
- const ids = await backend.getChunkIds(projectId, relPath);
17697
+ const ids = await backend.getChunkIds(projectId, pathPrefix + relPath);
17634
17698
  result.filesProcessed++;
17635
17699
  result.chunksCreated += ids.length;
17636
17700
  } else {
@@ -17641,8 +17705,8 @@ async function indexProjectWithBackend(backend, projectId, rootPath, claudeNotes
17641
17705
  }
17642
17706
  }
17643
17707
  const livePaths = /* @__PURE__ */ new Set();
17644
- for (const { absPath, rootBase } of filesToIndex) {
17645
- livePaths.add(relative(rootBase, absPath));
17708
+ for (const { absPath, rootBase, pathPrefix = "" } of filesToIndex) {
17709
+ livePaths.add(pathPrefix + relative(rootBase, absPath));
17646
17710
  }
17647
17711
  const dbChunkPaths = await backend.getDistinctChunkPaths(projectId);
17648
17712
  const stalePaths = [];
@@ -17669,6 +17733,7 @@ async function indexAllWithBackend(backend, registry) {
17669
17733
  }
17670
17734
  return { projects: projects.length, result: totals };
17671
17735
  }
17736
+ var CLAUDE_MEMORY_PREFIX;
17672
17737
  var init_async = __esm({
17673
17738
  "src/memory/indexer/async.ts"() {
17674
17739
  "use strict";
@@ -17677,6 +17742,7 @@ var init_async = __esm({
17677
17742
  init_chunker();
17678
17743
  init_helpers2();
17679
17744
  init_retry();
17745
+ CLAUDE_MEMORY_PREFIX = ".claude-memory/";
17680
17746
  }
17681
17747
  });
17682
17748
 
@@ -18685,6 +18751,7 @@ var init_backend = __esm({
18685
18751
  async insertChunks(chunks) {
18686
18752
  if (chunks.length === 0) return;
18687
18753
  const client = await this.pool.connect();
18754
+ let releaseErr;
18688
18755
  try {
18689
18756
  await client.query("BEGIN");
18690
18757
  for (const c of chunks) {
@@ -18722,10 +18789,14 @@ var init_backend = __esm({
18722
18789
  }
18723
18790
  await client.query("COMMIT");
18724
18791
  } catch (e) {
18725
- await client.query("ROLLBACK");
18792
+ try {
18793
+ await client.query("ROLLBACK");
18794
+ } catch (rollbackErr) {
18795
+ releaseErr = rollbackErr instanceof Error ? rollbackErr : new Error(String(rollbackErr));
18796
+ }
18726
18797
  throw e;
18727
18798
  } finally {
18728
- client.release();
18799
+ client.release(releaseErr);
18729
18800
  }
18730
18801
  }
18731
18802
  async getDistinctChunkPaths(projectId) {
@@ -19194,7 +19265,7 @@ var init_ntfy = __esm({
19194
19265
  "Content-Type": "text/plain; charset=utf-8"
19195
19266
  };
19196
19267
  if (payload.title) {
19197
- headers["Title"] = payload.title;
19268
+ headers["Title"] = /^[\x20-\x7e]*$/.test(payload.title) ? payload.title : `=?UTF-8?B?${Buffer.from(payload.title, "utf8").toString("base64")}?=`;
19198
19269
  }
19199
19270
  if (cfg.priority && cfg.priority !== "default") {
19200
19271
  headers["Priority"] = cfg.priority;
@@ -19301,11 +19372,19 @@ var init_macos = __esm({
19301
19372
  if (process.platform !== "darwin") return false;
19302
19373
  try {
19303
19374
  const title = payload.title ?? "PAI";
19304
- const safeTitle = title.replace(/'/g, "\\'");
19305
- const safeMessage = payload.message.replace(/'/g, "\\'");
19306
- const script = `display notification "${safeMessage}" with title "${safeTitle}"`;
19375
+ const args = [
19376
+ "-e",
19377
+ "on run argv",
19378
+ "-e",
19379
+ "display notification (item 1 of argv) with title (item 2 of argv)",
19380
+ "-e",
19381
+ "end run",
19382
+ "--",
19383
+ payload.message,
19384
+ title
19385
+ ];
19307
19386
  return new Promise((resolve4) => {
19308
- const child = spawn2("osascript", ["-e", script], {
19387
+ const child = spawn2("osascript", args, {
19309
19388
  detached: true,
19310
19389
  stdio: "ignore"
19311
19390
  });
@@ -20642,8 +20721,8 @@ async function findTunnelsForSlugMap2(db, slugMap, opts) {
20642
20721
  const totalOccurrences = rows.reduce((s, r) => s + Number(r.cnt), 0);
20643
20722
  if (totalOccurrences < opts.min_occurrences) continue;
20644
20723
  const projects = rows.map((r) => slugMap[r.project_id] ?? String(r.project_id)).filter(Boolean);
20645
- const firstSeen = Math.min(...rows.map((r) => r.first_seen));
20646
- const lastSeen = Math.max(...rows.map((r) => r.last_seen));
20724
+ const firstSeen = minOf(rows.map((r) => r.first_seen));
20725
+ const lastSeen = maxOf(rows.map((r) => r.last_seen));
20647
20726
  tunnels.push({
20648
20727
  concept: term2,
20649
20728
  projects,
@@ -20682,6 +20761,7 @@ async function findTunnelsSqlite(db, registry, options) {
20682
20761
  var init_tunnels2 = __esm({
20683
20762
  "src/storage/sqlite/tunnels.ts"() {
20684
20763
  "use strict";
20764
+ init_min_max();
20685
20765
  init_stop_words();
20686
20766
  }
20687
20767
  });
@@ -23148,8 +23228,9 @@ var init_registry_sqlite = __esm({
23148
23228
  `;
23149
23229
  if (where.length) sql += " WHERE " + where.join(" AND ");
23150
23230
  sql += " ORDER BY s.date DESC, s.number DESC";
23151
- const limit = opts.limit ?? 20;
23152
- sql += ` LIMIT ${limit}`;
23231
+ const limit = Math.max(1, Math.trunc(Number(opts.limit ?? 20)) || 20);
23232
+ sql += " LIMIT ?";
23233
+ params.push(limit);
23153
23234
  return this.db.prepare(sql).all(...params);
23154
23235
  }
23155
23236
  async findSessionByFilename(projectId, filename) {
@@ -23658,7 +23739,7 @@ var init_detect = __esm({
23658
23739
 
23659
23740
  // src/cli/lib/utils.ts
23660
23741
  import { resolve as resolve3, basename as basename6, join as join18 } from "node:path";
23661
- import { mkdirSync as mkdirSync11, existsSync as existsSync18, writeFileSync as writeFileSync10, readdirSync as readdirSync6, statSync as statSync7 } from "node:fs";
23742
+ import { mkdirSync as mkdirSync11, existsSync as existsSync18, writeFileSync as writeFileSync9, readdirSync as readdirSync6, statSync as statSync7 } from "node:fs";
23662
23743
  function encIndex(entries) {
23663
23744
  let idx = indexes.get(entries);
23664
23745
  if (!idx) {
@@ -23798,7 +23879,7 @@ import {
23798
23879
  existsSync as existsSync19,
23799
23880
  realpathSync as realpathSync2,
23800
23881
  mkdirSync as mkdirSync12,
23801
- writeFileSync as writeFileSync11,
23882
+ writeFileSync as writeFileSync10,
23802
23883
  renameSync as renameSync8
23803
23884
  } from "node:fs";
23804
23885
  import { join as join20, basename as basename7 } from "node:path";
@@ -23888,7 +23969,7 @@ function flushScanCache(prune) {
23888
23969
  const target = paiHomePath("session-scan-cache.json");
23889
23970
  mkdirSync12(paiHomePath(), { recursive: true });
23890
23971
  const tmp = target + ".tmp";
23891
- writeFileSync11(tmp, JSON.stringify(out));
23972
+ writeFileSync10(tmp, JSON.stringify(out));
23892
23973
  renameSync8(tmp, target);
23893
23974
  } catch {
23894
23975
  }
@@ -25024,7 +25105,7 @@ var init_session_provider = __esm({
25024
25105
  });
25025
25106
 
25026
25107
  // src/workers/routing.ts
25027
- import { existsSync as existsSync21, readFileSync as readFileSync21, writeFileSync as writeFileSync12, renameSync as renameSync9, mkdirSync as mkdirSync13 } from "node:fs";
25108
+ import { existsSync as existsSync21, readFileSync as readFileSync21, writeFileSync as writeFileSync11, renameSync as renameSync9, mkdirSync as mkdirSync13 } from "node:fs";
25028
25109
  function readRoutingState(logDir) {
25029
25110
  const path = routingStatePath(logDir);
25030
25111
  if (!existsSync21(path)) return { cooldowns: {} };
@@ -25138,7 +25219,7 @@ function resolveWorkers(args, ctx) {
25138
25219
  }
25139
25220
 
25140
25221
  // src/workers/standalone/session-name-cache.ts
25141
- import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync22, writeFileSync as writeFileSync13 } from "node:fs";
25222
+ import { existsSync as existsSync22, mkdirSync as mkdirSync14, readFileSync as readFileSync22, writeFileSync as writeFileSync12 } from "node:fs";
25142
25223
  import { join as join22 } from "node:path";
25143
25224
  var SESSION_NAME_CACHE_TTL_MS = 5 * 6e4;
25144
25225
  function sessionNameCachePath(logDir, env, cwd2 = process.cwd()) {
@@ -25162,7 +25243,7 @@ function writeSessionNameCache(path, name, now = Date.now()) {
25162
25243
  if (!path) return;
25163
25244
  try {
25164
25245
  mkdirSync14(path.slice(0, path.lastIndexOf("/")), { recursive: true });
25165
- writeFileSync13(path, JSON.stringify({ name: name ?? null, at: now }), "utf8");
25246
+ writeFileSync12(path, JSON.stringify({ name: name ?? null, at: now }), "utf8");
25166
25247
  } catch {
25167
25248
  }
25168
25249
  }