@tekmidian/pai 0.15.0 → 0.17.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/README.md +11 -3
  2. package/dist/{auto-route-CLYcToZ5.mjs → auto-route-CdvjEWs5.mjs} +4 -4
  3. package/dist/{auto-route-CLYcToZ5.mjs.map → auto-route-CdvjEWs5.mjs.map} +1 -1
  4. package/dist/auto-route-DkIRampF.mjs +86 -0
  5. package/dist/auto-route-DkIRampF.mjs.map +1 -0
  6. package/dist/{kg-extraction-C8DEUHTS.mjs → checkpoint-block-Bl0HD3U2.mjs} +442 -13
  7. package/dist/checkpoint-block-Bl0HD3U2.mjs.map +1 -0
  8. package/dist/checkpoint-block-C05sK_HK.mjs +1056 -0
  9. package/dist/checkpoint-block-C05sK_HK.mjs.map +1 -0
  10. package/dist/checkpoint-block-CUCG10Uh.mjs +1022 -0
  11. package/dist/checkpoint-block-CUCG10Uh.mjs.map +1 -0
  12. package/dist/checkpoint-block-D5IyLLTr.mjs +1062 -0
  13. package/dist/checkpoint-block-D5IyLLTr.mjs.map +1 -0
  14. package/dist/cli/index.mjs +14 -12
  15. package/dist/cli/index.mjs.map +1 -1
  16. package/dist/cli/program.d.mts.map +1 -1
  17. package/dist/cli/program.mjs +31 -16
  18. package/dist/cli/program.mjs.map +1 -1
  19. package/dist/{clusters-BYPw7vfW.mjs → clusters-CKWDwcMX.mjs} +2 -2
  20. package/dist/{clusters-BYPw7vfW.mjs.map → clusters-CKWDwcMX.mjs.map} +1 -1
  21. package/dist/{config-C8m-tPhP.mjs → config-DGOfoGfm.mjs} +1 -1
  22. package/dist/{config-C8m-tPhP.mjs.map → config-DGOfoGfm.mjs.map} +1 -1
  23. package/dist/daemon/index.mjs +18 -16
  24. package/dist/daemon/index.mjs.map +1 -1
  25. package/dist/{daemon-COSvHTNu.mjs → daemon-1rKbN-fd.mjs} +31 -30
  26. package/dist/{daemon-COSvHTNu.mjs.map → daemon-1rKbN-fd.mjs.map} +1 -1
  27. package/dist/daemon-9AL6Pwh-.mjs +1581 -0
  28. package/dist/daemon-9AL6Pwh-.mjs.map +1 -0
  29. package/dist/daemon-Bbk-_rV6.mjs +1581 -0
  30. package/dist/daemon-Bbk-_rV6.mjs.map +1 -0
  31. package/dist/daemon-BvcaMk4g.mjs +1581 -0
  32. package/dist/daemon-BvcaMk4g.mjs.map +1 -0
  33. package/dist/daemon-CTDEfwcq.mjs +1576 -0
  34. package/dist/daemon-CTDEfwcq.mjs.map +1 -0
  35. package/dist/daemon-ClbfaF60.mjs +1576 -0
  36. package/dist/daemon-ClbfaF60.mjs.map +1 -0
  37. package/dist/daemon-DDQNDgYF.mjs +1576 -0
  38. package/dist/daemon-DDQNDgYF.mjs.map +1 -0
  39. package/dist/daemon-DU8yDWlQ.mjs +1576 -0
  40. package/dist/daemon-DU8yDWlQ.mjs.map +1 -0
  41. package/dist/daemon-NJr4iSW3.mjs +1576 -0
  42. package/dist/daemon-NJr4iSW3.mjs.map +1 -0
  43. package/dist/daemon-mcp/index.mjs +2 -2
  44. package/dist/db-BtuN768f.mjs +206 -0
  45. package/dist/db-BtuN768f.mjs.map +1 -0
  46. package/dist/{db-CmYbAVCD.mjs → db-CYmBWcjh.mjs} +1 -1
  47. package/dist/{db-CmYbAVCD.mjs.map → db-CYmBWcjh.mjs.map} +1 -1
  48. package/dist/{detect-KjycLtXM.mjs → detect-Bf2z-oKB.mjs} +1 -1
  49. package/dist/{detect-KjycLtXM.mjs.map → detect-Bf2z-oKB.mjs.map} +1 -1
  50. package/dist/{detector-ZiOhHszd.mjs → detector-Bwzm3E_x.mjs} +2 -2
  51. package/dist/{detector-ZiOhHszd.mjs.map → detector-Bwzm3E_x.mjs.map} +1 -1
  52. package/dist/detector-rq9JGTmS.mjs +74 -0
  53. package/dist/detector-rq9JGTmS.mjs.map +1 -0
  54. package/dist/embeddings-Bn86ssxR.mjs +119 -0
  55. package/dist/embeddings-Bn86ssxR.mjs.map +1 -0
  56. package/dist/{embeddings-BJPOcbik.mjs → embeddings-DGRAPAYb.mjs} +1 -1
  57. package/dist/{embeddings-BJPOcbik.mjs.map → embeddings-DGRAPAYb.mjs.map} +1 -1
  58. package/dist/{factory-Q88X1bAN.mjs → factory-0-57Ac-7.mjs} +8 -5
  59. package/dist/{factory-Q88X1bAN.mjs.map → factory-0-57Ac-7.mjs.map} +1 -1
  60. package/dist/factory-HcQsQqh0.mjs +72 -0
  61. package/dist/factory-HcQsQqh0.mjs.map +1 -0
  62. package/dist/factory-PDXQdkLO.mjs +72 -0
  63. package/dist/factory-PDXQdkLO.mjs.map +1 -0
  64. package/dist/{helpers-IjZkXBhj.mjs → helpers-crDEr6S2.mjs} +1 -1
  65. package/dist/{helpers-IjZkXBhj.mjs.map → helpers-crDEr6S2.mjs.map} +1 -1
  66. package/dist/hooks/capture-all-events.mjs.map +1 -1
  67. package/dist/hooks/capture-session-summary.mjs.map +1 -1
  68. package/dist/hooks/capture-tool-output.mjs.map +1 -1
  69. package/dist/hooks/cleanup-session-files.mjs.map +1 -1
  70. package/dist/hooks/context-compression-hook.mjs +336 -48
  71. package/dist/hooks/context-compression-hook.mjs.map +4 -4
  72. package/dist/hooks/initialize-session.mjs.map +1 -1
  73. package/dist/hooks/inject-observations.mjs.map +1 -1
  74. package/dist/hooks/load-core-context.mjs.map +1 -1
  75. package/dist/hooks/load-project-context.mjs +188 -6
  76. package/dist/hooks/load-project-context.mjs.map +4 -4
  77. package/dist/hooks/observe.mjs.map +1 -1
  78. package/dist/hooks/post-compact-inject.mjs.map +1 -1
  79. package/dist/hooks/security-validator.mjs.map +1 -1
  80. package/dist/hooks/session-commands.mjs.map +1 -1
  81. package/dist/hooks/stop-hook.mjs +331 -43
  82. package/dist/hooks/stop-hook.mjs.map +4 -4
  83. package/dist/hooks/subagent-stop-hook.mjs.map +1 -1
  84. package/dist/hooks/sync-todo-to-md.mjs.map +1 -1
  85. package/dist/hooks/update-tab-on-action.mjs.map +1 -1
  86. package/dist/hooks/update-tab-titles.mjs.map +1 -1
  87. package/dist/hooks/whisper-rules.mjs.map +1 -1
  88. package/dist/index.d.mts +0 -9
  89. package/dist/index.d.mts.map +1 -1
  90. package/dist/index.mjs +10 -9
  91. package/dist/indexer-AEcT8wHf.mjs +1 -0
  92. package/dist/{indexer-backend-Cm5RS7y0.mjs → indexer-backend-BQZXoarl.mjs} +3 -3
  93. package/dist/{indexer-backend-Cm5RS7y0.mjs.map → indexer-backend-BQZXoarl.mjs.map} +1 -1
  94. package/dist/indexer-backend-BmaS2VcD.mjs +299 -0
  95. package/dist/indexer-backend-BmaS2VcD.mjs.map +1 -0
  96. package/dist/indexer-backend-COrJ5rjS.mjs +299 -0
  97. package/dist/indexer-backend-COrJ5rjS.mjs.map +1 -0
  98. package/dist/indexer-backend-NwD7TBGh.mjs +301 -0
  99. package/dist/indexer-backend-NwD7TBGh.mjs.map +1 -0
  100. package/dist/{ipc-client-CoyUHPod.mjs → ipc-client-vO2GV325.mjs} +1 -1
  101. package/dist/{ipc-client-CoyUHPod.mjs.map → ipc-client-vO2GV325.mjs.map} +1 -1
  102. package/dist/{kg-entity-LXblD7LZ.mjs → kg-entity-DbOMPdF9.mjs} +1 -1
  103. package/dist/{kg-entity-LXblD7LZ.mjs.map → kg-entity-DbOMPdF9.mjs.map} +1 -1
  104. package/dist/{latent-ideas-RyC6eyqI.mjs → latent-ideas-BwM3WdBp.mjs} +4 -4
  105. package/dist/{latent-ideas-RyC6eyqI.mjs.map → latent-ideas-BwM3WdBp.mjs.map} +1 -1
  106. package/dist/latent-ideas-C6IFFT0-.mjs +191 -0
  107. package/dist/latent-ideas-C6IFFT0-.mjs.map +1 -0
  108. package/dist/{main-resolver-uFxNiDy7.mjs → main-resolver-DimnS2qP.mjs} +22 -22
  109. package/dist/{main-resolver-uFxNiDy7.mjs.map → main-resolver-DimnS2qP.mjs.map} +1 -1
  110. package/dist/{migrate-B02wDDgS.mjs → migrate-fLD6rAdO.mjs} +2 -2
  111. package/dist/{migrate-B02wDDgS.mjs.map → migrate-fLD6rAdO.mjs.map} +1 -1
  112. package/dist/{neighborhood-CklGIB8r.mjs → neighborhood-CzRNG2Oy.mjs} +2 -2
  113. package/dist/{neighborhood-CklGIB8r.mjs.map → neighborhood-CzRNG2Oy.mjs.map} +1 -1
  114. package/dist/neighborhood-DZY0wkpE.mjs +135 -0
  115. package/dist/neighborhood-DZY0wkpE.mjs.map +1 -0
  116. package/dist/{note-context-qvZlVXVO.mjs → note-context-CrfMbr4R.mjs} +1 -1
  117. package/dist/{note-context-qvZlVXVO.mjs.map → note-context-CrfMbr4R.mjs.map} +1 -1
  118. package/dist/{pai-marker-HVBwwBW-.mjs → pai-marker-B20KqhA8.mjs} +44 -2
  119. package/dist/pai-marker-B20KqhA8.mjs.map +1 -0
  120. package/dist/pick-B0q5cy79.mjs +11785 -0
  121. package/dist/pick-B0q5cy79.mjs.map +1 -0
  122. package/dist/{pick-r95zvydr.mjs → pick-B3zEYjin.mjs} +2288 -497
  123. package/dist/pick-B3zEYjin.mjs.map +1 -0
  124. package/dist/pick-BHE9_iA0.mjs +11947 -0
  125. package/dist/pick-BHE9_iA0.mjs.map +1 -0
  126. package/dist/pick-BaTjoNqM.mjs +11544 -0
  127. package/dist/pick-BaTjoNqM.mjs.map +1 -0
  128. package/dist/pick-C6JbZfN4.mjs +11893 -0
  129. package/dist/pick-C6JbZfN4.mjs.map +1 -0
  130. package/dist/pick-CK-bJyjp.mjs +11883 -0
  131. package/dist/pick-CK-bJyjp.mjs.map +1 -0
  132. package/dist/pick-CLBkGHyI.mjs +11826 -0
  133. package/dist/pick-CLBkGHyI.mjs.map +1 -0
  134. package/dist/pick-CTOif21h.mjs +11544 -0
  135. package/dist/pick-CTOif21h.mjs.map +1 -0
  136. package/dist/pick-Ck2cdQgD.mjs +11893 -0
  137. package/dist/pick-Ck2cdQgD.mjs.map +1 -0
  138. package/dist/pick-Cr4nJzHA.mjs +11914 -0
  139. package/dist/pick-Cr4nJzHA.mjs.map +1 -0
  140. package/dist/pick-D4dFfKAu.mjs +11893 -0
  141. package/dist/pick-D4dFfKAu.mjs.map +1 -0
  142. package/dist/pick-D7-lYiGX.mjs +11543 -0
  143. package/dist/pick-D7-lYiGX.mjs.map +1 -0
  144. package/dist/pick-DMjCY0np.mjs +11875 -0
  145. package/dist/pick-DMjCY0np.mjs.map +1 -0
  146. package/dist/pick-DbX4OrCP.mjs +11543 -0
  147. package/dist/pick-DbX4OrCP.mjs.map +1 -0
  148. package/dist/pick-iCiPjlnC.mjs +11893 -0
  149. package/dist/pick-iCiPjlnC.mjs.map +1 -0
  150. package/dist/pick-sF9GnQUS.mjs +11893 -0
  151. package/dist/pick-sF9GnQUS.mjs.map +1 -0
  152. package/dist/pick-yHKUrnfG.mjs +11793 -0
  153. package/dist/pick-yHKUrnfG.mjs.map +1 -0
  154. package/dist/postgres-BJxiqtqg.mjs +891 -0
  155. package/dist/postgres-BJxiqtqg.mjs.map +1 -0
  156. package/dist/{postgres-B451Hnkm.mjs → postgres-zjKqPl4X.mjs} +2 -2
  157. package/dist/{postgres-B451Hnkm.mjs.map → postgres-zjKqPl4X.mjs.map} +1 -1
  158. package/dist/{query-feedback-fapbqRgh.mjs → query-feedback-BoY8_Dbb.mjs} +1 -1
  159. package/dist/{query-feedback-fapbqRgh.mjs.map → query-feedback-BoY8_Dbb.mjs.map} +1 -1
  160. package/dist/{reranker-C08R99zn.mjs → reranker-CMNZcfVx.mjs} +1 -1
  161. package/dist/{reranker-C08R99zn.mjs.map → reranker-CMNZcfVx.mjs.map} +1 -1
  162. package/dist/{search-HcdKtMla.mjs → search-CpTv1I24.mjs} +3 -3
  163. package/dist/{search-HcdKtMla.mjs.map → search-CpTv1I24.mjs.map} +1 -1
  164. package/dist/search-i2nlQ-JM.mjs +298 -0
  165. package/dist/search-i2nlQ-JM.mjs.map +1 -0
  166. package/dist/skills/End/SKILL.md +78 -0
  167. package/dist/skills/Pause/SKILL.md +84 -0
  168. package/dist/sqlite-CZ0LFili.mjs +271 -0
  169. package/dist/sqlite-CZ0LFili.mjs.map +1 -0
  170. package/dist/{sqlite-DQpY1Esi.mjs → sqlite-ChSCYwiC.mjs} +3 -3
  171. package/dist/{sqlite-DQpY1Esi.mjs.map → sqlite-ChSCYwiC.mjs.map} +1 -1
  172. package/dist/sqlite-Nw8ZW5Rj.mjs +271 -0
  173. package/dist/sqlite-Nw8ZW5Rj.mjs.map +1 -0
  174. package/dist/{state-BIlxNRUn.mjs → state-BXIdbxDs.mjs} +1 -1
  175. package/dist/{state-BIlxNRUn.mjs.map → state-BXIdbxDs.mjs.map} +1 -1
  176. package/dist/{stop-words-BwplsQ3z.mjs → stop-words-BaMEGVeY.mjs} +1 -1
  177. package/dist/{stop-words-BwplsQ3z.mjs.map → stop-words-BaMEGVeY.mjs.map} +1 -1
  178. package/dist/{sync-uPR4g438.mjs → sync--BoxBBok.mjs} +6 -205
  179. package/dist/sync--BoxBBok.mjs.map +1 -0
  180. package/dist/sync-CmBKOL3K.mjs +310 -0
  181. package/dist/sync-CmBKOL3K.mjs.map +1 -0
  182. package/dist/{themes-Cg8oG9Ra.mjs → themes-BBOlGXAg.mjs} +3 -3
  183. package/dist/{themes-Cg8oG9Ra.mjs.map → themes-BBOlGXAg.mjs.map} +1 -1
  184. package/dist/themes-nvRM8v84.mjs +148 -0
  185. package/dist/themes-nvRM8v84.mjs.map +1 -0
  186. package/dist/tools-B6BmaAvz.mjs +1939 -0
  187. package/dist/tools-B6BmaAvz.mjs.map +1 -0
  188. package/dist/tools-CAIY8TAb.mjs +1939 -0
  189. package/dist/tools-CAIY8TAb.mjs.map +1 -0
  190. package/dist/{tools-Op3C2Nm6.mjs → tools-CznjzfYz.mjs} +26 -26
  191. package/dist/{tools-Op3C2Nm6.mjs.map → tools-CznjzfYz.mjs.map} +1 -1
  192. package/dist/{trace-CLK-NPkb.mjs → trace-B8oz1ok0.mjs} +1 -1
  193. package/dist/{trace-CLK-NPkb.mjs.map → trace-B8oz1ok0.mjs.map} +1 -1
  194. package/dist/{utils-CqqgB0dH.mjs → utils-BAxjW3j8.mjs} +1 -1
  195. package/dist/{utils-CqqgB0dH.mjs.map → utils-BAxjW3j8.mjs.map} +1 -1
  196. package/dist/{vault-indexer-Dn_BccVK.mjs → vault-indexer-DrttVeEk.mjs} +2 -2
  197. package/dist/{vault-indexer-Dn_BccVK.mjs.map → vault-indexer-DrttVeEk.mjs.map} +1 -1
  198. package/dist/{work-queue-worker-BwouhVkb.mjs → work-queue-worker-BPXLkEik.mjs} +47 -30
  199. package/dist/work-queue-worker-BPXLkEik.mjs.map +1 -0
  200. package/dist/work-queue-worker-BoHIH70K.mjs +1856 -0
  201. package/dist/work-queue-worker-BoHIH70K.mjs.map +1 -0
  202. package/dist/work-queue-worker-CZGcQoLw.mjs +1856 -0
  203. package/dist/work-queue-worker-CZGcQoLw.mjs.map +1 -0
  204. package/dist/work-queue-worker-D05Ze9e9.mjs +1856 -0
  205. package/dist/work-queue-worker-D05Ze9e9.mjs.map +1 -0
  206. package/dist/work-queue-worker-DdXFINfH.mjs +1856 -0
  207. package/dist/work-queue-worker-DdXFINfH.mjs.map +1 -0
  208. package/dist/{zettelkasten-NwBD1NsT.mjs → zettelkasten-CTlt1dGv.mjs} +4 -4
  209. package/dist/{zettelkasten-NwBD1NsT.mjs.map → zettelkasten-CTlt1dGv.mjs.map} +1 -1
  210. package/dist/zettelkasten-D0N_A_OE.mjs +1063 -0
  211. package/dist/zettelkasten-D0N_A_OE.mjs.map +1 -0
  212. package/docs/commands/README.md +18 -0
  213. package/docs/commands/backup.md +1 -1
  214. package/docs/commands/clear-names.md +1 -1
  215. package/docs/commands/daemon.md +1 -1
  216. package/docs/commands/db.md +1 -1
  217. package/docs/commands/end.md +4 -1
  218. package/docs/commands/help.md +1 -1
  219. package/docs/commands/kg.md +1 -1
  220. package/docs/commands/mcp.md +1 -1
  221. package/docs/commands/memory.md +1 -1
  222. package/docs/commands/notify.md +1 -1
  223. package/docs/commands/observation.md +1 -1
  224. package/docs/commands/obsidian.md +1 -1
  225. package/docs/commands/pause.md +5 -2
  226. package/docs/commands/project.md +1 -1
  227. package/docs/commands/projects.md +1 -1
  228. package/docs/commands/registry.md +18 -1
  229. package/docs/commands/restore.md +1 -1
  230. package/docs/commands/session.md +295 -0
  231. package/docs/commands/sessions.md +1 -1
  232. package/docs/commands/setup.md +1 -1
  233. package/docs/commands/shell-init.md +1 -1
  234. package/docs/commands/skill.md +1 -1
  235. package/docs/commands/task.md +1 -1
  236. package/docs/commands/topic.md +1 -1
  237. package/docs/commands/update.md +1 -1
  238. package/docs/commands/zettel.md +1 -1
  239. package/package.json +1 -1
  240. package/plugins/context-preservation/hooks/hooks.json +12 -1
  241. package/scripts/build-hooks.mjs +33 -3
  242. package/src/hooks/session-autosave.sh +69 -0
  243. package/src/hooks/session-stop.sh +32 -1
  244. package/src/hooks/ts/lib/project-utils/todo.test.ts +132 -0
  245. package/src/hooks/ts/lib/project-utils/todo.ts +60 -34
  246. package/src/hooks/ts/session-start/load-project-context.ts +44 -0
  247. package/dist/kg-extraction-C8DEUHTS.mjs.map +0 -1
  248. package/dist/pai-marker-HVBwwBW-.mjs.map +0 -1
  249. package/dist/pick-r95zvydr.mjs.map +0 -1
  250. package/dist/sync-uPR4g438.mjs.map +0 -1
  251. package/dist/work-queue-worker-BwouhVkb.mjs.map +0 -1
