@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
@@ -0,0 +1,295 @@
1
+ <!-- GENERATED by scripts/build-docs.mjs from the live Commander tree (src/cli/program.ts). Do not edit by hand. -->
2
+
3
+ # pai session
4
+
5
+ > Session management: list, info, checkpoint, handover, cleanup, slug, tag, route.
6
+
7
+ Short forms: `pai pause`, `pai end`, `pai resume <name>`.
8
+
9
+ ## Synopsis
10
+
11
+ ```
12
+ pai session <subcommand> [options]
13
+ ```
14
+
15
+ ## Subcommands
16
+
17
+ | Command | Description |
18
+ |---------|-------------|
19
+ | [`pai session list`](#pai-session-list) | Resumable sessions catalog — named sessions with resume status. |
20
+ | [`pai session info <project-slug> <number>`](#pai-session-info-project-slug-number) | Show full details for a specific session |
21
+ | [`pai session rename <project-slug> <number> <new-slug>`](#pai-session-rename-project-slug-number-new-slug) | Rename a session note — updates file on disk, H1 title, and registry |
22
+ | [`pai session slug <project-slug> <number>`](#pai-session-slug-project-slug-number) | Generate a descriptive slug from the session JSONL transcript |
23
+ | [`pai session tag <project-slug> <number> [tags...]`](#pai-session-tag-project-slug-number-tags) | Set or show tags on a session. Tags can be space-separated or comma-separated. |
24
+ | [`pai session route <project-slug> <number> <target-project>`](#pai-session-route-project-slug-number-target-project) | Create a cross-reference link from a session to a target project |
25
+ | [`pai session handover [project-slug] [number-or-latest]`](#pai-session-handover-project-slug-number-or-latest) | Write a ## Continue section to the project's TODO.md. |
26
+ | [`pai session checkpoint <message>`](#pai-session-checkpoint-message) | Append a timestamped checkpoint to the active session note. |
27
+ | [`pai session autosave`](#pai-session-autosave) | Refresh the ## Continue checkpoint from the transcript and working tree. |
28
+ | [`pai session active`](#pai-session-active) | Show currently active Claude Code sessions. |
29
+ | [`pai session recent`](#pai-session-recent) | [Deprecated] Use `pai session list` or `pai sessions` instead. |
30
+ | [`pai session goto <name-or-id>`](#pai-session-goto-name-or-id) | Go to a session: resume if a resumable snapshot exists, start fresh otherwise. |
31
+ | [`pai session pause`](#pai-session-pause) | Write a ## Continue checkpoint to the project's TODO.md. |
32
+ | [`pai session auto-route`](#pai-session-auto-route) | Auto-detect which project this session belongs to. |
33
+ | [`pai session cleanup [project-slug]`](#pai-session-cleanup-project-slug) | Clean up session notes: delete empties, auto-name unnamed, move into YYYY/MM/ hierarchy, renumber |
34
+
35
+ ### pai session list
36
+
37
+ Resumable sessions catalog — named sessions with resume status.
38
+
39
+ Short form: pai sessions
40
+ Default shows all sessions you've named or that are resumable.
41
+ Use --all to also show unnamed orphan sessions.
42
+
43
+ **Options**
44
+
45
+ | Option | Description | Default |
46
+ |--------|-------------|---------|
47
+ | `-n <count>` | Maximum sessions to show (default: 20) | `20` |
48
+ | `--all` | Include unnamed orphan sessions (not in clc registry) | |
49
+ | `--json` | Output raw JSON instead of formatted table | |
50
+
51
+
52
+ ### pai session info <project-slug> <number>
53
+
54
+ Show full details for a specific session
55
+
56
+ **Arguments**
57
+
58
+ | Argument | Kind |
59
+ |----------|------|
60
+ | `<project-slug>` | required |
61
+ | `<number>` | required |
62
+
63
+
64
+ ### pai session rename <project-slug> <number> <new-slug>
65
+
66
+ Rename a session note — updates file on disk, H1 title, and registry
67
+
68
+ **Arguments**
69
+
70
+ | Argument | Kind |
71
+ |----------|------|
72
+ | `<project-slug>` | required |
73
+ | `<number>` | required |
74
+ | `<new-slug>` | required |
75
+
76
+
77
+ ### pai session slug <project-slug> <number>
78
+
79
+ Generate a descriptive slug from the session JSONL transcript
80
+
81
+ **Arguments**
82
+
83
+ | Argument | Kind |
84
+ |----------|------|
85
+ | `<project-slug>` | required |
86
+ | `<number>` | required |
87
+
88
+ **Options**
89
+
90
+ | Option | Description | Default |
91
+ |--------|-------------|---------|
92
+ | `--apply` | Rename the session note using the generated slug | |
93
+
94
+
95
+ ### pai session tag <project-slug> <number> [tags...]
96
+
97
+ Set or show tags on a session. Tags can be space-separated or comma-separated.
98
+
99
+ **Arguments**
100
+
101
+ | Argument | Kind |
102
+ |----------|------|
103
+ | `<project-slug>` | required |
104
+ | `<number>` | required |
105
+ | `[tags...]` | variadic |
106
+
107
+
108
+ ### pai session route <project-slug> <number> <target-project>
109
+
110
+ Create a cross-reference link from a session to a target project
111
+
112
+ **Arguments**
113
+
114
+ | Argument | Kind |
115
+ |----------|------|
116
+ | `<project-slug>` | required |
117
+ | `<number>` | required |
118
+ | `<target-project>` | required |
119
+
120
+ **Options**
121
+
122
+ | Option | Description | Default |
123
+ |--------|-------------|---------|
124
+ | `--type <type>` | Link type: related \| follow-up \| reference | `related` |
125
+
126
+
127
+ ### pai session handover [project-slug] [number-or-latest]
128
+
129
+ Write a ## Continue section to the project's TODO.md.
130
+
131
+ Called automatically from session-stop and pre-compact hooks.
132
+ Records the last session identifier, timestamp, and working directory
133
+ so the next session can resume from the correct context.
134
+
135
+ **Arguments**
136
+
137
+ | Argument | Kind |
138
+ |----------|------|
139
+ | `[project-slug]` | optional |
140
+ | `[number-or-latest]` | optional |
141
+
142
+ **Options**
143
+
144
+ | Option | Description | Default |
145
+ |--------|-------------|---------|
146
+ | `--session-id <uuid>` | Claude session UUID. Used to decide whether an existing authored checkpoint belongs to this session and must be preserved. Without it the comparison falls back to the session note filename, which the stop hook itself renames — so pass it whenever it is known. | |
147
+
148
+
149
+ ### pai session checkpoint <message>
150
+
151
+ Append a timestamped checkpoint to the active session note.
152
+
153
+ Designed for hooks (PostToolUse, UserPromptSubmit) — fast and silent.
154
+ Rate-limited: skips silently if last checkpoint was < --min-gap seconds ago.
155
+
156
+ **Arguments**
157
+
158
+ | Argument | Kind |
159
+ |----------|------|
160
+ | `<message>` | required |
161
+
162
+ **Options**
163
+
164
+ | Option | Description | Default |
165
+ |--------|-------------|---------|
166
+ | `--min-gap <seconds>` | Minimum seconds between checkpoints (default: 300 = 5 minutes) | `300` |
167
+
168
+
169
+ ### pai session autosave
170
+
171
+ Refresh the ## Continue checkpoint from the transcript and working tree.
172
+
173
+ Runs unattended from live hooks so an interrupted session still leaves
174
+ a usable handover. Writes in auto mode, so a model-authored checkpoint
175
+ for the same session is preserved untouched. Silent; always exits 0.
176
+
177
+ **Options**
178
+
179
+ | Option | Description | Default |
180
+ |--------|-------------|---------|
181
+ | `--session-id <uuid>` | Claude session UUID — the key that decides whether an existing authored checkpoint belongs to this session and must be left alone. | |
182
+ | `--min-gap <seconds>` | Minimum seconds between autosaves, shared across all triggers (default: 240) | `240` |
183
+ | `--dry-run` | Print the block that would be written and exit | |
184
+
185
+
186
+ ### pai session active
187
+
188
+ Show currently active Claude Code sessions.
189
+
190
+ Detects live sessions by checking which JSONL transcript files
191
+ were recently modified in ~/.claude/projects/.
192
+
193
+ **Options**
194
+
195
+ | Option | Description | Default |
196
+ |--------|-------------|---------|
197
+ | `--minutes <n>` | Consider sessions active if modified within N minutes (default: 60) | `60` |
198
+ | `--json` | Output raw JSON instead of formatted display | |
199
+
200
+
201
+ ### pai session recent
202
+
203
+ [Deprecated] Use `pai session list` or `pai sessions` instead.
204
+
205
+ **Options**
206
+
207
+ | Option | Description | Default |
208
+ |--------|-------------|---------|
209
+ | `-n <count>` | Maximum sessions to show (default: 20) | `20` |
210
+ | `--all` | Include unnamed orphan sessions (not in clc registry) | |
211
+ | `--json` | Output raw JSON instead of formatted table | |
212
+
213
+
214
+ ### pai session goto <name-or-id>
215
+
216
+ Go to a session: resume if a resumable snapshot exists, start fresh otherwise.
217
+
218
+ Recommended short form: pai resume <name>
219
+ Resolves by clc/registry name (case-insensitive) or UUID prefix.
220
+ Sends '/Name <name>\ngo' as the initial prompt so the PAI ## Continue hook fires.
221
+
222
+ **Arguments**
223
+
224
+ | Argument | Kind |
225
+ |----------|------|
226
+ | `<name-or-id>` | required |
227
+
228
+ **Options**
229
+
230
+ | Option | Description | Default |
231
+ |--------|-------------|---------|
232
+ | `--skip-name` | Do not prepend /Name to set the session name in chrome | |
233
+ | `--skip-go` | Do not append \ngo to trigger PAI auto-resume (## Continue) | |
234
+ | `--dry-run` | Print the exact argv and cwd, then exit without launching | |
235
+
236
+
237
+ ### pai session pause
238
+
239
+ Write a ## Continue checkpoint to the project's TODO.md.
240
+
241
+ Recommended short form: pai pause
242
+ Ctrl+C bypasses the stop-hook, orphaning the session (cannot --resume).
243
+ Use /exit inside Claude Code to preserve full session resumability.
244
+
245
+ **Options**
246
+
247
+ | Option | Description | Default |
248
+ |--------|-------------|---------|
249
+ | `--dry-run` | Preview the ## Continue block without writing it | |
250
+ | `--body-file <path>` | File holding the checkpoint markdown to persist ('-' reads stdin). Required unless --no-body. | |
251
+ | `--session-id <uuid>` | Claude Code session UUID — recorded as the `claude --resume` handle | |
252
+ | `--no-body` | Deliberately write a metadata-only checkpoint (no content) | |
253
+
254
+
255
+ ### pai session auto-route
256
+
257
+ Auto-detect which project this session belongs to.
258
+
259
+ Tries: (1) path match in registry, (2) Notes/PAI.md marker walk, (3) topic detection.
260
+ Designed for use in CLAUDE.md session-start hooks.
261
+
262
+ **Options**
263
+
264
+ | Option | Description | Default |
265
+ |--------|-------------|---------|
266
+ | `--cwd <path>` | Working directory to detect from (default: process.cwd()) | |
267
+ | `--context <text>` | Conversation context for topic-based fallback routing | |
268
+ | `--json` | Output raw JSON instead of formatted display | |
269
+
270
+
271
+ ### pai session cleanup [project-slug]
272
+
273
+ Clean up session notes: delete empties, auto-name unnamed, move into YYYY/MM/ hierarchy, renumber
274
+
275
+ **Arguments**
276
+
277
+ | Argument | Kind |
278
+ |----------|------|
279
+ | `[project-slug]` | optional |
280
+
281
+ **Options**
282
+
283
+ | Option | Description | Default |
284
+ |--------|-------------|---------|
285
+ | `--execute` | Actually perform the cleanup (default is dry-run) | |
286
+ | `--no-renumber` | Skip renumbering sessions after deletions | |
287
+ | `--no-reindex` | Skip triggering memory re-index after moves | |
288
+
289
+
290
+ ## See also
291
+
292
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
293
+
294
+ Run `pai help <area>` to read any of these in the terminal.
295
+
@@ -19,7 +19,7 @@ pai sessions [options]
19
19
 
20
20
  ## See also
21
21
 
22
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
22
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
23
23
 
24
24
  Run `pai help <area>` to read any of these in the terminal.
25
25
 
@@ -14,7 +14,7 @@ pai setup
14
14
 
15
15
  ## See also
16
16
 
17
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
17
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
18
18
 
19
19
  Run `pai help <area>` to read any of these in the terminal.
20
20
 
@@ -12,7 +12,7 @@ pai shell-init
12
12
 
13
13
  ## See also
14
14
 
15
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
15
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
16
16
 
17
17
  Run `pai help <area>` to read any of these in the terminal.
18
18
 
@@ -48,7 +48,7 @@ See `Notes/swarm/skills-self-educating.md` for the full self-educating loop
48
48
 
49
49
  ## See also
50
50
 
51
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
51
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
52
52
 
53
53
  Run `pai help <area>` to read any of these in the terminal.
54
54
 
@@ -142,7 +142,7 @@ Mark a task complete on the tracker
142
142
 
143
143
  ## See also
144
144
 
145
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
145
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai topic`](topic.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
146
146
 
147
147
  Run `pai help <area>` to read any of these in the terminal.
148
148
 
@@ -40,7 +40,7 @@ Exit code 1 if a shift is detected (useful for hooks).
40
40
 
41
41
  ## See also
42
42
 
43
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
43
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai update`](update.md) · [`pai zettel`](zettel.md)
44
44
 
45
45
  Run `pai help <area>` to read any of these in the terminal.
46
46
 
@@ -12,7 +12,7 @@ pai update
12
12
 
13
13
  ## See also
14
14
 
15
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai zettel`](zettel.md)
15
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai zettel`](zettel.md)
16
16
 
17
17
  Run `pai help <area>` to read any of these in the terminal.
18
18
 
@@ -145,7 +145,7 @@ pai zettel health
145
145
 
146
146
  ## See also
147
147
 
148
- [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md)
148
+ [`pai backup`](backup.md) · [`pai clear-names`](clear-names.md) · [`pai daemon`](daemon.md) · [`pai db`](db.md) · [`pai end`](end.md) · [`pai help`](help.md) · [`pai kg`](kg.md) · [`pai mcp`](mcp.md) · [`pai memory`](memory.md) · [`pai notify`](notify.md) · [`pai observation`](observation.md) · [`pai obsidian`](obsidian.md) · [`pai pause`](pause.md) · [`pai project`](project.md) · [`pai projects`](projects.md) · [`pai registry`](registry.md) · [`pai restore`](restore.md) · [`pai session`](session.md) · [`pai sessions`](sessions.md) · [`pai setup`](setup.md) · [`pai shell-init`](shell-init.md) · [`pai skill`](skill.md) · [`pai task`](task.md) · [`pai topic`](topic.md) · [`pai update`](update.md)
149
149
 
150
150
  Run `pai help <area>` to read any of these in the terminal.
151
151
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekmidian/pai",
3
- "version": "0.15.0",
3
+ "version": "0.17.0",
4
4
  "description": "PAI Knowledge OS — Personal AI Infrastructure with federated memory and project management",
5
5
  "type": "module",
6
6
  "main": "dist/index.mjs",
@@ -1,7 +1,18 @@
1
1
  {
2
2
  "module": "context-preservation",
3
- "description": "Context compression and relay across compaction cycles",
3
+ "description": "Context preservation across compaction cycles, restarts, and interrupted sessions",
4
4
  "hooks": [
5
+ {
6
+ "event": "UserPromptSubmit",
7
+ "command": "${PAI_DIR}/Hooks/pai-session-autosave.sh",
8
+ "description": "Refresh the rolling ## Continue checkpoint from the transcript and working tree (rate-limited). Never overwrites a model-authored checkpoint for the same session."
9
+ },
10
+ {
11
+ "event": "PostToolUse",
12
+ "matcher": "*",
13
+ "command": "${PAI_DIR}/Hooks/pai-session-autosave.sh",
14
+ "description": "Same rolling checkpoint, so a long working turn interrupted by Ctrl+C still leaves recoverable state"
15
+ },
5
16
  {
6
17
  "event": "PreCompact",
7
18
  "command": "${PAI_DIR}/Hooks/context-compression-hook.mjs",
@@ -24,6 +24,8 @@ import {
24
24
  copyFileSync,
25
25
  readFileSync,
26
26
  writeFileSync,
27
+ renameSync,
28
+ rmSync,
27
29
  } from "fs";
28
30
  import { join, resolve, basename } from "path";
29
31
  import { homedir, platform } from "os";
@@ -51,8 +53,24 @@ const entryPoints = collectEntryPoints(HOOKS_SRC);
51
53
 
52
54
  console.log(`Building ${entryPoints.length} hooks with esbuild...`);
53
55
 
56
+ // Build into a staging directory, then rename each artefact into place.
57
+ //
58
+ // ~/.claude/Hooks/*.mjs are symlinks to these files, and every LIVE Claude Code
59
+ // session executes them on each tool call. esbuild truncates-then-writes, so
60
+ // building straight to the output path leaves a window in which the file does
61
+ // not exist — any hook firing during a build in another session dies with
62
+ // "No such file or directory". That is not hypothetical: a rebuild here breaks
63
+ // hooks in every other session that happens to fire during it.
64
+ //
65
+ // rename(2) within one filesystem is atomic, so a concurrent session sees
66
+ // either the previous build or the new one, never a partial or absent file.
67
+ const STAGING = join(HOOKS_OUT, ".staging");
68
+ rmSync(STAGING, { recursive: true, force: true });
69
+ mkdirSync(STAGING, { recursive: true });
70
+
54
71
  for (const entry of entryPoints) {
55
- const outfile = join(HOOKS_OUT, basename(entry).replace(/\.ts$/, ".mjs"));
72
+ const name = basename(entry).replace(/\.ts$/, ".mjs");
73
+ const staged = join(STAGING, name);
56
74
 
57
75
  buildSync({
58
76
  entryPoints: [entry],
@@ -60,13 +78,24 @@ for (const entry of entryPoints) {
60
78
  platform: "node",
61
79
  target: "node20",
62
80
  format: "esm",
63
- outfile,
81
+ outfile: staged,
64
82
  sourcemap: true,
65
83
  });
66
84
 
67
- chmodSync(outfile, 0o755);
85
+ chmodSync(staged, 0o755);
86
+
87
+ // The sourceMappingURL comment is a bare filename, so the map must land in
88
+ // the same directory as the module. Move it first: a stale map for a moment
89
+ // is harmless, a missing module is not.
90
+ const stagedMap = `${staged}.map`;
91
+ if (existsSync(stagedMap)) {
92
+ renameSync(stagedMap, join(HOOKS_OUT, `${name}.map`));
93
+ }
94
+ renameSync(staged, join(HOOKS_OUT, name));
68
95
  }
69
96
 
97
+ rmSync(STAGING, { recursive: true, force: true });
98
+
70
99
  console.log(`✔ ${entryPoints.length} hooks built to ${HOOKS_OUT}/`);
71
100
 
72
101
  // ---------------------------------------------------------------------------
@@ -141,6 +170,7 @@ if (doSync) {
141
170
  const shellHooks = [
142
171
  ["src/hooks/pre-compact.sh", "pai-pre-compact.sh"],
143
172
  ["src/hooks/session-stop.sh", "pai-session-stop.sh"],
173
+ ["src/hooks/session-autosave.sh", "pai-session-autosave.sh"],
144
174
  ];
145
175
  for (const [src, destName] of shellHooks) {
146
176
  if (existsSync(src)) {
@@ -0,0 +1,69 @@
1
+ #!/bin/bash
2
+ # PAI Knowledge OS — rolling session autosave
3
+ #
4
+ # Fires from live hooks (UserPromptSubmit, PostToolUse) so that a session which
5
+ # never gets a model-authored checkpoint still leaves a usable ## Continue
6
+ # behind. Ctrl+C kills the process without running any stop hook, and /exit does
7
+ # not invoke the model — so an exit-time-only guarantee is no guarantee at all.
8
+ # The state has to be written while the session is still running.
9
+ #
10
+ # Writes in "auto" mode, so a model-authored checkpoint for the same session is
11
+ # preserved untouched. This is the floor, never a replacement for the ceiling.
12
+ #
13
+ # NEVER exits non-zero, NEVER prints — this must not interrupt Claude Code.
14
+
15
+ PAI_OS="pai"
16
+ command -v "$PAI_OS" &>/dev/null || exit 0
17
+
18
+ # ---------------------------------------------------------------------------
19
+ # Shell-side rate limit
20
+ # ---------------------------------------------------------------------------
21
+ # PostToolUse fires after every single tool call. The CLI rate-limits too, but
22
+ # reaching it costs a Node start-up each time — hundreds of milliseconds, paid
23
+ # on every tool call in the session. Checking a sentinel's mtime here costs a
24
+ # stat, so the expensive path is only taken when it will actually do work.
25
+
26
+ MIN_GAP_SECONDS="${PAI_AUTOSAVE_MIN_GAP:-240}"
27
+
28
+ SENTINEL_KEY=$(printf '%s' "$PWD" | tr -c 'a-zA-Z0-9' '-' | tail -c 80)
29
+ SENTINEL="${TMPDIR:-/tmp}/pai-autosave-hook-${SENTINEL_KEY}"
30
+
31
+ if [ -f "$SENTINEL" ]; then
32
+ NOW=$(date +%s)
33
+ # stat is not portable: BSD/macOS uses -f %m, GNU/Linux uses -c %Y.
34
+ LAST=$(stat -f %m "$SENTINEL" 2>/dev/null || stat -c %Y "$SENTINEL" 2>/dev/null || echo 0)
35
+ if [ $((NOW - LAST)) -lt "$MIN_GAP_SECONDS" ]; then
36
+ exit 0
37
+ fi
38
+ fi
39
+
40
+ # ---------------------------------------------------------------------------
41
+ # Session UUID from the hook payload
42
+ # ---------------------------------------------------------------------------
43
+ # The UUID decides whether an existing authored checkpoint belongs to this
44
+ # session and must be left alone. Without it the comparison falls back to the
45
+ # session note filename, which other stop-hook steps rename underneath us.
46
+
47
+ CLAUDE_SESSION_UUID=""
48
+ if [ ! -t 0 ]; then
49
+ HOOK_INPUT=$(timeout 2 cat 2>/dev/null || true)
50
+ if [ -n "$HOOK_INPUT" ]; then
51
+ if command -v jq &>/dev/null; then
52
+ CLAUDE_SESSION_UUID=$(printf '%s' "$HOOK_INPUT" | jq -r '.session_id // empty' 2>/dev/null || true)
53
+ else
54
+ CLAUDE_SESSION_UUID=$(printf '%s' "$HOOK_INPUT" | python3 -c \
55
+ "import sys,json; print(json.load(sys.stdin).get('session_id',''))" 2>/dev/null || true)
56
+ fi
57
+ fi
58
+ fi
59
+
60
+ touch "$SENTINEL" 2>/dev/null || true
61
+
62
+ if [ -n "$CLAUDE_SESSION_UUID" ]; then
63
+ "$PAI_OS" session autosave --session-id "$CLAUDE_SESSION_UUID" \
64
+ --min-gap "$MIN_GAP_SECONDS" &>/dev/null || true
65
+ else
66
+ "$PAI_OS" session autosave --min-gap "$MIN_GAP_SECONDS" &>/dev/null || true
67
+ fi
68
+
69
+ exit 0
@@ -12,6 +12,32 @@ PAI_OS="pai"
12
12
  command -v "$PAI_OS" &>/dev/null || exit 0
13
13
  command -v sqlite3 &>/dev/null || exit 0
14
14
 
15
+ # ---------------------------------------------------------------------------
16
+ # Read the Claude session UUID from the hook payload
17
+ # ---------------------------------------------------------------------------
18
+ # Claude Code delivers the Stop event as JSON on stdin, carrying `session_id`.
19
+ # That UUID is the only stable handle on this session: the steps below rename
20
+ # (`session slug --apply`) and renumber (`session cleanup --execute`) the
21
+ # session note, so anything derived from its filename has already changed by
22
+ # the time the handover runs. Passing the UUID through is what lets the
23
+ # handover recognise a checkpoint `pai pause` wrote minutes earlier instead of
24
+ # mistaking it for a stale one and overwriting it.
25
+ #
26
+ # Read non-blocking: when no payload is piped in, carry on without it.
27
+
28
+ CLAUDE_SESSION_UUID=""
29
+ if [ ! -t 0 ]; then
30
+ HOOK_INPUT=$(timeout 2 cat 2>/dev/null || true)
31
+ if [ -n "$HOOK_INPUT" ]; then
32
+ if command -v jq &>/dev/null; then
33
+ CLAUDE_SESSION_UUID=$(printf '%s' "$HOOK_INPUT" | jq -r '.session_id // empty' 2>/dev/null || true)
34
+ else
35
+ CLAUDE_SESSION_UUID=$(printf '%s' "$HOOK_INPUT" | python3 -c \
36
+ "import sys,json; print(json.load(sys.stdin).get('session_id',''))" 2>/dev/null || true)
37
+ fi
38
+ fi
39
+ fi
40
+
15
41
  REGISTRY_DB="$HOME/.pai/registry.db"
16
42
  [ -f "$REGISTRY_DB" ] || exit 0
17
43
 
@@ -88,7 +114,12 @@ fi
88
114
  # a handover section. If the command doesn't exist yet, fail gracefully.
89
115
  #
90
116
 
91
- "$PAI_OS" session handover "$PROJECT_SLUG" latest 2>/dev/null || true
117
+ if [ -n "$CLAUDE_SESSION_UUID" ]; then
118
+ "$PAI_OS" session handover "$PROJECT_SLUG" latest \
119
+ --session-id "$CLAUDE_SESSION_UUID" 2>/dev/null || true
120
+ else
121
+ "$PAI_OS" session handover "$PROJECT_SLUG" latest 2>/dev/null || true
122
+ fi
92
123
 
93
124
  # Set tab color to completed state when session ends
94
125
  TAB_COLOR="${PAI_DIR:-$HOME/.claude}/tab-color-command.sh"