@tekmidian/pai 0.54.1 → 0.56.0

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 (251) hide show
  1. package/dist/{aibroker-client-CNfIBrl5.mjs → aibroker-client-B8Wtasez.mjs} +1 -1
  2. package/dist/{aibroker-client-DzkTpVjx.mjs → aibroker-client-BK1h--W_.mjs} +3 -3
  3. package/dist/{aibroker-client-DzkTpVjx.mjs.map → aibroker-client-BK1h--W_.mjs.map} +1 -1
  4. package/dist/{indexer-backend-CdvCJCkD.mjs → async-CLvuY7b-.mjs} +7 -7
  5. package/dist/async-CLvuY7b-.mjs.map +1 -0
  6. package/dist/auto-route-CF8WNaoy.mjs +100 -0
  7. package/dist/auto-route-CF8WNaoy.mjs.map +1 -0
  8. package/dist/{chain-CZKlI0hq.mjs → chain-26f7uGUs.mjs} +4 -4
  9. package/dist/{chain-CZKlI0hq.mjs.map → chain-26f7uGUs.mjs.map} +1 -1
  10. package/dist/cli/index.mjs +22 -23
  11. package/dist/cli/index.mjs.map +1 -1
  12. package/dist/cli/program.d.mts.map +1 -1
  13. package/dist/cli/program.mjs +22 -23
  14. package/dist/{clusters-Cw_P6lO-.mjs → clusters-Ci1mseh2.mjs} +4 -36
  15. package/dist/clusters-Ci1mseh2.mjs.map +1 -0
  16. package/dist/{config-B3EPzRjf.mjs → config-B93YS8tP.mjs} +3 -3
  17. package/dist/{config-B3EPzRjf.mjs.map → config-B93YS8tP.mjs.map} +1 -1
  18. package/dist/{config-Bn9jpblO.mjs → config-D1omG_UU.mjs} +3 -3
  19. package/dist/{config-Bn9jpblO.mjs.map → config-D1omG_UU.mjs.map} +1 -1
  20. package/dist/{config-RjeVGJ7K.mjs → config-DCYWFaEi.mjs} +1 -1
  21. package/dist/{context-handover-cache-CXyH6QsC.mjs → context-handover-cache-k2kWbE6G.mjs} +82 -99
  22. package/dist/context-handover-cache-k2kWbE6G.mjs.map +1 -0
  23. package/dist/daemon/index.mjs +18 -24
  24. package/dist/daemon/index.mjs.map +1 -1
  25. package/dist/daemon-BOWol-LF.mjs +19 -0
  26. package/dist/{daemon-aJTxzg20.mjs → daemon-BsuM0UdV.mjs} +97 -466
  27. package/dist/daemon-BsuM0UdV.mjs.map +1 -0
  28. package/dist/daemon-mcp/index.mjs +10 -10
  29. package/dist/daemon-mcp/index.mjs.map +1 -1
  30. package/dist/{detector-DWXkeTlk.mjs → detector-3g7XuU1r.mjs} +5 -12
  31. package/dist/detector-3g7XuU1r.mjs.map +1 -0
  32. package/dist/detector-DgDn56j-.mjs +3 -0
  33. package/dist/{embeddings-ClqKtLZ8.mjs → embeddings-BNv3TQC5.mjs} +1 -1
  34. package/dist/{embeddings-DvRKcQyt.mjs → embeddings-DfrYNIng.mjs} +1 -1
  35. package/dist/{embeddings-DvRKcQyt.mjs.map → embeddings-DfrYNIng.mjs.map} +1 -1
  36. package/dist/factory-C9wGUe30.mjs +3 -0
  37. package/dist/factory-DiuntvwG.mjs +250 -0
  38. package/dist/factory-DiuntvwG.mjs.map +1 -0
  39. package/dist/{fallback-CCFIpPha.mjs → fallback-CVe3sb94.mjs} +192 -134
  40. package/dist/fallback-CVe3sb94.mjs.map +1 -0
  41. package/dist/federation-db-CJDw_Pwq.mjs +3 -0
  42. package/dist/{db-DJ8rk0VM.mjs → federation-db-w8e-sKjp.mjs} +5 -5
  43. package/dist/federation-db-w8e-sKjp.mjs.map +1 -0
  44. package/dist/{helpers-crDEr6S2.mjs → helpers-D9WkIf9R.mjs} +1 -1
  45. package/dist/{helpers-crDEr6S2.mjs.map → helpers-D9WkIf9R.mjs.map} +1 -1
  46. package/dist/hooks/capture-all-events.mjs.map +1 -1
  47. package/dist/hooks/capture-session-summary.mjs.map +1 -1
  48. package/dist/hooks/capture-tool-output.mjs.map +1 -1
  49. package/dist/hooks/context-compression-hook.mjs.map +1 -1
  50. package/dist/hooks/load-core-context.mjs +5 -0
  51. package/dist/hooks/load-core-context.mjs.map +2 -2
  52. package/dist/hooks/load-project-context.mjs.map +1 -1
  53. package/dist/hooks/post-compact-inject.mjs.map +1 -1
  54. package/dist/hooks/route-agents-to-worker.mjs.map +1 -1
  55. package/dist/hooks/route-edits-to-worker.mjs +1 -1
  56. package/dist/hooks/route-edits-to-worker.mjs.map +2 -2
  57. package/dist/hooks/security-validator.mjs +8367 -19
  58. package/dist/hooks/security-validator.mjs.map +4 -4
  59. package/dist/hooks/stop-hook.mjs.map +2 -2
  60. package/dist/hooks/whisper-rules.mjs.map +2 -2
  61. package/dist/hooks/worker-proxy.mjs.map +1 -1
  62. package/dist/hooks/worker-status-line.mjs.map +2 -2
  63. package/dist/hooks/worker-supervision.mjs.map +1 -1
  64. package/dist/index.d.mts +327 -100
  65. package/dist/index.d.mts.map +1 -1
  66. package/dist/index.mjs +7 -11
  67. package/dist/indexer-backend-Cc-_NK3q.mjs +1 -0
  68. package/dist/indexer-backend-DcDtin1O.mjs +5 -0
  69. package/dist/{ipc-client-C6NryMMb.mjs → ipc-client-Dasm515c.mjs} +2 -2
  70. package/dist/{ipc-client-C6NryMMb.mjs.map → ipc-client-Dasm515c.mjs.map} +1 -1
  71. package/dist/kg-entity-Cj8Q6YmU.mjs +29 -0
  72. package/dist/kg-entity-Cj8Q6YmU.mjs.map +1 -0
  73. package/dist/{latent-ideas-BfL4nCQ3.mjs → latent-ideas-BRy6HNwg.mjs} +4 -4
  74. package/dist/{latent-ideas-BfL4nCQ3.mjs.map → latent-ideas-BRy6HNwg.mjs.map} +1 -1
  75. package/dist/{link-boost-C5PaNdzm.mjs → link-boost-BptbAPuv.mjs} +1 -1
  76. package/dist/{link-boost-C5PaNdzm.mjs.map → link-boost-BptbAPuv.mjs.map} +1 -1
  77. package/dist/{main-resolver-Bt1f6jJc.mjs → main-resolver-Dx-pxic1.mjs} +56 -31
  78. package/dist/main-resolver-Dx-pxic1.mjs.map +1 -0
  79. package/dist/main-resolver-uDtK9p6e.mjs +7 -0
  80. package/dist/merge-BncjJTfb.mjs +3 -0
  81. package/dist/merge-xoyfZQ4W.mjs +6 -0
  82. package/dist/merge-xoyfZQ4W.mjs.map +1 -0
  83. package/dist/{migrate-CfERwXhY.mjs → migrate-BD7D8EEh.mjs} +21 -54
  84. package/dist/migrate-BD7D8EEh.mjs.map +1 -0
  85. package/dist/{neighborhood-CETR_P4y.mjs → neighborhood-D8uscnGy.mjs} +4 -25
  86. package/dist/neighborhood-D8uscnGy.mjs.map +1 -0
  87. package/dist/{note-context-DCcRWBoN.mjs → note-context-CgffaUMh.mjs} +3 -23
  88. package/dist/note-context-CgffaUMh.mjs.map +1 -0
  89. package/dist/{pai-home-ChAOupZc.mjs → pai-home-CeOIYltV.mjs} +2 -2
  90. package/dist/pai-home-CeOIYltV.mjs.map +1 -0
  91. package/dist/{pai-marker-B20KqhA8.mjs → pai-marker-D1MMswkz.mjs} +1 -1
  92. package/dist/{pai-marker-B20KqhA8.mjs.map → pai-marker-D1MMswkz.mjs.map} +1 -1
  93. package/dist/{planner-D3keWys5.mjs → planner-ye7wrrfB.mjs} +7 -7
  94. package/dist/{planner-D3keWys5.mjs.map → planner-ye7wrrfB.mjs.map} +1 -1
  95. package/dist/{postgres-CUSXWgTG.mjs → postgres-nvU5pShF.mjs} +863 -4
  96. package/dist/postgres-nvU5pShF.mjs.map +1 -0
  97. package/dist/{program-B3eRMhff.mjs → program-DuC1RcaO.mjs} +2268 -1402
  98. package/dist/program-DuC1RcaO.mjs.map +1 -0
  99. package/dist/query-feedback-COYCnvHQ.mjs +3 -0
  100. package/dist/{query-feedback-CTs_jx6i.mjs → query-feedback-xz5axTj3.mjs} +3 -3
  101. package/dist/query-feedback-xz5axTj3.mjs.map +1 -0
  102. package/dist/{db-Ddns80yf.mjs → registry-db-Bkpbp7Gf.mjs} +5 -5
  103. package/dist/registry-db-Bkpbp7Gf.mjs.map +1 -0
  104. package/dist/registry-db-DwXpf7yF.mjs +3 -0
  105. package/dist/registry-postgres-B07-hmn8.mjs +795 -0
  106. package/dist/registry-postgres-B07-hmn8.mjs.map +1 -0
  107. package/dist/registry-sqlite-CkGND_tm.mjs +593 -0
  108. package/dist/registry-sqlite-CkGND_tm.mjs.map +1 -0
  109. package/dist/{reranker-B5qUTamW.mjs → reranker-BS5gqGeF.mjs} +1 -1
  110. package/dist/{reranker-HHmhZk6v.mjs → reranker-CRVawoEh.mjs} +1 -1
  111. package/dist/{reranker-HHmhZk6v.mjs.map → reranker-CRVawoEh.mjs.map} +1 -1
  112. package/dist/router-BXOf_e9e.mjs +3 -0
  113. package/dist/{router-DBAZfE7X.mjs → router-BdxdsAvs.mjs} +2 -2
  114. package/dist/{router-DBAZfE7X.mjs.map → router-BdxdsAvs.mjs.map} +1 -1
  115. package/dist/{run-DLG25bzt.mjs → run-CqRvXGjd.mjs} +309 -49
  116. package/dist/run-CqRvXGjd.mjs.map +1 -0
  117. package/dist/{runtime-paths-B0P1TvUr.mjs → runtime-paths-BRwDeBEg.mjs} +1 -1
  118. package/dist/{runtime-paths-B0P1TvUr.mjs.map → runtime-paths-BRwDeBEg.mjs.map} +1 -1
  119. package/dist/search-BQHL5wDr.mjs +3 -0
  120. package/dist/search-BaTbyWjK.mjs +107 -0
  121. package/dist/search-BaTbyWjK.mjs.map +1 -0
  122. package/dist/{server-CGiHdaUp.mjs → server-CGuZFOeR.mjs} +4 -4
  123. package/dist/{server-CGiHdaUp.mjs.map → server-CGuZFOeR.mjs.map} +1 -1
  124. package/dist/{session-keepalive-DklS8VmU.mjs → session-keepalive-BQ6AQ9ez.mjs} +7 -7
  125. package/dist/{session-keepalive-DklS8VmU.mjs.map → session-keepalive-BQ6AQ9ez.mjs.map} +1 -1
  126. package/dist/skills/Plan/SKILL.md +1 -1
  127. package/dist/{sources-KBGEA_E6.mjs → sources-BBe3AZ-W.mjs} +8 -27
  128. package/dist/sources-BBe3AZ-W.mjs.map +1 -0
  129. package/dist/sqlite-D9p5a4qe.mjs +935 -0
  130. package/dist/sqlite-D9p5a4qe.mjs.map +1 -0
  131. package/dist/state-CwlGAKgF.mjs +3 -0
  132. package/dist/{state-DwrsOoMi.mjs → state-n13uPK5B.mjs} +6 -5
  133. package/dist/state-n13uPK5B.mjs.map +1 -0
  134. package/dist/{stop-words-BaMEGVeY.mjs → stop-words-ClCwO8mZ.mjs} +1 -1
  135. package/dist/{stop-words-BaMEGVeY.mjs.map → stop-words-ClCwO8mZ.mjs.map} +1 -1
  136. package/dist/{themes-BVoAnLZj.mjs → themes-B2v7RNnA.mjs} +3 -3
  137. package/dist/{themes-BVoAnLZj.mjs.map → themes-B2v7RNnA.mjs.map} +1 -1
  138. package/dist/{tools-BEqiJt_j.mjs → tools-Diro2s8J.mjs} +157 -398
  139. package/dist/tools-Diro2s8J.mjs.map +1 -0
  140. package/dist/{tools-BwsOTmjh.mjs → tools-KgL1rkPD.mjs} +4 -4
  141. package/dist/{trace-Cy8quQTm.mjs → trace-BRflVyBi.mjs} +1 -1
  142. package/dist/{trace-Cy8quQTm.mjs.map → trace-BRflVyBi.mjs.map} +1 -1
  143. package/dist/{utils-BD8g8oSf.mjs → utils-BrX9FLeK.mjs} +1 -1
  144. package/dist/{utils-CJymHkYm.mjs → utils-C9HsYDpO.mjs} +1 -1
  145. package/dist/{utils-CJymHkYm.mjs.map → utils-C9HsYDpO.mjs.map} +1 -1
  146. package/dist/{vault-indexer-C5i-OAyr.mjs → vault-indexer-DHYBpRZ5.mjs} +2 -2
  147. package/dist/{vault-indexer-C5i-OAyr.mjs.map → vault-indexer-DHYBpRZ5.mjs.map} +1 -1
  148. package/dist/{wakeup-Yk5lQ0jb.mjs → wakeup-D0uvqLsE.mjs} +95 -4
  149. package/dist/wakeup-D0uvqLsE.mjs.map +1 -0
  150. package/dist/work-queue-worker-DEbWsrDQ.mjs +11 -0
  151. package/dist/{work-queue-worker-utPp4hUv.mjs → work-queue-worker-DufMOtrL.mjs} +9 -9
  152. package/dist/work-queue-worker-DufMOtrL.mjs.map +1 -0
  153. package/dist/{zettelkasten-DezbXghl.mjs → zettelkasten-BPxSOalU.mjs} +4 -4
  154. package/dist/{zettelkasten-DezbXghl.mjs.map → zettelkasten-BPxSOalU.mjs.map} +1 -1
  155. package/docker/init.sql +5 -1
  156. package/docs/commands/README.md +5 -0
  157. package/docs/commands/audit.md +1 -1
  158. package/docs/commands/backup.md +1 -1
  159. package/docs/commands/clear-names.md +1 -1
  160. package/docs/commands/config.md +4 -4
  161. package/docs/commands/daemon.md +1 -1
  162. package/docs/commands/db.md +15 -1
  163. package/docs/commands/end.md +1 -1
  164. package/docs/commands/help.md +1 -1
  165. package/docs/commands/hooks-db.md +47 -0
  166. package/docs/commands/identity.md +1 -1
  167. package/docs/commands/kg.md +1 -1
  168. package/docs/commands/launch.md +1 -1
  169. package/docs/commands/mcp.md +1 -1
  170. package/docs/commands/memory.md +1 -1
  171. package/docs/commands/notify.md +1 -1
  172. package/docs/commands/observation.md +1 -1
  173. package/docs/commands/obsidian.md +1 -1
  174. package/docs/commands/pause.md +1 -1
  175. package/docs/commands/project.md +1 -1
  176. package/docs/commands/projects.md +1 -1
  177. package/docs/commands/registry.md +1 -1
  178. package/docs/commands/restore.md +1 -1
  179. package/docs/commands/session.md +2 -2
  180. package/docs/commands/sessions.md +1 -1
  181. package/docs/commands/setup.md +1 -1
  182. package/docs/commands/shell-init.md +1 -1
  183. package/docs/commands/skill.md +1 -1
  184. package/docs/commands/task.md +1 -1
  185. package/docs/commands/topic.md +1 -1
  186. package/docs/commands/update.md +1 -1
  187. package/docs/commands/worker.md +1 -1
  188. package/docs/commands/zettel.md +1 -1
  189. package/docs/design/postgres-only.md +438 -0
  190. package/docs/design/registry-method-map.md +174 -0
  191. package/package.json +1 -1
  192. package/src/hooks/pre-compact.sh +2 -40
  193. package/src/hooks/session-hooks-db.test.ts +93 -0
  194. package/src/hooks/session-stop.sh +2 -26
  195. package/src/hooks/ts/lib/edit-gate.test.ts +9 -0
  196. package/src/hooks/ts/lib/edit-gate.ts +5 -2
  197. package/src/hooks/ts/lib/plutil-guard.test.ts +54 -0
  198. package/src/hooks/ts/lib/plutil-guard.ts +43 -0
  199. package/src/hooks/ts/lib/worker-git-guard.test.ts +134 -0
  200. package/src/hooks/ts/lib/worker-git-guard.ts +103 -0
  201. package/src/hooks/ts/pre-tool-use/security-validator.test.ts +68 -0
  202. package/src/hooks/ts/pre-tool-use/security-validator.ts +69 -21
  203. package/src/hooks/ts/session-start/load-core-context.ts +13 -0
  204. package/src/hooks/ts/session-start/session-start-worker-guard.test.ts +13 -0
  205. package/dist/auto-route-CcD0OWWB.mjs +0 -86
  206. package/dist/auto-route-CcD0OWWB.mjs.map +0 -1
  207. package/dist/clusters-Cw_P6lO-.mjs.map +0 -1
  208. package/dist/context-handover-cache-CXyH6QsC.mjs.map +0 -1
  209. package/dist/daemon-CknQ6YGZ.mjs +0 -25
  210. package/dist/daemon-aJTxzg20.mjs.map +0 -1
  211. package/dist/db-BOBfewFH.mjs +0 -3
  212. package/dist/db-DJ8rk0VM.mjs.map +0 -1
  213. package/dist/db-DbY2O8QO.mjs +0 -3
  214. package/dist/db-Ddns80yf.mjs.map +0 -1
  215. package/dist/detect-Bf2z-oKB.mjs +0 -86
  216. package/dist/detect-Bf2z-oKB.mjs.map +0 -1
  217. package/dist/detector-CkwkXuGh.mjs +0 -5
  218. package/dist/detector-DWXkeTlk.mjs.map +0 -1
  219. package/dist/factory-Ba8j9K7q.mjs +0 -3
  220. package/dist/factory-Bt7TWQje.mjs +0 -150
  221. package/dist/factory-Bt7TWQje.mjs.map +0 -1
  222. package/dist/fallback-CCFIpPha.mjs.map +0 -1
  223. package/dist/indexer-backend-CdvCJCkD.mjs.map +0 -1
  224. package/dist/kg-entity-BSW7ra8i.mjs +0 -176
  225. package/dist/kg-entity-BSW7ra8i.mjs.map +0 -1
  226. package/dist/main-resolver-Bt1f6jJc.mjs.map +0 -1
  227. package/dist/main-resolver-DYHhw5Ig.mjs +0 -7
  228. package/dist/migrate-CfERwXhY.mjs.map +0 -1
  229. package/dist/neighborhood-CETR_P4y.mjs.map +0 -1
  230. package/dist/note-context-DCcRWBoN.mjs.map +0 -1
  231. package/dist/pai-home-ChAOupZc.mjs.map +0 -1
  232. package/dist/postgres-CUSXWgTG.mjs.map +0 -1
  233. package/dist/program-B3eRMhff.mjs.map +0 -1
  234. package/dist/query-feedback-Bm6XvCmg.mjs +0 -3
  235. package/dist/query-feedback-CTs_jx6i.mjs.map +0 -1
  236. package/dist/router-CremHKTI.mjs +0 -3
  237. package/dist/run-DLG25bzt.mjs.map +0 -1
  238. package/dist/search-B69cQwDB.mjs +0 -303
  239. package/dist/search-B69cQwDB.mjs.map +0 -1
  240. package/dist/search-fb-5ovj4.mjs +0 -4
  241. package/dist/sources-KBGEA_E6.mjs.map +0 -1
  242. package/dist/sqlite-By6r2YhZ.mjs +0 -271
  243. package/dist/sqlite-By6r2YhZ.mjs.map +0 -1
  244. package/dist/state-Ca0ltLgI.mjs +0 -3
  245. package/dist/state-DwrsOoMi.mjs.map +0 -1
  246. package/dist/sync-Btcb6xA4.mjs +0 -310
  247. package/dist/sync-Btcb6xA4.mjs.map +0 -1
  248. package/dist/tools-BEqiJt_j.mjs.map +0 -1
  249. package/dist/wakeup-Yk5lQ0jb.mjs.map +0 -1
  250. package/dist/work-queue-worker-DsdJx-jn.mjs +0 -14
  251. package/dist/work-queue-worker-utPp4hUv.mjs.map +0 -1