@@ -1,8 +1,8 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/hooks/ts/pre-compact/context-compression-hook.ts
4
- import { existsSync as existsSync7, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
5
- import { basename as basename3, dirname, join as join6 } from "path";
4
+ import { existsSync as existsSync8, readFileSync as readFileSync7, writeFileSync as writeFileSync4 } from "fs";
5
+ import { basename as basename3, dirname, join as join7 } from "path";
6
6
  import { tmpdir } from "os";
7
7
  import { connect } from "net";
8
8
  import { randomUUID } from "crypto";
@@ -420,13 +420,292 @@ function calculateSessionTokens(jsonlPath) {
420
420
  }
421
421
 
422
422
  // src/hooks/ts/lib/project-utils/todo.ts
423
- import { existsSync as existsSync6, mkdirSync as mkdirSync3, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
424
- import { join as join5 } from "path";
423
+ import { existsSync as existsSync7, mkdirSync as mkdirSync4, readFileSync as readFileSync6, writeFileSync as writeFileSync3 } from "fs";
424
+ import { join as join6 } from "path";
425
+
426
+ // src/session/checkpoint-block.ts
427
+ import {
428
+ existsSync as existsSync6,
429
+ readFileSync as readFileSync5,
430
+ writeFileSync as writeFileSync2,
431
+ readdirSync as readdirSync3,
432
+ renameSync as renameSync3,
433
+ mkdirSync as mkdirSync3,
434
+ realpathSync
435
+ } from "node:fs";
436
+ import { join as join5 } from "node:path";
437
+ var TODO_LOCATIONS = [
438
+ "Notes/TODO.md",
439
+ ".claude/Notes/TODO.md",
440
+ "tasks/todo.md",
441
+ "TODO.md"
442
+ ];
443
+ var MARKER_OPEN = "<!-- pai:checkpoint";
444
+ var MARKER_CLOSE = "<!-- /pai:checkpoint -->";
445
+ var CONTINUE_HEADING = "## Continue";
446
+ function findProjectTodo(rootPath) {
447
+ for (const rel of TODO_LOCATIONS) {
448
+ const full = join5(rootPath, rel);
449
+ if (existsSync6(full)) {
450
+ try {
451
+ return { path: full, content: readFileSync5(full, "utf8") };
452
+ } catch {
453
+ }
454
+ }
455
+ }
456
+ return null;
457
+ }
458
+ function resolveTodoTarget(rootPath, opts = {}) {
459
+ const found = findProjectTodo(rootPath);
460
+ if (found) return found;
461
+ const notesDir = join5(rootPath, "Notes");
462
+ if (opts.create !== false) {
463
+ try {
464
+ if (!existsSync6(notesDir)) mkdirSync3(notesDir, { recursive: true });
465
+ } catch {
466
+ return null;
467
+ }
468
+ }
469
+ return { path: join5(notesDir, "TODO.md"), content: "" };
470
+ }
471
+ function parseMarker(line) {
472
+ const trimmed = line.trim();
473
+ if (!trimmed.startsWith(MARKER_OPEN)) return null;
474
+ const attrs = {};
475
+ for (const m of trimmed.matchAll(/([a-zA-Z][\w-]*)="([^"]*)"/g)) {
476
+ attrs[m[1]] = m[2];
477
+ }
478
+ return {
479
+ authored: attrs.authored === "model" ? "model" : "auto",
480
+ session: attrs.session || void 0,
481
+ sessionId: attrs["session-id"] || void 0,
482
+ ts: attrs.ts || void 0
483
+ };
484
+ }
485
+ var BOILERPLATE_PATTERNS = [
486
+ /^##\s+Continue$/,
487
+ /^<!--\s*\/?pai:checkpoint/,
488
+ /^>\s*\*\*Last session:\*\*/,
489
+ /^>\s*\*\*Paused at:\*\*/,
490
+ /^>\s*Working directory:/,
491
+ /^>\s*Resume with:/,
492
+ /^>\s*_No checkpoint body was recorded/,
493
+ /^-{3,}$/
494
+ ];
495
+ var BLANK_LINE = /^>?\s*$/;
496
+ function isBoilerplateOnly(lines) {
497
+ return lines.every((line) => {
498
+ const t = line.trim();
499
+ return BLANK_LINE.test(t) || BOILERPLATE_PATTERNS.some((re) => re.test(t));
500
+ });
501
+ }
502
+ function extractSectionContent(lines) {
503
+ const kept = [];
504
+ for (const line of lines) {
505
+ const t = line.trim();
506
+ if (BOILERPLATE_PATTERNS.some((re) => re.test(t))) continue;
507
+ kept.push(line);
508
+ }
509
+ return trimBlankEdges(collapseBlankRuns(kept)).join("\n");
510
+ }
511
+ function trimBlankEdges(lines) {
512
+ let start = 0;
513
+ let end = lines.length;
514
+ while (start < end && BLANK_LINE.test(lines[start].trim())) start += 1;
515
+ while (end > start && BLANK_LINE.test(lines[end - 1].trim())) end -= 1;
516
+ return lines.slice(start, end);
517
+ }
518
+ function collapseBlankRuns(lines) {
519
+ const out = [];
520
+ let lastWasBlank = false;
521
+ for (const line of lines) {
522
+ const isBlank = BLANK_LINE.test(line.trim());
523
+ if (isBlank && lastWasBlank) continue;
524
+ out.push(line);
525
+ lastWasBlank = isBlank;
526
+ }
527
+ return out;
528
+ }
529
+ function locateContinue(content) {
530
+ const lines = content.split("\n");
531
+ const startIdx = lines.findIndex((l) => l.trim() === CONTINUE_HEADING);
532
+ if (startIdx === -1) return null;
533
+ let meta = null;
534
+ let markerIdx = -1;
535
+ for (let i = startIdx + 1; i < Math.min(startIdx + 6, lines.length); i++) {
536
+ const parsed = parseMarker(lines[i]);
537
+ if (parsed) {
538
+ meta = parsed;
539
+ markerIdx = i;
540
+ break;
541
+ }
542
+ if (lines[i].trim() !== "") break;
543
+ }
544
+ let endIdx = lines.length;
545
+ if (markerIdx !== -1) {
546
+ const closeIdx = lines.findIndex(
547
+ (l, i) => i > markerIdx && l.trim() === MARKER_CLOSE
548
+ );
549
+ if (closeIdx !== -1) {
550
+ endIdx = closeIdx + 1;
551
+ } else {
552
+ endIdx = heuristicEnd(lines, startIdx);
553
+ }
554
+ } else {
555
+ endIdx = heuristicEnd(lines, startIdx);
556
+ }
557
+ let trailingEnd = endIdx;
558
+ while (trailingEnd < lines.length && lines[trailingEnd].trim() === "") {
559
+ trailingEnd += 1;
560
+ }
561
+ if (trailingEnd < lines.length && lines[trailingEnd].trim() === "---") {
562
+ trailingEnd += 1;
563
+ } else {
564
+ trailingEnd = endIdx;
565
+ }
566
+ return {
567
+ startIdx,
568
+ endIdx: trailingEnd,
569
+ meta,
570
+ lines: lines.slice(startIdx, trailingEnd)
571
+ };
572
+ }
573
+ function heuristicEnd(lines, startIdx) {
574
+ for (let i = startIdx + 1; i < lines.length; i++) {
575
+ const trimmed = lines[i].trim();
576
+ if (trimmed === "---" || /^##(?!#)/.test(trimmed) && trimmed !== CONTINUE_HEADING) {
577
+ return i;
578
+ }
579
+ }
580
+ return lines.length;
581
+ }
582
+ function stripContinue(content) {
583
+ const found = locateContinue(content);
584
+ if (!found) return content;
585
+ const lines = content.split("\n");
586
+ const before = lines.slice(0, found.startIdx);
587
+ const after = lines.slice(found.endIdx);
588
+ while (after.length > 0 && after[0].trim() === "") after.shift();
589
+ return [...before, ...after].join("\n");
590
+ }
591
+ function escapeAttr(value) {
592
+ return value.replace(/"/g, "'");
593
+ }
594
+ function buildContinueBlock(opts) {
595
+ const ts = opts.timestamp ?? (/* @__PURE__ */ new Date()).toISOString();
596
+ const attrs = [
597
+ `authored="${opts.authored}"`,
598
+ `session="${escapeAttr(opts.sessionLine)}"`,
599
+ opts.sessionId ? `session-id="${escapeAttr(opts.sessionId)}"` : null,
600
+ `ts="${ts}"`
601
+ ].filter(Boolean).join(" ");
602
+ const header = [
603
+ `> **Last session:** ${opts.sessionLine}`,
604
+ `> **Paused at:** ${ts}`,
605
+ ">",
606
+ `> Working directory: ${opts.cwd}`
607
+ ];
608
+ if (opts.sessionId) {
609
+ header.push(">", `> Resume with: \`claude --resume ${opts.sessionId}\``);
610
+ }
611
+ const body = (opts.body ?? "").trim();
612
+ const parts = [
613
+ CONTINUE_HEADING,
614
+ "",
615
+ `${MARKER_OPEN} ${attrs} -->`,
616
+ "",
617
+ ...header
618
+ ];
619
+ if (body) {
620
+ parts.push("", body);
621
+ } else {
622
+ parts.push(
623
+ ">",
624
+ "> _No checkpoint body was recorded \u2014 see the latest session note._"
625
+ );
626
+ }
627
+ parts.push("", MARKER_CLOSE, "", "---", "");
628
+ return parts.join("\n");
629
+ }
630
+ function isSameSession(meta, opts) {
631
+ if (meta.sessionId && opts.sessionId) {
632
+ return meta.sessionId === opts.sessionId;
633
+ }
634
+ return meta.session === opts.sessionLine;
635
+ }
636
+ function applyContinue(opts) {
637
+ const target = resolveTodoTarget(opts.rootPath, { create: !opts.dryRun });
638
+ if (!target) {
639
+ return {
640
+ action: "failed",
641
+ path: null,
642
+ block: buildContinueBlock(opts),
643
+ error: "Could not resolve or create a TODO.md target"
644
+ };
645
+ }
646
+ const existing = locateContinue(target.content);
647
+ let carriedForward = false;
648
+ let effectiveBody = opts.body;
649
+ if (opts.authored === "auto" && existing) {
650
+ if (existing.meta?.authored === "model" && isSameSession(existing.meta, opts)) {
651
+ return {
652
+ action: "preserved",
653
+ path: target.path,
654
+ block: buildContinueBlock(opts),
655
+ preservedMeta: existing.meta
656
+ };
657
+ }
658
+ if (existing.meta && !(opts.body ?? "").trim() && !isBoilerplateOnly(existing.lines)) {
659
+ return {
660
+ action: "preserved",
661
+ path: target.path,
662
+ block: buildContinueBlock(opts),
663
+ preservedMeta: existing.meta ?? void 0
664
+ };
665
+ }
666
+ if (!existing.meta && !isBoilerplateOnly(existing.lines)) {
667
+ const salvaged = extractSectionContent(existing.lines);
668
+ if (salvaged) {
669
+ effectiveBody = [
670
+ "_Carried forward from the previous checkpoint (author unknown \u2014 this",
671
+ "block predates checkpoint authorship markers):_",
672
+ "",
673
+ salvaged
674
+ ].join("\n");
675
+ carriedForward = true;
676
+ }
677
+ }
678
+ }
679
+ const block = buildContinueBlock({ ...opts, body: effectiveBody });
680
+ if (opts.dryRun) {
681
+ return { action: "written", path: target.path, block, carriedForward };
682
+ }
683
+ const newContent = block + stripContinue(target.content).trimStart();
684
+ const tmpPath = `${target.path}.continue.tmp`;
685
+ try {
686
+ writeFileSync2(tmpPath, newContent, "utf8");
687
+ renameSync3(tmpPath, target.path);
688
+ } catch (err) {
689
+ try {
690
+ if (existsSync6(tmpPath)) renameSync3(tmpPath, `${tmpPath}.dead`);
691
+ } catch {
692
+ }
693
+ return {
694
+ action: "failed",
695
+ path: target.path,
696
+ block,
697
+ error: String(err)
698
+ };
699
+ }
700
+ return { action: "written", path: target.path, block, carriedForward };
701
+ }
702
+
703
+ // src/hooks/ts/lib/project-utils/todo.ts
425
704
  function ensureTodoMd(cwd) {
426
705
  const todoPath = findTodoPath(cwd);
427
- if (!existsSync6(todoPath)) {
428
- const parentDir = join5(todoPath, "..");
429
- if (!existsSync6(parentDir)) mkdirSync3(parentDir, { recursive: true });
706
+ if (!existsSync7(todoPath)) {
707
+ const parentDir = join6(todoPath, "..");
708
+ if (!existsSync7(parentDir)) mkdirSync4(parentDir, { recursive: true });
430
709
  const content = `# TODO
431
710
 
432
711
  ## Current Session
@@ -441,43 +720,52 @@ function ensureTodoMd(cwd) {
441
720
 
442
721
  *Last updated: ${(/* @__PURE__ */ new Date()).toISOString()}*
443
722
  `;
444
- writeFileSync2(todoPath, content);
723
+ writeFileSync3(todoPath, content);
445
724
  console.error(`Created TODO.md: ${todoPath}`);
446
725
  }
447
726
  return todoPath;
448
727
  }
449
728
  function updateTodoContinue(cwd, noteFilename, state, tokenDisplay) {
450
- const todoPath = ensureTodoMd(cwd);
451
- let content = readFileSync5(todoPath, "utf-8");
452
- content = content.replace(/## Continue\n[\s\S]*?\n---\n+/, "");
453
- const now = (/* @__PURE__ */ new Date()).toISOString();
454
- const stateLines = state ? state.split("\n").filter((l) => l.trim()).slice(0, 10).map((l) => `> ${l}`).join("\n") : `> Working directory: ${cwd}. Check the latest session note for details.`;
455
- const continueSection = `## Continue
456
-
457
- > **Last session:** ${noteFilename.replace(".md", "")}
458
- > **Paused at:** ${now}
459
- >
460
- ${stateLines}
461
-
462
- ---
463
-
464
- `;
465
- content = content.replace(/^\s+/, "");
466
- const titleMatch = content.match(/^(# [^\n]+\n+)/);
467
- if (titleMatch) {
468
- content = titleMatch[1] + continueSection + content.substring(titleMatch[0].length);
469
- } else {
470
- content = continueSection + content;
729
+ ensureTodoMd(cwd);
730
+ const result = applyContinue({
731
+ rootPath: cwd,
732
+ authored: "auto",
733
+ // The hooks identify a session by its note filename; `pai pause` resolves
734
+ // the same string from the registry (and falls back to this filename when
735
+ // the registry has no session row). They must agree, because this string
736
+ // is the key that decides whether an authored checkpoint belongs to the
737
+ // current session and must be preserved.
738
+ sessionLine: noteFilename.replace(/\.md$/, ""),
739
+ cwd,
740
+ body: state?.trim() || void 0
741
+ });
742
+ if (result.action === "preserved") {
743
+ console.error(
744
+ "TODO.md ## Continue left intact \u2014 authored checkpoint for this session"
745
+ );
746
+ return;
471
747
  }
472
- content = content.replace(/(\n---\s*)*(\n\*Last updated:.*\*\s*)+$/g, "");
473
- content = content.trimEnd() + `
748
+ if (result.action === "failed") {
749
+ console.error(`TODO.md ## Continue update failed: ${result.error}`);
750
+ return;
751
+ }
752
+ try {
753
+ const todoPath = result.path;
754
+ const now = (/* @__PURE__ */ new Date()).toISOString();
755
+ let content = readFileSync6(todoPath, "utf-8");
756
+ content = content.replace(/(\n---\s*)*(\n\*Last updated:.*\*\s*)+$/g, "");
757
+ content = content.trimEnd() + `
474
758
 
475
759
  ---
476
760
 
477
761
  *Last updated: ${now}*
478
762
  `;
479
- writeFileSync2(todoPath, content);
480
- console.error("TODO.md ## Continue section updated");
763
+ writeFileSync3(todoPath, content);
764
+ } catch {
765
+ }
766
+ console.error(
767
+ result.carriedForward ? "TODO.md ## Continue section updated (previous content carried forward)" : "TODO.md ## Continue section updated"
768
+ );
481
769
  }
482
770
 
483
771
  // src/hooks/ts/pre-compact/context-compression-hook.ts
@@ -497,7 +785,7 @@ function contentToText(content) {
497
785
  }
498
786
  function getTranscriptStats(transcriptPath) {
499
787
  try {
500
- const content = readFileSync6(transcriptPath, "utf-8");
788
+ const content = readFileSync7(transcriptPath, "utf-8");
501
789
  const lines = content.trim().split("\n");
502
790
  let userMessages = 0;
503
791
  let assistantMessages = 0;
@@ -526,7 +814,7 @@ function parseTranscript(transcriptPath) {
526
814
  workItems: []
527
815
  };
528
816
  try {
529
- const raw = readFileSync6(transcriptPath, "utf-8");
817
+ const raw = readFileSync7(transcriptPath, "utf-8");
530
818
  const lines = raw.trim().split("\n");
531
819
  const seenSummaries = /* @__PURE__ */ new Set();
532
820
  for (const line of lines) {
@@ -662,9 +950,9 @@ function deriveTitle(data) {
662
950
  var CUMULATIVE_STATE_FILE = ".compact-state.json";
663
951
  function loadCumulativeState(notesDir) {
664
952
  try {
665
- const filePath = join6(notesDir, CUMULATIVE_STATE_FILE);
666
- if (!existsSync7(filePath)) return null;
667
- const raw = JSON.parse(readFileSync6(filePath, "utf-8"));
953
+ const filePath = join7(notesDir, CUMULATIVE_STATE_FILE);
954
+ if (!existsSync8(filePath)) return null;
955
+ const raw = JSON.parse(readFileSync7(filePath, "utf-8"));
668
956
  return {
669
957
  userMessages: raw.userMessages || [],
670
958
  summaries: raw.summaries || [],
@@ -696,8 +984,8 @@ function mergeTranscriptData(accumulated, current) {
696
984
  }
697
985
  function saveCumulativeState(notesDir, data, notePath) {
698
986
  try {
699
- const filePath = join6(notesDir, CUMULATIVE_STATE_FILE);
700
- writeFileSync3(filePath, JSON.stringify({
987
+ const filePath = join7(notesDir, CUMULATIVE_STATE_FILE);
988
+ writeFileSync4(filePath, JSON.stringify({
701
989
  ...data,
702
990
  notePath,
703
991
  lastUpdated: (/* @__PURE__ */ new Date()).toISOString()
@@ -840,9 +1128,9 @@ async function main() {
840
1128
  const data = parseTranscript(hookInput.transcript_path);
841
1129
  let notesInfo;
842
1130
  try {
843
- notesInfo = hookInput.cwd ? findNotesDir(hookInput.cwd) : { path: join6(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
1131
+ notesInfo = hookInput.cwd ? findNotesDir(hookInput.cwd) : { path: join7(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
844
1132
  } catch {
845
- notesInfo = { path: join6(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
1133
+ notesInfo = { path: join7(dirname(hookInput.transcript_path), "Notes"), isLocal: false };
846
1134
  }
847
1135
  const accumulated = loadCumulativeState(notesInfo.path);
848
1136
  const merged = mergeTranscriptData(accumulated, data);
@@ -858,10 +1146,10 @@ async function main() {
858
1146
  notePath = createSessionNote(notesInfo.path, "Untitled Session");
859
1147
  } else {
860
1148
  try {
861
- let noteContent = readFileSync6(notePath, "utf-8");
1149
+ let noteContent = readFileSync7(notePath, "utf-8");
862
1150
  if (noteContent.includes("**Status:** Completed")) {
863
1151
  noteContent = noteContent.replace("**Status:** Completed", "**Status:** In Progress");
864
- writeFileSync3(notePath, noteContent);
1152
+ writeFileSync4(notePath, noteContent);
865
1153
  console.error(`Reopened completed note for continued session: ${basename3(notePath)}`);
866
1154
  }
867
1155
  } catch {
@@ -880,12 +1168,12 @@ ${state}` : `Context compression triggered at ~${tokenDisplay} tokens with ${sta
880
1168
  const newPath = renameSessionNote(notePath, title);
881
1169
  if (newPath !== notePath) {
882
1170
  try {
883
- let noteContent = readFileSync6(newPath, "utf-8");
1171
+ let noteContent = readFileSync7(newPath, "utf-8");
884
1172
  noteContent = noteContent.replace(
885
1173
  /^(# Session \d+:)\s*.*$/m,
886
1174
  `$1 ${title}`
887
1175
  );
888
- writeFileSync3(newPath, noteContent);
1176
+ writeFileSync4(newPath, noteContent);
889
1177
  console.error(`Updated note H1 to match rename`);
890
1178
  } catch {
891
1179
  }
@@ -926,8 +1214,8 @@ rename it based on actual work done and add a rich summary.` : "";
926
1214
  "</system-reminder>"
927
1215
  ].join("\n");
928
1216
  try {
929
- const stateFile = join6(tmpdir(), `pai-compact-state-${hookInput.session_id}.txt`);
930
- writeFileSync3(stateFile, injection, "utf-8");
1217
+ const stateFile = join7(tmpdir(), `pai-compact-state-${hookInput.session_id}.txt`);
1218
+ writeFileSync4(stateFile, injection, "utf-8");
931
1219
  console.error(`Session state saved to ${stateFile} (${injection.length} chars)`);
932
1220
  } catch (err) {
933
1221
  console.error(`Failed to save state file: ${err}`);