package/dist/index.d.mts CHANGED
@@ -1,32 +1,329 @@
1
- import { Database, Database as Database$1, Database as Database$2 } from "better-sqlite3";
2
-
3
- //#region src/registry/schema.d.ts
4
- declare const SCHEMA_VERSION = 4;
5
- declare const CREATE_TABLES_SQL = "\nPRAGMA journal_mode = WAL;\nPRAGMA foreign_keys = ON;\n\nCREATE TABLE IF NOT EXISTS projects (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n slug TEXT NOT NULL UNIQUE,\n display_name TEXT NOT NULL,\n root_path TEXT NOT NULL UNIQUE,\n encoded_dir TEXT NOT NULL UNIQUE,\n type TEXT NOT NULL DEFAULT 'local'\n CHECK(type IN ('local','central','obsidian-linked','external')),\n status TEXT NOT NULL DEFAULT 'active'\n CHECK(status IN ('active','archived','migrating')),\n parent_id INTEGER,\n obsidian_link TEXT,\n claude_notes_dir TEXT,\n session_config TEXT,\n created_at INTEGER NOT NULL,\n updated_at INTEGER NOT NULL,\n archived_at INTEGER,\n FOREIGN KEY (parent_id) REFERENCES projects(id)\n);\n\nCREATE TABLE IF NOT EXISTS sessions (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n number INTEGER NOT NULL,\n date TEXT NOT NULL,\n slug TEXT NOT NULL,\n title TEXT NOT NULL,\n filename TEXT NOT NULL,\n status TEXT NOT NULL DEFAULT 'open'\n CHECK(status IN ('open','completed','compacted')),\n claude_session_id TEXT,\n token_count INTEGER,\n created_at INTEGER NOT NULL,\n closed_at INTEGER,\n UNIQUE (project_id, number),\n FOREIGN KEY (project_id) REFERENCES projects(id)\n);\n\nCREATE TABLE IF NOT EXISTS tags (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n name TEXT NOT NULL UNIQUE\n);\n\nCREATE TABLE IF NOT EXISTS project_tags (\n project_id INTEGER NOT NULL,\n tag_id INTEGER NOT NULL,\n PRIMARY KEY (project_id, tag_id),\n FOREIGN KEY (project_id) REFERENCES projects(id),\n FOREIGN KEY (tag_id) REFERENCES tags(id)\n);\n\nCREATE TABLE IF NOT EXISTS session_tags (\n session_id INTEGER NOT NULL,\n tag_id INTEGER NOT NULL,\n PRIMARY KEY (session_id, tag_id),\n FOREIGN KEY (session_id) REFERENCES sessions(id),\n FOREIGN KEY (tag_id) REFERENCES tags(id)\n);\n\nCREATE TABLE IF NOT EXISTS aliases (\n alias TEXT PRIMARY KEY,\n project_id INTEGER NOT NULL,\n FOREIGN KEY (project_id) REFERENCES projects(id)\n);\n\nCREATE TABLE IF NOT EXISTS compaction_log (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n project_id INTEGER NOT NULL,\n session_id INTEGER,\n trigger TEXT NOT NULL\n CHECK(trigger IN ('precompact','manual','end-session')),\n files_written TEXT NOT NULL,\n token_count INTEGER,\n created_at INTEGER NOT NULL,\n FOREIGN KEY (project_id) REFERENCES projects(id),\n FOREIGN KEY (session_id) REFERENCES sessions(id)\n);\n\nCREATE TABLE IF NOT EXISTS links (\n id INTEGER PRIMARY KEY AUTOINCREMENT,\n session_id INTEGER NOT NULL,\n target_project_id INTEGER NOT NULL,\n link_type TEXT NOT NULL DEFAULT 'related'\n CHECK(link_type IN ('related','follow-up','reference')),\n created_at INTEGER NOT NULL,\n UNIQUE (session_id, target_project_id),\n FOREIGN KEY (session_id) REFERENCES sessions(id),\n FOREIGN KEY (target_project_id) REFERENCES projects(id)\n);\n\nCREATE TABLE IF NOT EXISTS schema_version (\n version INTEGER PRIMARY KEY,\n applied_at INTEGER NOT NULL\n);\n\n-- Indexes\nCREATE INDEX IF NOT EXISTS idx_projects_slug ON projects(slug);\nCREATE INDEX IF NOT EXISTS idx_projects_status ON projects(status);\nCREATE INDEX IF NOT EXISTS idx_projects_type ON projects(type);\nCREATE INDEX IF NOT EXISTS idx_sessions_project ON sessions(project_id);\nCREATE INDEX IF NOT EXISTS idx_sessions_date ON sessions(date);\nCREATE INDEX IF NOT EXISTS idx_sessions_status ON sessions(status);\nCREATE INDEX IF NOT EXISTS idx_sessions_claude ON sessions(claude_session_id);\nCREATE INDEX IF NOT EXISTS idx_pc_project ON project_tags(project_id);\n";
1
+ //#region src/registry/merge.d.ts
6
2
  /**
7
- * Run the full DDL against an open database connection.
3
+ * merge.ts — pure types and error class shared by the merge implementations.
8
4
  *
9
- * The function is idempotent — every statement uses IF NOT EXISTS so it is
10
- * safe to call on an already-initialised database. After creating the tables
11
- * it inserts the current SCHEMA_VERSION into schema_version if no row exists
12
- * yet.
13
- */
14
- declare function initializeSchema(db: Database): void;
15
- //#endregion
16
- //#region src/registry/db.d.ts
17
- /**
18
- * Open (or create) the PAI registry database.
19
- *
20
- * @param path Absolute path to registry.db. Defaults to PAI_HOME/registry.db
21
- * (falling back to the pre-2026-09-19 ~/.pai/registry.db).
22
- * @returns An open better-sqlite3 Database instance.
5
+ * The actual SQLite implementation (planMerge/applyMerge, taking a raw
6
+ * better-sqlite3 Database) lives in src/storage/sqlite/registry-merge.ts —
7
+ * moved there so nothing outside src/storage/ imports better-sqlite3. The
8
+ * Postgres implementation lives in src/storage/registry-postgres.ts. Both are
9
+ * reached through RegistryBackend.planProjectMerge/applyProjectMerge
10
+ * (src/storage/registry-interface.ts), never directly.
23
11
  *
24
- * Side effects on first call:
25
- * - Creates the parent directory if it does not exist.
26
- * - Enables WAL journal mode.
27
- * - Runs initializeSchema() if schema_version is empty.
12
+ * See src/storage/sqlite/registry-merge.ts for the "why one function" design
13
+ * rationale (five tables reference a project, foreign_keys is off).
28
14
  */
29
- declare function openRegistry(path?: string): Database$2;
15
+ interface MergePlan {
16
+ fromId: number;
17
+ fromSlug: string;
18
+ intoId: number;
19
+ intoSlug: string;
20
+ /** Sessions to move, with the numbers they will be given. */
21
+ sessions: {
22
+ id: number;
23
+ from: number;
24
+ to: number;
25
+ }[];
26
+ tags: number;
27
+ aliases: number;
28
+ compactions: number;
29
+ links: number;
30
+ /** The losing slug is kept as an alias, so `pai <old-name>` still resolves. */
31
+ aliasToAdd?: string;
32
+ }
33
+ //#endregion
34
+ //#region src/storage/registry-interface.d.ts
35
+ type ProjectType = "local" | "central" | "obsidian-linked" | "external";
36
+ type ProjectStatus = "active" | "archived" | "migrating";
37
+ type SessionStatus = "open" | "completed" | "compacted";
38
+ type LinkType = "related" | "follow-up" | "reference";
39
+ type CompactionTrigger = "precompact" | "manual" | "end-session";
40
+ interface Project {
41
+ id: number;
42
+ slug: string;
43
+ display_name: string;
44
+ root_path: string;
45
+ encoded_dir: string;
46
+ type: ProjectType;
47
+ status: ProjectStatus;
48
+ parent_id: number | null;
49
+ obsidian_link: string | null;
50
+ claude_notes_dir: string | null;
51
+ session_config: string | null;
52
+ created_at: number;
53
+ updated_at: number;
54
+ archived_at: number | null;
55
+ }
56
+ interface ProjectWithSessionStats extends Project {
57
+ session_count: number;
58
+ last_active: number | null;
59
+ }
60
+ interface Session {
61
+ id: number;
62
+ project_id: number;
63
+ number: number;
64
+ date: string;
65
+ slug: string;
66
+ title: string;
67
+ filename: string;
68
+ status: SessionStatus;
69
+ claude_session_id: string | null;
70
+ token_count: number | null;
71
+ created_at: number;
72
+ closed_at: number | null;
73
+ }
74
+ interface SessionWithProject extends Session {
75
+ project_slug: string;
76
+ project_name: string;
77
+ }
78
+ interface NewProject {
79
+ slug: string;
80
+ displayName: string;
81
+ rootPath: string;
82
+ encodedDir: string;
83
+ type?: ProjectType;
84
+ status?: ProjectStatus;
85
+ createdAt: number;
86
+ updatedAt: number;
87
+ }
88
+ /** Insert a project row, retrying with a numeric slug suffix on collision. */
89
+ interface NewProjectWithSlugRetry {
90
+ baseSlug: string;
91
+ displayName: string;
92
+ rootPath: string;
93
+ encodedDir: string;
94
+ createdAt: number;
95
+ updatedAt: number;
96
+ }
97
+ interface NewSession {
98
+ projectId: number;
99
+ number: number;
100
+ date: string;
101
+ slug: string;
102
+ title: string;
103
+ filename: string;
104
+ status?: SessionStatus;
105
+ createdAt: number;
106
+ }
107
+ interface NewCompactionLogEntry {
108
+ projectId: number;
109
+ sessionId: number | null;
110
+ trigger: CompactionTrigger;
111
+ filesWritten: string;
112
+ tokenCount: number | null;
113
+ createdAt: number;
114
+ }
115
+ interface ListProjectsOptions {
116
+ status?: ProjectStatus;
117
+ /** WHERE status != 'archived' */
118
+ excludeArchived?: boolean;
119
+ tagName?: string;
120
+ orderBy?: "status_updated" | "updated_desc" | "slug" | "id";
121
+ limit?: number;
122
+ }
123
+ interface ListProjectsByPathLengthOptions {
124
+ excludeArchived?: boolean;
125
+ }
126
+ interface ListProjectsWithStatsOptions {
127
+ status?: ProjectStatus;
128
+ tagId?: number;
129
+ orderBy?: "status_updated" | "updated_desc";
130
+ }
131
+ interface ListNamedProjectsOptions {
132
+ /** LEFT JOIN aliases instead of JOIN, so unnamed projects are included too. */
133
+ includeUnnamed?: boolean;
134
+ }
135
+ interface ListSessionsOptions {
136
+ projectId?: number;
137
+ status?: SessionStatus | string;
138
+ limit?: number;
139
+ }
140
+ interface ListSessionsForProjectOptions {
141
+ orderBy?: "number_asc" | "created_desc";
142
+ limit?: number;
143
+ }
144
+ interface RegistryBackend {
145
+ readonly backendType: "sqlite" | "postgres";
146
+ close(): Promise<void>;
147
+ /**
148
+ * Erase every row from every registry table (projects, sessions, tags,
149
+ * project_tags, session_tags, aliases, links, compaction_log). Used by
150
+ * `pai registry rebuild`. Does not touch schema/DDL — only data.
151
+ */
152
+ resetRegistry(): Promise<void>;
153
+ getProjectById(id: number): Promise<Project | null>;
154
+ /** Exact slug match; caseInsensitive uses lower(slug) = lower(?). excludeId excludes a row by id (conflict checks). */
155
+ getProjectBySlug(slug: string, opts?: {
156
+ caseInsensitive?: boolean;
157
+ excludeId?: number;
158
+ }): Promise<Project | null>;
159
+ getProjectByAlias(alias: string, opts?: {
160
+ caseInsensitive?: boolean;
161
+ }): Promise<Project | null>;
162
+ getProjectByRootPath(rootPath: string, opts?: {
163
+ excludeId?: number;
164
+ }): Promise<Project | null>;
165
+ getProjectByEncodedDir(encodedDir: string, opts?: {
166
+ excludeId?: number;
167
+ }): Promise<Project | null>;
168
+ /** status='active' AND cwd LIKE root_path || '%' ORDER BY length(root_path) DESC LIMIT 1. */
169
+ findProjectByCwdPrefix(cwd: string): Promise<Project | null>;
170
+ listProjects(opts?: ListProjectsOptions): Promise<Project[]>;
171
+ /** All projects ordered by LENGTH(root_path) DESC, for caller-side prefix matching. */
172
+ listProjectsByPathLengthDesc(opts?: ListProjectsByPathLengthOptions): Promise<Project[]>;
173
+ listProjectsWithSessionStats(opts?: ListProjectsWithStatsOptions): Promise<ProjectWithSessionStats[]>;
174
+ /** Projects joined to their curated alias ("name"), status='active'. */
175
+ listNamedProjects(opts?: ListNamedProjectsOptions): Promise<Array<ProjectWithSessionStats & {
176
+ name: string | null;
177
+ }>>;
178
+ searchProjects(query: string, limit?: number): Promise<Project[]>;
179
+ countProjects(opts?: {
180
+ status?: ProjectStatus;
181
+ }): Promise<number>;
182
+ getMostRecentProjectUpdatedAt(): Promise<number | null>;
183
+ countChildProjects(parentId: number): Promise<number>;
184
+ /** Sibling projects (slug variants) with at least one session, for split-identity detection. */
185
+ findSiblingProjectsBySlugPattern(excludeProjectId: number, slug: string, limit?: number): Promise<Array<{
186
+ slug: string;
187
+ root_path: string;
188
+ session_count: number;
189
+ }>>;
190
+ createProject(input: NewProject): Promise<Project>;
191
+ createProjectWithSlugRetry(input: NewProjectWithSlugRetry): Promise<{
192
+ id: number;
193
+ slug: string;
194
+ created: boolean;
195
+ }>;
196
+ updateProjectPath(id: number, patch: {
197
+ rootPath?: string;
198
+ encodedDir?: string;
199
+ }, updatedAt?: number): Promise<void>;
200
+ updateProjectStatus(id: number, status: ProjectStatus, opts?: {
201
+ archivedAt?: number | null;
202
+ updatedAt?: number;
203
+ requireCurrentStatus?: ProjectStatus;
204
+ }): Promise<void>;
205
+ updateProjectDisplayName(id: number, displayName: string, updatedAt?: number): Promise<void>;
206
+ updateProjectType(id: number, type: ProjectType, updatedAt?: number): Promise<void>;
207
+ updateProjectSessionConfig(id: number, config: string | null, updatedAt?: number): Promise<void>;
208
+ updateProjectClaudeNotesDir(id: number, dir: string | null, updatedAt?: number): Promise<void>;
209
+ updateProjectObsidianLink(id: number, link: string | null, updatedAt?: number): Promise<void>;
210
+ updateProjectSlug(id: number, slug: string, updatedAt: number): Promise<void>;
211
+ /** UPDATE projects SET parent_id = toParentId WHERE parent_id = fromParentId. Returns rows changed. */
212
+ reassignProjectParent(fromParentId: number, toParentId: number): Promise<number>;
213
+ deleteProject(id: number): Promise<void>;
214
+ /** Atomic cascade: links, compaction_log, project_tags, aliases, sessions, then the project row. */
215
+ deleteProjectCascade(id: number): Promise<void>;
216
+ listTagsForProject(projectId: number): Promise<string[]>;
217
+ listAllTags(): Promise<Array<{
218
+ id: number;
219
+ name: string;
220
+ }>>;
221
+ /** INSERT OR IGNORE then SELECT id — returns the tag's id either way. */
222
+ upsertTag(name: string): Promise<number>;
223
+ addProjectTag(projectId: number, tagId: number): Promise<void>;
224
+ projectHasTag(projectId: number, tagId: number): Promise<boolean>;
225
+ deleteProjectTag(projectId: number, tagId: number): Promise<void>;
226
+ reassignProjectTag(fromProjectId: number, toProjectId: number, tagId: number): Promise<void>;
227
+ listProjectTagIds(projectId: number): Promise<number[]>;
228
+ countProjectTagsForProject(projectId: number): Promise<number>;
229
+ /** INSERT OR IGNORE INTO project_tags SELECT toProjectId, tag_id FROM project_tags WHERE project_id = fromProjectId. */
230
+ copyProjectTags(fromProjectId: number, toProjectId: number): Promise<void>;
231
+ deleteProjectTagsForProject(projectId: number): Promise<void>;
232
+ /** Look up the project_id an alias resolves to, or null. */
233
+ resolveAlias(alias: string): Promise<number | null>;
234
+ listAliasesForProject(projectId: number): Promise<string[]>;
235
+ addAlias(alias: string, projectId: number): Promise<void>;
236
+ removeAlias(alias: string): Promise<void>;
237
+ countAliasesForProject(projectId: number): Promise<number>;
238
+ /** Bulk UPDATE aliases SET project_id = toProjectId WHERE project_id = fromProjectId. */
239
+ moveProjectAliases(fromProjectId: number, toProjectId: number): Promise<void>;
240
+ /** Repoint a single alias to another project (used when folding duplicates). */
241
+ reassignAlias(alias: string, toProjectId: number): Promise<void>;
242
+ /** aliases JOIN projects, for task-owner resolution. Excludes archived projects. */
243
+ listAliasMap(): Promise<Array<{
244
+ alias: string;
245
+ slug: string;
246
+ root_path: string;
247
+ }>>;
248
+ getSessionById(id: number): Promise<Session | null>;
249
+ getSessionByNumber(projectId: number, number: number): Promise<Session | null>;
250
+ getLatestSessionForProject(projectId: number): Promise<Session | null>;
251
+ getMaxSessionNumber(projectId: number): Promise<number>;
252
+ listSessionsForProject(projectId: number, opts?: ListSessionsForProjectOptions): Promise<Session[]>;
253
+ /** Sessions joined to their project's slug/display_name, with optional project/status filters. */
254
+ listSessions(opts?: ListSessionsOptions): Promise<SessionWithProject[]>;
255
+ findSessionByFilename(projectId: number, filename: string): Promise<{
256
+ id: number;
257
+ } | null>;
258
+ sessionNumberTaken(projectId: number, number: number): Promise<boolean>;
259
+ createSession(input: NewSession): Promise<Session>;
260
+ /** Insert only if (project_id, number) is free. Returns true if newly inserted. */
261
+ upsertSessionIfAbsent(input: NewSession): Promise<boolean>;
262
+ updateSessionMeta(id: number, patch: {
263
+ slug?: string;
264
+ title?: string;
265
+ filename?: string;
266
+ }): Promise<void>;
267
+ updateSessionNumber(id: number, number: number, opts?: {
268
+ filename?: string;
269
+ }): Promise<void>;
270
+ updateSessionFilename(id: number, filename: string): Promise<void>;
271
+ /** Sets status, and closed_at when opts.closedAt is passed (session-stop/pre-compact hooks). */
272
+ updateSessionStatus(id: number, status: SessionStatus, opts?: {
273
+ closedAt?: number;
274
+ }): Promise<void>;
275
+ moveSessionToProject(id: number, projectId: number, opts?: {
276
+ number?: number;
277
+ }): Promise<void>;
278
+ deleteSession(id: number): Promise<void>;
279
+ /** Backfill claude_session_id/token_count/closed_at/status from dropId into keepId (COALESCE semantics), then leaves dropId untouched — caller deletes it separately via deleteSession. */
280
+ backfillFoldedSession(keepId: number, dropId: number): Promise<void>;
281
+ countSessionsForProject(projectId: number): Promise<number>;
282
+ /** Total session count across all projects. */
283
+ countSessions(): Promise<number>;
284
+ getMostRecentSessionDate(projectId: number): Promise<string | null>;
285
+ getMostRecentSessionCreatedAt(): Promise<number | null>;
286
+ listSessionTagIds(sessionId: number): Promise<number[]>;
287
+ sessionHasTag(sessionId: number, tagId: number): Promise<boolean>;
288
+ addSessionTag(sessionId: number, tagId: number): Promise<void>;
289
+ deleteSessionTag(sessionId: number, tagId: number): Promise<void>;
290
+ reassignSessionTag(fromSessionId: number, toSessionId: number, tagId: number): Promise<void>;
291
+ listTagsForSession(sessionId: number): Promise<string[]>;
292
+ addLink(input: {
293
+ sessionId: number;
294
+ targetProjectId: number;
295
+ linkType: LinkType;
296
+ createdAt: number;
297
+ }): Promise<void>;
298
+ listLinksForSession(sessionId: number): Promise<Array<{
299
+ id: number;
300
+ target_project_id: number;
301
+ }>>;
302
+ listLinksForProject(projectId: number): Promise<Array<{
303
+ id: number;
304
+ session_id: number;
305
+ }>>;
306
+ linkExists(sessionId: number, targetProjectId: number): Promise<boolean>;
307
+ deleteLink(id: number): Promise<void>;
308
+ deleteLinksTargetingProject(projectId: number): Promise<void>;
309
+ /** DELETE FROM links WHERE session_id IN (SELECT id FROM sessions WHERE project_id = ?). */
310
+ deleteLinksFromProjectSessions(projectId: number): Promise<void>;
311
+ retargetLink(id: number, targetProjectId: number): Promise<void>;
312
+ moveLinkToSession(id: number, sessionId: number): Promise<void>;
313
+ /** Bulk UPDATE OR IGNORE links SET target_project_id = toProjectId WHERE target_project_id = fromProjectId. */
314
+ reassignLinksTarget(fromProjectId: number, toProjectId: number): Promise<void>;
315
+ countLinksForProject(projectId: number): Promise<number>;
316
+ /** Self-links created by a merge: DELETE FROM links WHERE target_project_id = ? AND session_id IN (SELECT id FROM sessions WHERE project_id = ?), same id both sides. */
317
+ deleteSelfLinksForProject(projectId: number): Promise<void>;
318
+ appendCompactionLog(entry: NewCompactionLogEntry): Promise<void>;
319
+ countCompactionLogsForProject(projectId: number): Promise<number>;
320
+ /** Returns rows changed. */
321
+ moveCompactionLogsByProject(fromProjectId: number, toProjectId: number): Promise<number>;
322
+ moveCompactionLogsBySession(fromSessionId: number, toSessionId: number): Promise<void>;
323
+ deleteCompactionLogsForProject(projectId: number): Promise<void>;
324
+ planProjectMerge(fromSlug: string, intoSlug: string): Promise<MergePlan>;
325
+ applyProjectMerge(plan: MergePlan): Promise<void>;
326
+ }
30
327
  //#endregion
31
328
  //#region src/registry/migrate.d.ts
32
329
  /**
@@ -82,16 +379,16 @@ interface MigrationResult {
82
379
  errors: string[];
83
380
  }
84
381
  /**
85
- * Migrate the existing JSON session-registry into the SQLite registry.
382
+ * Migrate the existing JSON session-registry into the registry backend.
86
383
  *
87
- * @param db Open better-sqlite3 Database (target).
384
+ * @param backend Target RegistryBackend (SQLite or Postgres).
88
385
  * @param registryPath Path to session-registry.json.
89
386
  * Defaults to ~/.claude/session-registry.json.
90
387
  *
91
388
  * The migration is idempotent: projects and sessions that already exist
92
389
  * (matched by slug / project_id+number) are silently skipped.
93
390
  */
94
- declare function migrateFromJson(db: Database, registryPath?: string): MigrationResult;
391
+ declare function migrateFromJson(backend: RegistryBackend, registryPath?: string): Promise<MigrationResult>;
95
392
  //#endregion
96
393
  //#region src/registry/pai-marker.d.ts
97
394
  interface PaiMarker {
@@ -135,34 +432,6 @@ declare function readPaiMarker(projectRoot: string): {
135
432
  */
136
433
  declare function discoverPaiMarkers(searchDirs: string[]): PaiMarker[];
137
434
  //#endregion
138
- //#region src/memory/schema.d.ts
139
- declare const FEDERATION_SCHEMA_SQL = "\nPRAGMA journal_mode = WAL;\nPRAGMA foreign_keys = ON;\n\nCREATE TABLE IF NOT EXISTS memory_files (\n project_id INTEGER NOT NULL,\n path TEXT NOT NULL,\n source TEXT NOT NULL DEFAULT 'memory',\n tier TEXT NOT NULL DEFAULT 'topic',\n hash TEXT NOT NULL,\n mtime INTEGER NOT NULL,\n size INTEGER NOT NULL,\n PRIMARY KEY (project_id, path)\n);\n\nCREATE TABLE IF NOT EXISTS memory_chunks (\n id TEXT PRIMARY KEY,\n project_id INTEGER NOT NULL,\n source TEXT NOT NULL DEFAULT 'memory',\n tier TEXT NOT NULL DEFAULT 'topic',\n path TEXT NOT NULL,\n start_line INTEGER NOT NULL,\n end_line INTEGER NOT NULL,\n hash TEXT NOT NULL,\n text TEXT NOT NULL,\n updated_at INTEGER NOT NULL,\n last_accessed_at INTEGER,\n relevance_score REAL DEFAULT 0.5,\n embedding BLOB\n);\n\nCREATE VIRTUAL TABLE IF NOT EXISTS memory_fts USING fts5(\n text,\n id UNINDEXED,\n project_id UNINDEXED,\n path UNINDEXED,\n source UNINDEXED,\n tier UNINDEXED,\n start_line UNINDEXED,\n end_line UNINDEXED\n);\n\nCREATE INDEX IF NOT EXISTS idx_mc_project ON memory_chunks(project_id);\nCREATE INDEX IF NOT EXISTS idx_mc_source ON memory_chunks(project_id, source);\nCREATE INDEX IF NOT EXISTS idx_mc_tier ON memory_chunks(tier);\nCREATE INDEX IF NOT EXISTS idx_mf_project ON memory_files(project_id);\n\nCREATE TABLE IF NOT EXISTS kg_entities (\n entity_id TEXT PRIMARY KEY,\n tenant_id TEXT NOT NULL DEFAULT 'default',\n name TEXT NOT NULL,\n type TEXT NOT NULL DEFAULT 'unknown',\n description TEXT,\n first_seen INTEGER,\n last_seen INTEGER,\n mention_count INTEGER NOT NULL DEFAULT 1,\n feedback_weight REAL NOT NULL DEFAULT 0.5,\n UNIQUE(tenant_id, entity_id)\n);\n\nCREATE INDEX IF NOT EXISTS idx_kge_tenant ON kg_entities(tenant_id);\nCREATE INDEX IF NOT EXISTS idx_kge_name ON kg_entities(tenant_id, name);\nCREATE INDEX IF NOT EXISTS idx_kge_type ON kg_entities(tenant_id, type);\n";
140
- /**
141
- * Apply the full federation schema to an open database.
142
- *
143
- * Idempotent — all statements use IF NOT EXISTS so calling this on an
144
- * already-initialised database is safe.
145
- *
146
- * Also runs any necessary migrations for existing databases (e.g. adding the
147
- * embedding column to an older schema that was created without it).
148
- */
149
- declare function initializeFederationSchema(db: Database): void;
150
- //#endregion
151
- //#region src/memory/db.d.ts
152
- /**
153
- * Open (or create) the PAI federation database.
154
- *
155
- * @param path Absolute path to federation.db. Defaults to PAI_HOME/federation.db
156
- * (falling back to the pre-2026-09-19 ~/.pai/federation.db).
157
- * @returns An open better-sqlite3 Database instance.
158
- *
159
- * Side effects on first call:
160
- * - Creates the parent directory if it does not exist.
161
- * - Enables WAL journal mode.
162
- * - Runs initializeFederationSchema() to ensure tables exist.
163
- */
164
- declare function openFederation(path?: string): Database$1;
165
- //#endregion
166
435
  //#region src/memory/chunker.d.ts
167
436
  /**
168
437
  * Markdown text chunker for the PAI memory engine.
@@ -218,35 +487,6 @@ interface IndexResult {
218
487
  filesSkipped: number;
219
488
  }
220
489
  //#endregion
221
- //#region src/memory/indexer/sync.d.ts
222
- /**
223
- * Index a single file into the federation database.
224
- *
225
- * @returns true if the file was re-indexed (changed or new), false if skipped.
226
- */
227
- declare function indexFile(db: Database, projectId: number, rootPath: string, relativePath: string, source: string, tier: string): boolean;
228
- /**
229
- * Index all memory, Notes, and content files for a single registered project.
230
- *
231
- * Scans:
232
- * - {rootPath}/MEMORY.md → source='memory', tier='evergreen'
233
- * - {rootPath}/memory/ → source='memory', tier from detectTier()
234
- * - {rootPath}/Notes/ → source='notes', tier='session'
235
- * - {rootPath}/**\/*.md → source='content', tier='topic' (all other .md files, recursive)
236
- * - {claudeNotesDir}/ → source='notes', tier='session' (if set and different)
237
- */
238
- declare function indexProject(db: Database, projectId: number, rootPath: string, claudeNotesDir?: string | null): Promise<IndexResult>;
239
- /**
240
- * Index all active projects registered in the registry DB.
241
- *
242
- * Async: yields to the event loop between each project so that the daemon's
243
- * Unix socket server can process IPC requests (e.g. status) while indexing.
244
- */
245
- declare function indexAll(db: Database, registryDb: Database): Promise<{
246
- projects: number;
247
- result: IndexResult;
248
- }>;
249
- //#endregion
250
490
  //#region src/memory/search.d.ts
251
491
  interface SearchResult {
252
492
  projectId: number;
@@ -275,24 +515,11 @@ interface SearchOptions {
275
515
  minScore?: number;
276
516
  }
277
517
  declare function buildFtsQuery(query: string): string;
278
- /**
279
- * Search across all indexed memory using FTS5 BM25 ranking.
280
- *
281
- * Results are ordered by BM25 score (most relevant first).
282
- * FTS5 bm25() returns negative values; closer to 0 = more relevant.
283
- * We negate the score so callers get positive values where higher = better.
284
- *
285
- * Multilingual note: SQLite FTS5 uses the `unicode61` tokenizer by default,
286
- * which handles Unicode correctly (German umlauts, French accents, etc.) without
287
- * language-specific stemming. No changes needed here — it is already
288
- * multilingual-safe.
289
- */
290
- declare function searchMemory(db: Database, query: string, opts?: SearchOptions): SearchResult[];
291
518
  /**
292
519
  * Populate the projectSlug field on search results by looking up project IDs
293
520
  * in the registry database.
294
521
  */
295
- declare function populateSlugs(results: SearchResult[], registryDb: Database): SearchResult[];
522
+ declare function populateSlugs(results: SearchResult[], registry: RegistryBackend): Promise<SearchResult[]>;
296
523
  //#endregion
297
524
  //#region src/memory/reranker.d.ts
298
525
  /**
@@ -321,5 +548,5 @@ interface RerankOptions {
321
548
  */
322
549
  declare function rerankResults(query: string, results: SearchResult[], opts?: RerankOptions): Promise<SearchResult[]>;
323
550
  //#endregion
324
- export { CREATE_TABLES_SQL, type Chunk, type ChunkOptions, FEDERATION_SCHEMA_SQL, type IndexResult, type MigrationResult, type PaiMarker, type RerankOptions, SCHEMA_VERSION, type SearchOptions, type SearchResult, buildFtsQuery, chunkMarkdown, configureRerankerModel, decodeEncodedDir, detectTier, discoverPaiMarkers, ensurePaiMarker, estimateTokens, indexAll, indexFile, indexProject, initializeFederationSchema, initializeSchema, migrateFromJson, openFederation, openRegistry, parseSessionFilename, populateSlugs, readPaiMarker, rerankResults, searchMemory, slugify };
551
+ export { Chunk, ChunkOptions, IndexResult, MigrationResult, PaiMarker, RerankOptions, SearchOptions, SearchResult, buildFtsQuery, chunkMarkdown, configureRerankerModel, decodeEncodedDir, detectTier, discoverPaiMarkers, ensurePaiMarker, estimateTokens, migrateFromJson, parseSessionFilename, populateSlugs, readPaiMarker, rerankResults, slugify };
325
552
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../src/registry/schema.ts","../src/registry/db.ts","../src/registry/migrate.ts","../src/registry/pai-marker.ts","../src/memory/schema.ts","../src/memory/db.ts","../src/memory/chunker.ts","../src/memory/indexer/helpers.ts","../src/memory/indexer/types.ts","../src/memory/indexer/sync.ts","../src/memory/search.ts","../src/memory/reranker.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../src/registry/merge.ts","../src/storage/registry-interface.ts","../src/registry/migrate.ts","../src/registry/pai-marker.ts","../src/memory/chunker.ts","../src/memory/indexer/helpers.ts","../src/memory/indexer/types.ts","../src/memory/search.ts","../src/memory/reranker.ts"],"mappings":"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"}
package/dist/index.mjs CHANGED
@@ -1,12 +1,8 @@
1
- import { a as SCHEMA_VERSION, i as CREATE_TABLES_SQL, n as openRegistry, o as initializeSchema } from "./db-Ddns80yf.mjs";
2
- import "./utils-CJymHkYm.mjs";
3
- import { a as slugify, i as parseSessionFilename, n as decodeEncodedDir, r as migrateFromJson } from "./migrate-CfERwXhY.mjs";
4
- import { n as ensurePaiMarker, r as readPaiMarker, t as discoverPaiMarkers } from "./pai-marker-B20KqhA8.mjs";
5
- import { a as initializeFederationSchema, i as FEDERATION_SCHEMA_SQL, r as openFederation } from "./db-DJ8rk0VM.mjs";
6
- import { l as chunkMarkdown, r as detectTier, u as estimateTokens } from "./helpers-crDEr6S2.mjs";
7
- import { i as indexProject, n as indexAll, r as indexFile } from "./sync-Btcb6xA4.mjs";
8
- import "./embeddings-DvRKcQyt.mjs";
9
- import { a as searchMemory, i as populateSlugs, n as buildFtsQuery } from "./search-B69cQwDB.mjs";
10
- import { n as rerankResults, t as configureRerankerModel } from "./reranker-HHmhZk6v.mjs";
1
+ import "./utils-C9HsYDpO.mjs";
2
+ import { a as slugify, i as parseSessionFilename, n as decodeEncodedDir, r as migrateFromJson } from "./migrate-BD7D8EEh.mjs";
3
+ import { n as ensurePaiMarker, r as readPaiMarker, t as discoverPaiMarkers } from "./pai-marker-D1MMswkz.mjs";
4
+ import { l as chunkMarkdown, r as detectTier, u as estimateTokens } from "./helpers-D9WkIf9R.mjs";
5
+ import { i as populateSlugs, n as buildFtsQuery } from "./search-BaTbyWjK.mjs";
6
+ import { n as rerankResults, t as configureRerankerModel } from "./reranker-CRVawoEh.mjs";
11
7
 
12
- export { CREATE_TABLES_SQL, FEDERATION_SCHEMA_SQL, SCHEMA_VERSION, buildFtsQuery, chunkMarkdown, configureRerankerModel, decodeEncodedDir, detectTier, discoverPaiMarkers, ensurePaiMarker, estimateTokens, indexAll, indexFile, indexProject, initializeFederationSchema, initializeSchema, migrateFromJson, openFederation, openRegistry, parseSessionFilename, populateSlugs, readPaiMarker, rerankResults, searchMemory, slugify };
8
+ export { buildFtsQuery, chunkMarkdown, configureRerankerModel, decodeEncodedDir, detectTier, discoverPaiMarkers, ensurePaiMarker, estimateTokens, migrateFromJson, parseSessionFilename, populateSlugs, readPaiMarker, rerankResults, slugify };
@@ -0,0 +1 @@
1
+ export { };
@@ -0,0 +1,5 @@
1
+ import { a as parseSessionTitleChunk } from "./helpers-D9WkIf9R.mjs";
2
+ import { i as indexProjectWithBackend, n as indexAllWithBackend, r as indexFileWithBackend, t as embedChunksWithBackend } from "./async-CLvuY7b-.mjs";
3
+ import "./indexer-backend-Cc-_NK3q.mjs";
4
+
5
+ export { embedChunksWithBackend };
@@ -1,4 +1,4 @@
1
- import { i as paiSocketPath } from "./runtime-paths-B0P1TvUr.mjs";
1
+ import { i as paiSocketPath } from "./runtime-paths-BRwDeBEg.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { connect } from "node:net";
4
4
 
@@ -155,4 +155,4 @@ var PaiClient = class {
155
155
 
156
156
  //#endregion
157
157
  export { PaiClient as t };
158
- //# sourceMappingURL=ipc-client-C6NryMMb.mjs.map
158
+ //# sourceMappingURL=ipc-client-Dasm515c.mjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"ipc-client-C6NryMMb.mjs","names":[],"sources":["../src/daemon/ipc-client.ts"],"sourcesContent":["/**\n * ipc-client.ts — IPC client for the PAI Daemon MCP shim\n *\n * PaiClient connects to the Unix Domain Socket served by daemon.ts\n * and forwards tool calls to the daemon. Uses a fresh socket connection per\n * call (connect → write JSON + newline → read response line → parse → destroy).\n * This keeps the client stateless and avoids connection management complexity.\n *\n * Adapted from the Coogle ipc-client pattern (which was adapted from Whazaa).\n */\n\nimport { connect, Socket } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n NotificationConfig,\n NotificationMode,\n NotificationEvent,\n SendResult,\n} from \"../notifications/types.js\";\nimport type { TopicCheckParams, TopicCheckResult } from \"../topics/detector.js\";\nimport type { AutoRouteResult } from \"../session/auto-route.js\";\nimport { paiSocketPath } from \"../runtime-paths.js\";\n\n// ---------------------------------------------------------------------------\n// Protocol types\n// ---------------------------------------------------------------------------\n\n/** Default socket path */\nexport const IPC_SOCKET_PATH = paiSocketPath();\n\n/** Timeout for IPC calls (60 seconds) */\nconst IPC_TIMEOUT_MS = 60_000;\n\ninterface IpcRequest {\n id: string;\n method: string;\n params: Record<string, unknown>;\n}\n\ninterface IpcResponse {\n id: string;\n ok: boolean;\n result?: unknown;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\n/**\n * Thin IPC proxy that forwards tool calls to pai-daemon over a Unix\n * Domain Socket. Each call opens a fresh connection, sends one NDJSON request,\n * reads the response, and closes. Stateless and simple.\n */\nexport class PaiClient {\n private readonly socketPath: string;\n\n constructor(socketPath?: string) {\n this.socketPath = socketPath ?? IPC_SOCKET_PATH;\n }\n\n /**\n * Call a PAI tool by name with the given params.\n * Returns the tool result or throws on error.\n *\n * `timeoutMs` overrides the default 60s wait — for a caller on a hook's\n * critical path (e.g. the threshold-triggered handover enqueue in\n * `cli/commands/session/autosave.ts`) where the actual work happens later,\n * asynchronously, in the daemon's worker loop, and only the cheap\n * enqueue handshake itself should ever be waited on.\n */\n async call(method: string, params: Record<string, unknown>, timeoutMs?: number): Promise<unknown> {\n return this.send(method, params, timeoutMs);\n }\n\n /**\n * Check daemon status.\n */\n async status(): Promise<Record<string, unknown>> {\n const result = await this.send(\"status\", {});\n return result as Record<string, unknown>;\n }\n\n /**\n * Trigger an immediate index run.\n */\n async triggerIndex(): Promise<void> {\n await this.send(\"index_now\", {});\n }\n\n // -------------------------------------------------------------------------\n // Notification methods\n // -------------------------------------------------------------------------\n\n /**\n * Get the current notification config from the daemon.\n */\n async getNotificationConfig(): Promise<{\n config: NotificationConfig;\n activeChannels: string[];\n }> {\n const result = await this.send(\"notification_get_config\", {});\n return result as { config: NotificationConfig; activeChannels: string[] };\n }\n\n /**\n * Patch the notification config on the daemon (and persist to disk).\n */\n async setNotificationConfig(patch: {\n mode?: NotificationMode;\n channels?: Partial<NotificationConfig[\"channels\"]>;\n routing?: Partial<NotificationConfig[\"routing\"]>;\n }): Promise<{ config: NotificationConfig }> {\n const result = await this.send(\"notification_set_config\", patch as Record<string, unknown>);\n return result as { config: NotificationConfig };\n }\n\n /**\n * Send a notification via the daemon (routes to configured channels).\n */\n async sendNotification(payload: {\n event: NotificationEvent;\n message: string;\n title?: string;\n }): Promise<SendResult> {\n const result = await this.send(\"notification_send\", payload as Record<string, unknown>);\n return result as SendResult;\n }\n\n // -------------------------------------------------------------------------\n // Topic detection methods\n // -------------------------------------------------------------------------\n\n /**\n * Check whether the provided context text has drifted to a different project\n * than the session's current routing.\n */\n async topicCheck(params: TopicCheckParams): Promise<TopicCheckResult> {\n const result = await this.send(\"topic_check\", params as unknown as Record<string, unknown>);\n return result as TopicCheckResult;\n }\n\n // -------------------------------------------------------------------------\n // Session routing methods\n // -------------------------------------------------------------------------\n\n /**\n * Automatically detect which project a session belongs to.\n * Tries path match, PAI.md marker walk, then topic detection (if context given).\n */\n async sessionAutoRoute(params: {\n cwd?: string;\n context?: string;\n }): Promise<AutoRouteResult | null> {\n // session_auto_route returns a ToolResult (content array). Extract the text\n // and parse JSON from it.\n const result = await this.send(\"session_auto_route\", params as Record<string, unknown>);\n const toolResult = result as { content?: Array<{ text: string }>; isError?: boolean };\n if (toolResult.isError) return null;\n const text = toolResult.content?.[0]?.text ?? \"\";\n // Text is either JSON (on match) or a human-readable \"no match\" message\n try {\n return JSON.parse(text) as AutoRouteResult;\n } catch {\n return null;\n }\n }\n\n // -------------------------------------------------------------------------\n // Internal transport\n // -------------------------------------------------------------------------\n\n /**\n * Send a single IPC request and wait for the response.\n * Opens a new socket connection per call — simple and reliable.\n */\n private send(\n method: string,\n params: Record<string, unknown>,\n timeoutMs: number = IPC_TIMEOUT_MS\n ): Promise<unknown> {\n const socketPath = this.socketPath;\n\n return new Promise((resolve, reject) => {\n let socket: Socket | null = null;\n let done = false;\n let buffer = \"\";\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function finish(error: Error | null, value?: unknown): void {\n if (done) return;\n done = true;\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n try {\n socket?.destroy();\n } catch {\n // ignore\n }\n if (error) {\n reject(error);\n } else {\n resolve(value);\n }\n }\n\n socket = connect(socketPath, () => {\n const request: IpcRequest = {\n id: randomUUID(),\n method,\n params,\n };\n socket!.write(JSON.stringify(request) + \"\\n\");\n });\n\n socket.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString();\n const nl = buffer.indexOf(\"\\n\");\n if (nl === -1) return;\n\n const line = buffer.slice(0, nl);\n buffer = buffer.slice(nl + 1);\n\n let response: IpcResponse;\n try {\n response = JSON.parse(line) as IpcResponse;\n } catch {\n finish(new Error(`IPC parse error: ${line}`));\n return;\n }\n\n if (!response.ok) {\n finish(new Error(response.error ?? \"IPC call failed\"));\n } else {\n finish(null, response.result);\n }\n });\n\n socket.on(\"error\", (e: NodeJS.ErrnoException) => {\n if (e.code === \"ENOENT\" || e.code === \"ECONNREFUSED\") {\n finish(\n new Error(\n \"PAI daemon not running. Start it with: pai daemon serve\"\n )\n );\n } else {\n finish(e);\n }\n });\n\n socket.on(\"end\", () => {\n if (!done) {\n finish(new Error(\"IPC connection closed before response\"));\n }\n });\n\n timer = setTimeout(() => {\n finish(new Error(`IPC call timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4BA,MAAa,kBAAkB,eAAe;;AAG9C,MAAM,iBAAiB;;;;;;AAwBvB,IAAa,YAAb,MAAuB;CACrB,AAAiB;CAEjB,YAAY,YAAqB;AAC/B,OAAK,aAAa,cAAc;;;;;;;;;;;;CAalC,MAAM,KAAK,QAAgB,QAAiC,WAAsC;AAChG,SAAO,KAAK,KAAK,QAAQ,QAAQ,UAAU;;;;;CAM7C,MAAM,SAA2C;AAE/C,SADe,MAAM,KAAK,KAAK,UAAU,EAAE,CAAC;;;;;CAO9C,MAAM,eAA8B;AAClC,QAAM,KAAK,KAAK,aAAa,EAAE,CAAC;;;;;CAUlC,MAAM,wBAGH;AAED,SADe,MAAM,KAAK,KAAK,2BAA2B,EAAE,CAAC;;;;;CAO/D,MAAM,sBAAsB,OAIgB;AAE1C,SADe,MAAM,KAAK,KAAK,2BAA2B,MAAiC;;;;;CAO7F,MAAM,iBAAiB,SAIC;AAEtB,SADe,MAAM,KAAK,KAAK,qBAAqB,QAAmC;;;;;;CAYzF,MAAM,WAAW,QAAqD;AAEpE,SADe,MAAM,KAAK,KAAK,eAAe,OAA6C;;;;;;CAY7F,MAAM,iBAAiB,QAGa;EAIlC,MAAM,aADS,MAAM,KAAK,KAAK,sBAAsB,OAAkC;AAEvF,MAAI,WAAW,QAAS,QAAO;EAC/B,MAAM,OAAO,WAAW,UAAU,IAAI,QAAQ;AAE9C,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;UACjB;AACN,UAAO;;;;;;;CAYX,AAAQ,KACN,QACA,QACA,YAAoB,gBACF;EAClB,MAAM,aAAa,KAAK;AAExB,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,SAAwB;GAC5B,IAAI,OAAO;GACX,IAAI,SAAS;GACb,IAAI,QAA8C;GAElD,SAAS,OAAO,OAAqB,OAAuB;AAC1D,QAAI,KAAM;AACV,WAAO;AACP,QAAI,UAAU,MAAM;AAClB,kBAAa,MAAM;AACnB,aAAQ;;AAEV,QAAI;AACF,aAAQ,SAAS;YACX;AAGR,QAAI,MACF,QAAO,MAAM;QAEb,SAAQ,MAAM;;AAIlB,YAAS,QAAQ,kBAAkB;IACjC,MAAM,UAAsB;KAC1B,IAAI,YAAY;KAChB;KACA;KACD;AACD,WAAQ,MAAM,KAAK,UAAU,QAAQ,GAAG,KAAK;KAC7C;AAEF,UAAO,GAAG,SAAS,UAAkB;AACnC,cAAU,MAAM,UAAU;IAC1B,MAAM,KAAK,OAAO,QAAQ,KAAK;AAC/B,QAAI,OAAO,GAAI;IAEf,MAAM,OAAO,OAAO,MAAM,GAAG,GAAG;AAChC,aAAS,OAAO,MAAM,KAAK,EAAE;IAE7B,IAAI;AACJ,QAAI;AACF,gBAAW,KAAK,MAAM,KAAK;YACrB;AACN,4BAAO,IAAI,MAAM,oBAAoB,OAAO,CAAC;AAC7C;;AAGF,QAAI,CAAC,SAAS,GACZ,QAAO,IAAI,MAAM,SAAS,SAAS,kBAAkB,CAAC;QAEtD,QAAO,MAAM,SAAS,OAAO;KAE/B;AAEF,UAAO,GAAG,UAAU,MAA6B;AAC/C,QAAI,EAAE,SAAS,YAAY,EAAE,SAAS,eACpC,wBACE,IAAI,MACF,0DACD,CACF;QAED,QAAO,EAAE;KAEX;AAEF,UAAO,GAAG,aAAa;AACrB,QAAI,CAAC,KACH,wBAAO,IAAI,MAAM,wCAAwC,CAAC;KAE5D;AAEF,WAAQ,iBAAiB;AACvB,2BAAO,IAAI,MAAM,4BAA4B,UAAU,IAAI,CAAC;MAC3D,UAAU;IACb"}
1
+ {"version":3,"file":"ipc-client-Dasm515c.mjs","names":[],"sources":["../src/daemon/ipc-client.ts"],"sourcesContent":["/**\n * ipc-client.ts — IPC client for the PAI Daemon MCP shim\n *\n * PaiClient connects to the Unix Domain Socket served by daemon.ts\n * and forwards tool calls to the daemon. Uses a fresh socket connection per\n * call (connect → write JSON + newline → read response line → parse → destroy).\n * This keeps the client stateless and avoids connection management complexity.\n *\n * Adapted from the Coogle ipc-client pattern (which was adapted from Whazaa).\n */\n\nimport { connect, Socket } from \"node:net\";\nimport { randomUUID } from \"node:crypto\";\nimport type {\n NotificationConfig,\n NotificationMode,\n NotificationEvent,\n SendResult,\n} from \"../notifications/types.js\";\nimport type { TopicCheckParams, TopicCheckResult } from \"../topics/detector.js\";\nimport type { AutoRouteResult } from \"../session/auto-route.js\";\nimport { paiSocketPath } from \"../runtime-paths.js\";\n\n// ---------------------------------------------------------------------------\n// Protocol types\n// ---------------------------------------------------------------------------\n\n/** Default socket path */\nexport const IPC_SOCKET_PATH = paiSocketPath();\n\n/** Timeout for IPC calls (60 seconds) */\nconst IPC_TIMEOUT_MS = 60_000;\n\ninterface IpcRequest {\n id: string;\n method: string;\n params: Record<string, unknown>;\n}\n\ninterface IpcResponse {\n id: string;\n ok: boolean;\n result?: unknown;\n error?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Client\n// ---------------------------------------------------------------------------\n\n/**\n * Thin IPC proxy that forwards tool calls to pai-daemon over a Unix\n * Domain Socket. Each call opens a fresh connection, sends one NDJSON request,\n * reads the response, and closes. Stateless and simple.\n */\nexport class PaiClient {\n private readonly socketPath: string;\n\n constructor(socketPath?: string) {\n this.socketPath = socketPath ?? IPC_SOCKET_PATH;\n }\n\n /**\n * Call a PAI tool by name with the given params.\n * Returns the tool result or throws on error.\n *\n * `timeoutMs` overrides the default 60s wait — for a caller on a hook's\n * critical path (e.g. the threshold-triggered handover enqueue in\n * `cli/commands/session/autosave.ts`) where the actual work happens later,\n * asynchronously, in the daemon's worker loop, and only the cheap\n * enqueue handshake itself should ever be waited on.\n */\n async call(method: string, params: Record<string, unknown>, timeoutMs?: number): Promise<unknown> {\n return this.send(method, params, timeoutMs);\n }\n\n /**\n * Check daemon status.\n */\n async status(): Promise<Record<string, unknown>> {\n const result = await this.send(\"status\", {});\n return result as Record<string, unknown>;\n }\n\n /**\n * Trigger an immediate index run.\n */\n async triggerIndex(): Promise<void> {\n await this.send(\"index_now\", {});\n }\n\n // -------------------------------------------------------------------------\n // Notification methods\n // -------------------------------------------------------------------------\n\n /**\n * Get the current notification config from the daemon.\n */\n async getNotificationConfig(): Promise<{\n config: NotificationConfig;\n activeChannels: string[];\n }> {\n const result = await this.send(\"notification_get_config\", {});\n return result as { config: NotificationConfig; activeChannels: string[] };\n }\n\n /**\n * Patch the notification config on the daemon (and persist to disk).\n */\n async setNotificationConfig(patch: {\n mode?: NotificationMode;\n channels?: Partial<NotificationConfig[\"channels\"]>;\n routing?: Partial<NotificationConfig[\"routing\"]>;\n }): Promise<{ config: NotificationConfig }> {\n const result = await this.send(\"notification_set_config\", patch as Record<string, unknown>);\n return result as { config: NotificationConfig };\n }\n\n /**\n * Send a notification via the daemon (routes to configured channels).\n */\n async sendNotification(payload: {\n event: NotificationEvent;\n message: string;\n title?: string;\n }): Promise<SendResult> {\n const result = await this.send(\"notification_send\", payload as Record<string, unknown>);\n return result as SendResult;\n }\n\n // -------------------------------------------------------------------------\n // Topic detection methods\n // -------------------------------------------------------------------------\n\n /**\n * Check whether the provided context text has drifted to a different project\n * than the session's current routing.\n */\n async topicCheck(params: TopicCheckParams): Promise<TopicCheckResult> {\n const result = await this.send(\"topic_check\", params as unknown as Record<string, unknown>);\n return result as TopicCheckResult;\n }\n\n // -------------------------------------------------------------------------\n // Session routing methods\n // -------------------------------------------------------------------------\n\n /**\n * Automatically detect which project a session belongs to.\n * Tries path match, PAI.md marker walk, then topic detection (if context given).\n */\n async sessionAutoRoute(params: {\n cwd?: string;\n context?: string;\n }): Promise<AutoRouteResult | null> {\n // session_auto_route returns a ToolResult (content array). Extract the text\n // and parse JSON from it.\n const result = await this.send(\"session_auto_route\", params as Record<string, unknown>);\n const toolResult = result as { content?: Array<{ text: string }>; isError?: boolean };\n if (toolResult.isError) return null;\n const text = toolResult.content?.[0]?.text ?? \"\";\n // Text is either JSON (on match) or a human-readable \"no match\" message\n try {\n return JSON.parse(text) as AutoRouteResult;\n } catch {\n return null;\n }\n }\n\n // -------------------------------------------------------------------------\n // Internal transport\n // -------------------------------------------------------------------------\n\n /**\n * Send a single IPC request and wait for the response.\n * Opens a new socket connection per call — simple and reliable.\n */\n private send(\n method: string,\n params: Record<string, unknown>,\n timeoutMs: number = IPC_TIMEOUT_MS\n ): Promise<unknown> {\n const socketPath = this.socketPath;\n\n return new Promise((resolve, reject) => {\n let socket: Socket | null = null;\n let done = false;\n let buffer = \"\";\n let timer: ReturnType<typeof setTimeout> | null = null;\n\n function finish(error: Error | null, value?: unknown): void {\n if (done) return;\n done = true;\n if (timer !== null) {\n clearTimeout(timer);\n timer = null;\n }\n try {\n socket?.destroy();\n } catch {\n // ignore\n }\n if (error) {\n reject(error);\n } else {\n resolve(value);\n }\n }\n\n socket = connect(socketPath, () => {\n const request: IpcRequest = {\n id: randomUUID(),\n method,\n params,\n };\n socket!.write(JSON.stringify(request) + \"\\n\");\n });\n\n socket.on(\"data\", (chunk: Buffer) => {\n buffer += chunk.toString();\n const nl = buffer.indexOf(\"\\n\");\n if (nl === -1) return;\n\n const line = buffer.slice(0, nl);\n buffer = buffer.slice(nl + 1);\n\n let response: IpcResponse;\n try {\n response = JSON.parse(line) as IpcResponse;\n } catch {\n finish(new Error(`IPC parse error: ${line}`));\n return;\n }\n\n if (!response.ok) {\n finish(new Error(response.error ?? \"IPC call failed\"));\n } else {\n finish(null, response.result);\n }\n });\n\n socket.on(\"error\", (e: NodeJS.ErrnoException) => {\n if (e.code === \"ENOENT\" || e.code === \"ECONNREFUSED\") {\n finish(\n new Error(\n \"PAI daemon not running. Start it with: pai daemon serve\"\n )\n );\n } else {\n finish(e);\n }\n });\n\n socket.on(\"end\", () => {\n if (!done) {\n finish(new Error(\"IPC connection closed before response\"));\n }\n });\n\n timer = setTimeout(() => {\n finish(new Error(`IPC call timed out after ${timeoutMs}ms`));\n }, timeoutMs);\n });\n }\n}\n"],"mappings":";;;;;;;;;;;;;;;;AA4BA,MAAa,kBAAkB,eAAe;;AAG9C,MAAM,iBAAiB;;;;;;AAwBvB,IAAa,YAAb,MAAuB;CACrB,AAAiB;CAEjB,YAAY,YAAqB;AAC/B,OAAK,aAAa,cAAc;;;;;;;;;;;;CAalC,MAAM,KAAK,QAAgB,QAAiC,WAAsC;AAChG,SAAO,KAAK,KAAK,QAAQ,QAAQ,UAAU;;;;;CAM7C,MAAM,SAA2C;AAE/C,SADe,MAAM,KAAK,KAAK,UAAU,EAAE,CAAC;;;;;CAO9C,MAAM,eAA8B;AAClC,QAAM,KAAK,KAAK,aAAa,EAAE,CAAC;;;;;CAUlC,MAAM,wBAGH;AAED,SADe,MAAM,KAAK,KAAK,2BAA2B,EAAE,CAAC;;;;;CAO/D,MAAM,sBAAsB,OAIgB;AAE1C,SADe,MAAM,KAAK,KAAK,2BAA2B,MAAiC;;;;;CAO7F,MAAM,iBAAiB,SAIC;AAEtB,SADe,MAAM,KAAK,KAAK,qBAAqB,QAAmC;;;;;;CAYzF,MAAM,WAAW,QAAqD;AAEpE,SADe,MAAM,KAAK,KAAK,eAAe,OAA6C;;;;;;CAY7F,MAAM,iBAAiB,QAGa;EAIlC,MAAM,aADS,MAAM,KAAK,KAAK,sBAAsB,OAAkC;AAEvF,MAAI,WAAW,QAAS,QAAO;EAC/B,MAAM,OAAO,WAAW,UAAU,IAAI,QAAQ;AAE9C,MAAI;AACF,UAAO,KAAK,MAAM,KAAK;UACjB;AACN,UAAO;;;;;;;CAYX,AAAQ,KACN,QACA,QACA,YAAoB,gBACF;EAClB,MAAM,aAAa,KAAK;AAExB,SAAO,IAAI,SAAS,SAAS,WAAW;GACtC,IAAI,SAAwB;GAC5B,IAAI,OAAO;GACX,IAAI,SAAS;GACb,IAAI,QAA8C;GAElD,SAAS,OAAO,OAAqB,OAAuB;AAC1D,QAAI,KAAM;AACV,WAAO;AACP,QAAI,UAAU,MAAM;AAClB,kBAAa,MAAM;AACnB,aAAQ;;AAEV,QAAI;AACF,aAAQ,SAAS;YACX;AAGR,QAAI,MACF,QAAO,MAAM;QAEb,SAAQ,MAAM;;AAIlB,YAAS,QAAQ,kBAAkB;IACjC,MAAM,UAAsB;KAC1B,IAAI,YAAY;KAChB;KACA;KACD;AACD,WAAQ,MAAM,KAAK,UAAU,QAAQ,GAAG,KAAK;KAC7C;AAEF,UAAO,GAAG,SAAS,UAAkB;AACnC,cAAU,MAAM,UAAU;IAC1B,MAAM,KAAK,OAAO,QAAQ,KAAK;AAC/B,QAAI,OAAO,GAAI;IAEf,MAAM,OAAO,OAAO,MAAM,GAAG,GAAG;AAChC,aAAS,OAAO,MAAM,KAAK,EAAE;IAE7B,IAAI;AACJ,QAAI;AACF,gBAAW,KAAK,MAAM,KAAK;YACrB;AACN,4BAAO,IAAI,MAAM,oBAAoB,OAAO,CAAC;AAC7C;;AAGF,QAAI,CAAC,SAAS,GACZ,QAAO,IAAI,MAAM,SAAS,SAAS,kBAAkB,CAAC;QAEtD,QAAO,MAAM,SAAS,OAAO;KAE/B;AAEF,UAAO,GAAG,UAAU,MAA6B;AAC/C,QAAI,EAAE,SAAS,YAAY,EAAE,SAAS,eACpC,wBACE,IAAI,MACF,0DACD,CACF;QAED,QAAO,EAAE;KAEX;AAEF,UAAO,GAAG,aAAa;AACrB,QAAI,CAAC,KACH,wBAAO,IAAI,MAAM,wCAAwC,CAAC;KAE5D;AAEF,WAAQ,iBAAiB;AACvB,2BAAO,IAAI,MAAM,4BAA4B,UAAU,IAAI,CAAC;MAC3D,UAAU;IACb"}