@llblab/pi-kit 0.12.1 → 0.14.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 (299) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/README.md +2 -2
  3. package/node_modules/@llblab/pi-state-flow/AGENTS.md +7 -7
  4. package/node_modules/@llblab/pi-state-flow/BACKLOG.md +8 -9
  5. package/node_modules/@llblab/pi-state-flow/CHANGELOG.md +26 -0
  6. package/node_modules/@llblab/pi-state-flow/README.md +1 -3
  7. package/node_modules/@llblab/pi-state-flow/dist/index.d.ts +21 -0
  8. package/node_modules/@llblab/pi-state-flow/dist/index.js +20 -0
  9. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.d.ts +39 -0
  10. package/node_modules/@llblab/pi-state-flow/dist/lib/acquisition.js +78 -0
  11. package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.d.ts +110 -0
  12. package/node_modules/@llblab/pi-state-flow/dist/lib/artifact.js +334 -0
  13. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.d.ts +49 -0
  14. package/node_modules/@llblab/pi-state-flow/dist/lib/compaction.js +67 -0
  15. package/node_modules/@llblab/pi-state-flow/dist/lib/config.d.ts +11 -0
  16. package/node_modules/@llblab/pi-state-flow/dist/lib/config.js +53 -0
  17. package/node_modules/@llblab/pi-state-flow/dist/lib/context.d.ts +23 -0
  18. package/node_modules/@llblab/pi-state-flow/dist/lib/context.js +109 -0
  19. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.d.ts +111 -0
  20. package/node_modules/@llblab/pi-state-flow/dist/lib/continuation.js +189 -0
  21. package/node_modules/@llblab/pi-state-flow/dist/lib/discovery.d.ts +21 -0
  22. package/node_modules/@llblab/pi-state-flow/dist/lib/discovery.js +125 -0
  23. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.d.ts +102 -0
  24. package/node_modules/@llblab/pi-state-flow/dist/lib/durable.js +507 -0
  25. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.d.ts +8 -0
  26. package/node_modules/@llblab/pi-state-flow/dist/lib/episode.js +27 -0
  27. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.d.ts +22 -0
  28. package/node_modules/@llblab/pi-state-flow/dist/lib/extension.js +1263 -0
  29. package/node_modules/@llblab/pi-state-flow/dist/lib/git.d.ts +72 -0
  30. package/node_modules/@llblab/pi-state-flow/dist/lib/git.js +565 -0
  31. package/node_modules/@llblab/pi-state-flow/dist/lib/history.d.ts +22 -0
  32. package/node_modules/@llblab/pi-state-flow/dist/lib/history.js +79 -0
  33. package/node_modules/@llblab/pi-state-flow/dist/lib/json.d.ts +12 -0
  34. package/node_modules/@llblab/pi-state-flow/dist/lib/json.js +109 -0
  35. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.d.ts +25 -0
  36. package/node_modules/@llblab/pi-state-flow/dist/lib/logging.js +24 -0
  37. package/node_modules/@llblab/pi-state-flow/dist/lib/maintenance.d.ts +36 -0
  38. package/node_modules/@llblab/pi-state-flow/dist/lib/maintenance.js +98 -0
  39. package/node_modules/@llblab/pi-state-flow/dist/lib/memory.d.ts +15 -0
  40. package/node_modules/@llblab/pi-state-flow/dist/lib/memory.js +42 -0
  41. package/node_modules/@llblab/pi-state-flow/dist/lib/migration.d.ts +13 -0
  42. package/node_modules/@llblab/pi-state-flow/dist/lib/migration.js +133 -0
  43. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.d.ts +7 -0
  44. package/node_modules/@llblab/pi-state-flow/dist/lib/protocol.js +59 -0
  45. package/node_modules/@llblab/pi-state-flow/dist/lib/publication.d.ts +69 -0
  46. package/node_modules/@llblab/pi-state-flow/dist/lib/publication.js +335 -0
  47. package/node_modules/@llblab/pi-state-flow/dist/lib/query.d.ts +27 -0
  48. package/node_modules/@llblab/pi-state-flow/dist/lib/query.js +35 -0
  49. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.d.ts +8 -0
  50. package/node_modules/@llblab/pi-state-flow/dist/lib/recovery.js +27 -0
  51. package/node_modules/@llblab/pi-state-flow/dist/lib/rehydration.d.ts +36 -0
  52. package/node_modules/@llblab/pi-state-flow/dist/lib/rehydration.js +38 -0
  53. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.d.ts +142 -0
  54. package/node_modules/@llblab/pi-state-flow/dist/lib/runtime.js +529 -0
  55. package/node_modules/@llblab/pi-state-flow/dist/lib/session.d.ts +21 -0
  56. package/node_modules/@llblab/pi-state-flow/dist/lib/session.js +44 -0
  57. package/node_modules/@llblab/pi-state-flow/dist/lib/skills.d.ts +25 -0
  58. package/node_modules/@llblab/pi-state-flow/dist/lib/skills.js +131 -0
  59. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.d.ts +88 -0
  60. package/node_modules/@llblab/pi-state-flow/dist/lib/snapshot.js +255 -0
  61. package/node_modules/@llblab/pi-state-flow/dist/lib/state.d.ts +55 -0
  62. package/node_modules/@llblab/pi-state-flow/dist/lib/state.js +31 -0
  63. package/node_modules/@llblab/pi-state-flow/dist/lib/status.d.ts +38 -0
  64. package/node_modules/@llblab/pi-state-flow/dist/lib/status.js +79 -0
  65. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.d.ts +46 -0
  66. package/node_modules/@llblab/pi-state-flow/dist/lib/storage.js +217 -0
  67. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.d.ts +98 -0
  68. package/node_modules/@llblab/pi-state-flow/dist/lib/telegram.js +231 -0
  69. package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.d.ts +39 -0
  70. package/node_modules/@llblab/pi-state-flow/dist/lib/temporal.js +203 -0
  71. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.d.ts +25 -0
  72. package/node_modules/@llblab/pi-state-flow/dist/lib/transition.js +204 -0
  73. package/node_modules/@llblab/pi-state-flow/dist/package.json +79 -0
  74. package/node_modules/@llblab/pi-state-flow/dist/pi-state-flow/index.js +1 -0
  75. package/node_modules/@llblab/pi-state-flow/dist/skills/state-flow-memory/SKILL.md +138 -0
  76. package/node_modules/@llblab/pi-state-flow/docs/architecture.md +11 -5
  77. package/node_modules/@llblab/pi-state-flow/docs/compatibility.md +5 -1
  78. package/node_modules/@llblab/pi-state-flow/docs/filesystem-recovery.md +3 -3
  79. package/node_modules/@llblab/pi-state-flow/docs/usage.md +6 -4
  80. package/node_modules/@llblab/pi-state-flow/index.ts +1 -0
  81. package/node_modules/@llblab/pi-state-flow/lib/compaction.ts +17 -1
  82. package/node_modules/@llblab/pi-state-flow/lib/config.ts +6 -1
  83. package/node_modules/@llblab/pi-state-flow/lib/durable.ts +88 -96
  84. package/node_modules/@llblab/pi-state-flow/lib/extension.ts +64 -12
  85. package/node_modules/@llblab/pi-state-flow/lib/git.ts +32 -188
  86. package/node_modules/@llblab/pi-state-flow/lib/migration.ts +84 -48
  87. package/node_modules/@llblab/pi-state-flow/lib/query.ts +40 -0
  88. package/node_modules/@llblab/pi-state-flow/lib/recovery.ts +7 -30
  89. package/node_modules/@llblab/pi-state-flow/lib/runtime.ts +48 -50
  90. package/node_modules/@llblab/pi-state-flow/lib/snapshot.ts +41 -97
  91. package/node_modules/@llblab/pi-state-flow/lib/storage.ts +17 -12
  92. package/node_modules/@llblab/pi-state-flow/lib/telegram.ts +4 -4
  93. package/node_modules/@llblab/pi-state-flow/package.json +23 -6
  94. package/node_modules/@llblab/pi-state-flow/skills/state-flow-memory/SKILL.md +3 -1
  95. package/node_modules/@llblab/pi-telegram/AGENTS.md +5 -3
  96. package/node_modules/@llblab/pi-telegram/BACKLOG.md +0 -6
  97. package/node_modules/@llblab/pi-telegram/CHANGELOG.md +22 -0
  98. package/node_modules/@llblab/pi-telegram/README.md +6 -3
  99. package/node_modules/@llblab/pi-telegram/dist/api/activity.d.ts +6 -0
  100. package/node_modules/@llblab/pi-telegram/dist/api/activity.js +6 -0
  101. package/node_modules/@llblab/pi-telegram/dist/api/commands.d.ts +6 -0
  102. package/node_modules/@llblab/pi-telegram/dist/api/commands.js +6 -0
  103. package/node_modules/@llblab/pi-telegram/dist/api/delivery.d.ts +6 -0
  104. package/node_modules/@llblab/pi-telegram/dist/api/delivery.js +6 -0
  105. package/node_modules/@llblab/pi-telegram/dist/api/inbound.d.ts +6 -0
  106. package/node_modules/@llblab/pi-telegram/dist/api/inbound.js +6 -0
  107. package/node_modules/@llblab/pi-telegram/dist/api/keyboard.d.ts +6 -0
  108. package/node_modules/@llblab/pi-telegram/dist/api/keyboard.js +6 -0
  109. package/node_modules/@llblab/pi-telegram/dist/api/outbound.d.ts +6 -0
  110. package/node_modules/@llblab/pi-telegram/dist/api/outbound.js +6 -0
  111. package/node_modules/@llblab/pi-telegram/dist/api/sections.d.ts +7 -0
  112. package/node_modules/@llblab/pi-telegram/dist/api/sections.js +6 -0
  113. package/node_modules/@llblab/pi-telegram/dist/api/status.d.ts +6 -0
  114. package/node_modules/@llblab/pi-telegram/dist/api/status.js +6 -0
  115. package/node_modules/@llblab/pi-telegram/dist/api/updates.d.ts +6 -0
  116. package/node_modules/@llblab/pi-telegram/dist/api/updates.js +6 -0
  117. package/node_modules/@llblab/pi-telegram/dist/api/voice.d.ts +6 -0
  118. package/node_modules/@llblab/pi-telegram/dist/api/voice.js +6 -0
  119. package/node_modules/@llblab/pi-telegram/dist/index.d.ts +6 -0
  120. package/node_modules/@llblab/pi-telegram/dist/index.js +6 -0
  121. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.d.ts +52 -0
  122. package/node_modules/@llblab/pi-telegram/dist/lib/activity-verbosity.js +596 -0
  123. package/node_modules/@llblab/pi-telegram/dist/lib/activity.d.ts +220 -0
  124. package/node_modules/@llblab/pi-telegram/dist/lib/activity.js +574 -0
  125. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.d.ts +28 -0
  126. package/node_modules/@llblab/pi-telegram/dist/lib/agent-messages.js +86 -0
  127. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.d.ts +250 -0
  128. package/node_modules/@llblab/pi-telegram/dist/lib/bindings.js +936 -0
  129. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.d.ts +18 -0
  130. package/node_modules/@llblab/pi-telegram/dist/lib/bus-api.js +254 -0
  131. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.d.ts +464 -0
  132. package/node_modules/@llblab/pi-telegram/dist/lib/bus-follower.js +1689 -0
  133. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.d.ts +292 -0
  134. package/node_modules/@llblab/pi-telegram/dist/lib/bus-leader.js +2242 -0
  135. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.d.ts +64 -0
  136. package/node_modules/@llblab/pi-telegram/dist/lib/bus-transport.js +140 -0
  137. package/node_modules/@llblab/pi-telegram/dist/lib/bus.d.ts +518 -0
  138. package/node_modules/@llblab/pi-telegram/dist/lib/bus.js +2055 -0
  139. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.d.ts +170 -0
  140. package/node_modules/@llblab/pi-telegram/dist/lib/channel-posts.js +611 -0
  141. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.d.ts +70 -0
  142. package/node_modules/@llblab/pi-telegram/dist/lib/command-templates.js +744 -0
  143. package/node_modules/@llblab/pi-telegram/dist/lib/commands.d.ts +541 -0
  144. package/node_modules/@llblab/pi-telegram/dist/lib/commands.js +1155 -0
  145. package/node_modules/@llblab/pi-telegram/dist/lib/config.d.ts +252 -0
  146. package/node_modules/@llblab/pi-telegram/dist/lib/config.js +889 -0
  147. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.d.ts +163 -0
  148. package/node_modules/@llblab/pi-telegram/dist/lib/delivery.js +542 -0
  149. package/node_modules/@llblab/pi-telegram/dist/lib/extension.d.ts +7 -0
  150. package/node_modules/@llblab/pi-telegram/dist/lib/extension.js +1604 -0
  151. package/node_modules/@llblab/pi-telegram/dist/lib/generative-app-worker.mjs +104 -0
  152. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.d.ts +212 -0
  153. package/node_modules/@llblab/pi-telegram/dist/lib/generative-apps.js +1006 -0
  154. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.d.ts +91 -0
  155. package/node_modules/@llblab/pi-telegram/dist/lib/inbound.js +502 -0
  156. package/node_modules/@llblab/pi-telegram/dist/lib/journal.d.ts +665 -0
  157. package/node_modules/@llblab/pi-telegram/dist/lib/journal.js +3701 -0
  158. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.d.ts +23 -0
  159. package/node_modules/@llblab/pi-telegram/dist/lib/keyboard.js +37 -0
  160. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.d.ts +157 -0
  161. package/node_modules/@llblab/pi-telegram/dist/lib/lifecycle.js +395 -0
  162. package/node_modules/@llblab/pi-telegram/dist/lib/locks.d.ts +164 -0
  163. package/node_modules/@llblab/pi-telegram/dist/lib/locks.js +1208 -0
  164. package/node_modules/@llblab/pi-telegram/dist/lib/logging.d.ts +50 -0
  165. package/node_modules/@llblab/pi-telegram/dist/lib/logging.js +274 -0
  166. package/node_modules/@llblab/pi-telegram/dist/lib/media.d.ts +181 -0
  167. package/node_modules/@llblab/pi-telegram/dist/lib/media.js +602 -0
  168. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.d.ts +217 -0
  169. package/node_modules/@llblab/pi-telegram/dist/lib/menu-model.js +663 -0
  170. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.d.ts +37 -0
  171. package/node_modules/@llblab/pi-telegram/dist/lib/menu-queue.js +408 -0
  172. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.d.ts +115 -0
  173. package/node_modules/@llblab/pi-telegram/dist/lib/menu-settings.js +595 -0
  174. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.d.ts +32 -0
  175. package/node_modules/@llblab/pi-telegram/dist/lib/menu-status.js +112 -0
  176. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.d.ts +29 -0
  177. package/node_modules/@llblab/pi-telegram/dist/lib/menu-thinking.js +82 -0
  178. package/node_modules/@llblab/pi-telegram/dist/lib/menu.d.ts +171 -0
  179. package/node_modules/@llblab/pi-telegram/dist/lib/menu.js +323 -0
  180. package/node_modules/@llblab/pi-telegram/dist/lib/model.d.ts +127 -0
  181. package/node_modules/@llblab/pi-telegram/dist/lib/model.js +409 -0
  182. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.d.ts +241 -0
  183. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-attachments.js +639 -0
  184. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.d.ts +69 -0
  185. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-buttons.js +248 -0
  186. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.d.ts +42 -0
  187. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-markup.js +678 -0
  188. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.d.ts +55 -0
  189. package/node_modules/@llblab/pi-telegram/dist/lib/outbound-voice.js +152 -0
  190. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.d.ts +185 -0
  191. package/node_modules/@llblab/pi-telegram/dist/lib/outbound.js +516 -0
  192. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.d.ts +77 -0
  193. package/node_modules/@llblab/pi-telegram/dist/lib/ownership.js +174 -0
  194. package/node_modules/@llblab/pi-telegram/dist/lib/paths.d.ts +40 -0
  195. package/node_modules/@llblab/pi-telegram/dist/lib/paths.js +94 -0
  196. package/node_modules/@llblab/pi-telegram/dist/lib/pi.d.ts +72 -0
  197. package/node_modules/@llblab/pi-telegram/dist/lib/pi.js +121 -0
  198. package/node_modules/@llblab/pi-telegram/dist/lib/polling.d.ts +351 -0
  199. package/node_modules/@llblab/pi-telegram/dist/lib/polling.js +1196 -0
  200. package/node_modules/@llblab/pi-telegram/dist/lib/preview.d.ts +192 -0
  201. package/node_modules/@llblab/pi-telegram/dist/lib/preview.js +614 -0
  202. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.d.ts +24 -0
  203. package/node_modules/@llblab/pi-telegram/dist/lib/prompt-templates.js +118 -0
  204. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.d.ts +57 -0
  205. package/node_modules/@llblab/pi-telegram/dist/lib/prompts.js +167 -0
  206. package/node_modules/@llblab/pi-telegram/dist/lib/queue.d.ts +766 -0
  207. package/node_modules/@llblab/pi-telegram/dist/lib/queue.js +1965 -0
  208. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.d.ts +86 -0
  209. package/node_modules/@llblab/pi-telegram/dist/lib/recovery.js +285 -0
  210. package/node_modules/@llblab/pi-telegram/dist/lib/rendering.d.ts +20 -0
  211. package/node_modules/@llblab/pi-telegram/dist/lib/rendering.js +983 -0
  212. package/node_modules/@llblab/pi-telegram/dist/lib/replies.d.ts +214 -0
  213. package/node_modules/@llblab/pi-telegram/dist/lib/replies.js +737 -0
  214. package/node_modules/@llblab/pi-telegram/dist/lib/routing.d.ts +207 -0
  215. package/node_modules/@llblab/pi-telegram/dist/lib/routing.js +2282 -0
  216. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.d.ts +172 -0
  217. package/node_modules/@llblab/pi-telegram/dist/lib/runtime.js +402 -0
  218. package/node_modules/@llblab/pi-telegram/dist/lib/sections.d.ts +165 -0
  219. package/node_modules/@llblab/pi-telegram/dist/lib/sections.js +327 -0
  220. package/node_modules/@llblab/pi-telegram/dist/lib/setup.d.ts +82 -0
  221. package/node_modules/@llblab/pi-telegram/dist/lib/setup.js +150 -0
  222. package/node_modules/@llblab/pi-telegram/dist/lib/skills.d.ts +8 -0
  223. package/node_modules/@llblab/pi-telegram/dist/lib/skills.js +12 -0
  224. package/node_modules/@llblab/pi-telegram/dist/lib/status.d.ts +442 -0
  225. package/node_modules/@llblab/pi-telegram/dist/lib/status.js +1000 -0
  226. package/node_modules/@llblab/pi-telegram/dist/lib/sync.d.ts +179 -0
  227. package/node_modules/@llblab/pi-telegram/dist/lib/sync.js +782 -0
  228. package/node_modules/@llblab/pi-telegram/dist/lib/target.d.ts +20 -0
  229. package/node_modules/@llblab/pi-telegram/dist/lib/target.js +27 -0
  230. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.d.ts +541 -0
  231. package/node_modules/@llblab/pi-telegram/dist/lib/telegram-api.js +1159 -0
  232. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.d.ts +89 -0
  233. package/node_modules/@llblab/pi-telegram/dist/lib/text-groups.js +317 -0
  234. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.d.ts +288 -0
  235. package/node_modules/@llblab/pi-telegram/dist/lib/thread-cleanup-manager.js +560 -0
  236. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.d.ts +46 -0
  237. package/node_modules/@llblab/pi-telegram/dist/lib/thread-display.js +257 -0
  238. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.d.ts +46 -0
  239. package/node_modules/@llblab/pi-telegram/dist/lib/thread-naming.js +78 -0
  240. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.d.ts +239 -0
  241. package/node_modules/@llblab/pi-telegram/dist/lib/thread-reconciler.js +644 -0
  242. package/node_modules/@llblab/pi-telegram/dist/lib/threads.d.ts +621 -0
  243. package/node_modules/@llblab/pi-telegram/dist/lib/threads.js +3679 -0
  244. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.d.ts +15 -0
  245. package/node_modules/@llblab/pi-telegram/dist/lib/time-injection.js +56 -0
  246. package/node_modules/@llblab/pi-telegram/dist/lib/turns.d.ts +109 -0
  247. package/node_modules/@llblab/pi-telegram/dist/lib/turns.js +500 -0
  248. package/node_modules/@llblab/pi-telegram/dist/lib/updates.d.ts +1290 -0
  249. package/node_modules/@llblab/pi-telegram/dist/lib/updates.js +3634 -0
  250. package/node_modules/@llblab/pi-telegram/dist/lib/voice.d.ts +117 -0
  251. package/node_modules/@llblab/pi-telegram/dist/lib/voice.js +174 -0
  252. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.d.ts +264 -0
  253. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-admission.js +1136 -0
  254. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.d.ts +219 -0
  255. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-retirement.js +587 -0
  256. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.d.ts +30 -0
  257. package/node_modules/@llblab/pi-telegram/dist/lib/workspace-slots.js +54 -0
  258. package/node_modules/@llblab/pi-telegram/dist/package.json +126 -0
  259. package/node_modules/@llblab/pi-telegram/dist/pi-telegram/index.js +1 -0
  260. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/SKILL.md +107 -0
  261. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/references/capability-adapters.md +27 -0
  262. package/node_modules/@llblab/pi-telegram/dist/skills/generated-control-surface/references/layout-and-state.md +37 -0
  263. package/node_modules/@llblab/pi-telegram/dist/skills/generative-apps/SKILL.md +115 -0
  264. package/node_modules/@llblab/pi-telegram/dist/skills/show-me/SKILL.md +166 -0
  265. package/node_modules/@llblab/pi-telegram/dist/skills/show-me/references/telegram-surfaces.md +43 -0
  266. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/SKILL.md +129 -0
  267. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/configuration.md +15 -0
  268. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/delivery-and-threads.md +27 -0
  269. package/node_modules/@llblab/pi-telegram/dist/skills/telegram-bridge/references/diagnosis.md +18 -0
  270. package/node_modules/@llblab/pi-telegram/docs/README.md +2 -0
  271. package/node_modules/@llblab/pi-telegram/docs/architecture.md +4 -2
  272. package/node_modules/@llblab/pi-telegram/docs/compact-matrix-literal.md +10 -3
  273. package/node_modules/@llblab/pi-telegram/docs/generative-apps.md +15 -13
  274. package/node_modules/@llblab/pi-telegram/docs/multi-instance-bus.md +6 -4
  275. package/node_modules/@llblab/pi-telegram/docs/outbound.md +1 -1
  276. package/node_modules/@llblab/pi-telegram/docs/public-api.md +3 -3
  277. package/node_modules/@llblab/pi-telegram/lib/bindings.ts +89 -6
  278. package/node_modules/@llblab/pi-telegram/lib/bus-follower.ts +12 -5
  279. package/node_modules/@llblab/pi-telegram/lib/bus-leader.ts +44 -19
  280. package/node_modules/@llblab/pi-telegram/lib/bus.ts +4 -1
  281. package/node_modules/@llblab/pi-telegram/lib/commands.ts +2 -2
  282. package/node_modules/@llblab/pi-telegram/lib/config.ts +14 -7
  283. package/node_modules/@llblab/pi-telegram/lib/delivery.ts +38 -6
  284. package/node_modules/@llblab/pi-telegram/lib/extension.ts +7 -0
  285. package/node_modules/@llblab/pi-telegram/lib/generative-apps.ts +379 -13
  286. package/node_modules/@llblab/pi-telegram/lib/menu-settings.ts +20 -6
  287. package/node_modules/@llblab/pi-telegram/lib/outbound-markup.ts +16 -7
  288. package/node_modules/@llblab/pi-telegram/lib/status.ts +9 -15
  289. package/node_modules/@llblab/pi-telegram/lib/telegram-api.ts +12 -1
  290. package/node_modules/@llblab/pi-telegram/lib/thread-display.ts +96 -18
  291. package/node_modules/@llblab/pi-telegram/package.json +56 -13
  292. package/node_modules/@llblab/pi-telegram/scripts/build-dist.mjs +44 -0
  293. package/node_modules/@llblab/pi-telegram/scripts/measure-bus.mjs +8 -1
  294. package/node_modules/@llblab/pi-telegram/scripts/measure-workspace.mjs +8 -1
  295. package/node_modules/@llblab/pi-telegram/skills/generative-apps/SKILL.md +1 -1
  296. package/node_modules/@llblab/pi-telegram/skills/show-me/SKILL.md +1 -1
  297. package/node_modules/@llblab/pi-telegram/skills/show-me/references/telegram-surfaces.md +1 -1
  298. package/node_modules/@llblab/pi-telegram/skills/telegram-bridge/SKILL.md +1 -1
  299. package/package.json +7 -7
@@ -0,0 +1,72 @@
1
+ import { type DurableFileBase } from "./durable.ts";
2
+ import { type ArtifactProvenanceRegistry } from "./artifact.ts";
3
+ import { type ScopeStream, type TemporalState } from "./temporal.ts";
4
+ import { type SessionRuntime, type Snapshot } from "./snapshot.ts";
5
+ import type { StateScope } from "./state.ts";
6
+ export interface GitPushResult {
7
+ status: "pushed" | "local" | "pending";
8
+ commit: string;
9
+ error?: string;
10
+ }
11
+ /** Explicit start only: initialize this exact root, preserving existing files and ancestor Git. */
12
+ export declare function initializeGitRepository(repositoryRoot: string): void;
13
+ export interface TemporalGitBase {
14
+ head?: string;
15
+ files: DurableFileBase[];
16
+ }
17
+ export interface TemporalRevisionLoad {
18
+ base: TemporalGitBase;
19
+ scopes: Record<StateScope, ScopeStream | undefined>;
20
+ runtime?: {
21
+ document: SessionRuntime;
22
+ revision: string;
23
+ };
24
+ /** Runtime-owned artifact provenance retained at this revision. */
25
+ provenance: Record<StateScope, ArtifactProvenanceRegistry>;
26
+ }
27
+ export declare function captureTemporalGitBase(cwd: string, sessionId: string, repositoryRoot: string, sessionKey?: string): TemporalGitBase;
28
+ /** Cold scope-stream reconstruction from canonical revision paths only. */
29
+ export declare function loadTemporalRevision(cwd: string, sessionId: string, repositoryRoot: string, revision: string, sessionKey?: string): TemporalRevisionLoad;
30
+ export interface StorageMigrationPublication {
31
+ commit?: string;
32
+ push?: GitPushResult;
33
+ scopes: StateScope[];
34
+ }
35
+ /** Explicit migration entrypoint; initialization adopts it only with the temporal writer cutover. */
36
+ export declare function migrateLegacyStorageToGit(cwd: string, sessionId: string, repositoryRoot: string, sessionKey?: string): StorageMigrationPublication;
37
+ /** Explicit current-file adoption, not reconstruction or invention of pre-Git history. */
38
+ export declare function adoptFileStateToGit(cwd: string, sessionId: string, repositoryRoot: string, revision: string, snapshot: Snapshot, sessionKey?: string, push?: boolean): {
39
+ commit?: string;
40
+ push?: GitPushResult;
41
+ revision: string;
42
+ view: {
43
+ scopes: Record<StateScope, ScopeStream>;
44
+ lineage: import("./temporal.ts").TransitionBoundary[];
45
+ };
46
+ provenance: Record<StateScope, ArtifactProvenanceRegistry>;
47
+ base: {
48
+ head: string | undefined;
49
+ files: DurableFileBase[];
50
+ };
51
+ };
52
+ /** Persist selected streams from one validated view, never derive checkpoints from current state. */
53
+ export declare function publishTemporalStateToGit(cwd: string, sessionId: string, view: TemporalState, scopes: readonly StateScope[], base: TemporalGitBase, repositoryRoot: string, runtime?: SessionRuntime, sessionKey?: string, push?: boolean, provenance?: Readonly<Record<StateScope, ArtifactProvenanceRegistry>>): {
54
+ base: TemporalGitBase;
55
+ commit?: string;
56
+ push?: GitPushResult;
57
+ };
58
+ export declare function resolveGitPushDestination(repositoryRoot: string): {
59
+ gitCommonDir: string;
60
+ remote: string;
61
+ ref: string;
62
+ } | undefined;
63
+ /** Read-only publication policy; configuration errors are not local-only success. */
64
+ export declare function isLocalGitRepository(repositoryRoot: string): boolean;
65
+ /** Push an already-created commit exactly; failures are publication state, not transition rejection. */
66
+ export declare function isGitCommitAncestor(repositoryRoot: string, ancestor: string, descendant: string): boolean;
67
+ /** Own one non-interactive exact-target push; cancellation is not confirmation of child exit. */
68
+ export declare function pushGitTarget(repositoryRoot: string, destination: {
69
+ remote: string;
70
+ ref: string;
71
+ }, commit: string, signal?: AbortSignal): Promise<void>;
72
+ export declare function pushGitCommit(repositoryRoot: string, commit: string): GitPushResult;
@@ -0,0 +1,565 @@
1
+ // Domain: durable Git revision reads, compare-and-swap publication, and exact-commit push retry.
2
+ import { createHash } from "node:crypto";
3
+ import { closeSync, lstatSync, mkdirSync, mkdtempSync, openSync, rmSync, writeFileSync } from "node:fs";
4
+ import { tmpdir } from "node:os";
5
+ import { dirname, relative, resolve, sep } from "node:path";
6
+ import { spawn, spawnSync } from "node:child_process";
7
+ import { assertOwnedFileUpdates, captureOwnedFileBases, captureTemporalFileBases, isStateFlowOwnedPath, parseScopeProvenance, parseScopeStream, restoreDurableFileBases, temporalScopePaths, sessionRuntimePaths, writeOwnedFileUpdates, } from "./durable.js";
8
+ import { parseArtifactProvenanceRegistry } from "./artifact.js";
9
+ import { planLegacyStorageMigration } from "./migration.js";
10
+ import { sameJson } from "./json.js";
11
+ import { validateTemporalState } from "./temporal.js";
12
+ import { createSessionRuntime, parseSessionRuntime, serializeSessionRuntime } from "./snapshot.js";
13
+ import { assertTemporalFileBase, loadTemporalFileRevision, planTemporalPublication, temporalFileReceipts, withStoragePublicationLock } from "./storage.js";
14
+ const GIT_TIMEOUT_MS = 15_000;
15
+ const STATE_FLOW_COMMIT_TRAILER = "State-Flow-Durable: v1";
16
+ function git(repositoryRoot, args, options = {}) {
17
+ const result = spawnSync("git", ["-C", repositoryRoot, ...args], {
18
+ encoding: "utf8",
19
+ timeout: GIT_TIMEOUT_MS,
20
+ input: options.input,
21
+ ...(options.maxBuffer === undefined ? {} : { maxBuffer: options.maxBuffer }),
22
+ env: {
23
+ ...process.env,
24
+ GIT_TERMINAL_PROMPT: "0",
25
+ ...options.env,
26
+ },
27
+ });
28
+ const status = result.status ?? 1;
29
+ const stdout = result.stdout ?? "";
30
+ const stderr = result.error?.message ?? result.stderr ?? "";
31
+ if (status !== 0 && !options.allowFailure) {
32
+ const detail = stderr.trim() || stdout.trim() || `exit status ${status}`;
33
+ throw new Error(`Git command failed (${args.join(" ")}): ${detail}`);
34
+ }
35
+ return { status, stdout, stderr };
36
+ }
37
+ function assertDirectoryPath(path) {
38
+ const parent = dirname(path);
39
+ if (parent !== path)
40
+ assertDirectoryPath(parent);
41
+ const stat = lstatSync(path, { throwIfNoEntry: false });
42
+ if (stat && (!stat.isDirectory() || stat.isSymbolicLink()))
43
+ throw new Error(`State Flow repository path is not a regular directory: ${path}`);
44
+ }
45
+ /** Explicit start only: initialize this exact root, preserving existing files and ancestor Git. */
46
+ export function initializeGitRepository(repositoryRoot) {
47
+ const root = resolve(repositoryRoot);
48
+ assertDirectoryPath(root);
49
+ if (lstatSync(resolve(root, ".git"), { throwIfNoEntry: false })) {
50
+ assertRepositoryRoot(root);
51
+ return;
52
+ }
53
+ mkdirSync(root, { recursive: true });
54
+ git(root, ["init"]);
55
+ assertRepositoryRoot(root);
56
+ }
57
+ function assertRepositoryRoot(repositoryRoot) {
58
+ const expected = resolve(repositoryRoot);
59
+ assertDirectoryPath(expected);
60
+ if (lstatSync(resolve(expected, ".git"), { throwIfNoEntry: false })?.isSymbolicLink()) {
61
+ throw new Error(`State Flow Git metadata must not be a symlink: ${expected}`);
62
+ }
63
+ const actual = resolve(git(expected, ["rev-parse", "--show-toplevel"]).stdout.trim());
64
+ if (actual !== expected) {
65
+ throw new Error(`State Flow durable repository root mismatch: expected ${expected}, found ${actual}`);
66
+ }
67
+ return expected;
68
+ }
69
+ /** Serialize cooperating State Flow publishers through capture, commit, and rollback. */
70
+ function withPublicationLock(repositoryRoot, action) {
71
+ return withStoragePublicationLock(repositoryRoot, (lockedRoot) => {
72
+ const root = assertRepositoryRoot(lockedRoot);
73
+ const common = resolve(root, git(root, ["rev-parse", "--git-common-dir"]).stdout.trim());
74
+ const path = resolve(common, "state-flow-publication.lock");
75
+ let descriptor;
76
+ try {
77
+ descriptor = openSync(path, "wx", 0o600);
78
+ }
79
+ catch (error) {
80
+ throw new Error(`State Flow publication lock is unavailable at ${path}; reconcile the active or interrupted publisher before retrying`, { cause: error });
81
+ }
82
+ try {
83
+ writeFileSync(descriptor, `${process.pid}\n`);
84
+ return action(root);
85
+ }
86
+ finally {
87
+ closeSync(descriptor);
88
+ rmSync(path);
89
+ }
90
+ });
91
+ }
92
+ function currentHead(repositoryRoot) {
93
+ const result = git(repositoryRoot, ["rev-parse", "--verify", "HEAD"], { allowFailure: true });
94
+ return result.status === 0 ? result.stdout.trim() : undefined;
95
+ }
96
+ function currentBranchRef(repositoryRoot) {
97
+ const result = git(repositoryRoot, ["symbolic-ref", "--quiet", "HEAD"], { allowFailure: true });
98
+ if (result.status !== 0 || result.stdout.trim().length === 0) {
99
+ throw new Error("State Flow durable publication requires an attached Git branch");
100
+ }
101
+ return result.stdout.trim();
102
+ }
103
+ /** One exact-path tree query per immutable revision; inspect only blobs the caller actually selects. */
104
+ function revisionFileReader(repositoryRoot, revision, paths) {
105
+ const relativePaths = new Map(paths.map((path) => [path, relativeOwnedPath(path, repositoryRoot)]));
106
+ if (relativePaths.size === 0)
107
+ throw new Error("Git revision reader requires owned paths");
108
+ const selected = new Set(relativePaths.values());
109
+ const listing = git(repositoryRoot, ["ls-tree", "-z", revision, "--", ...selected], { env: {
110
+ GIT_LITERAL_PATHSPECS: "1", GIT_GLOB_PATHSPECS: "0", GIT_NOGLOB_PATHSPECS: "0", GIT_ICASE_PATHSPECS: "0",
111
+ } }).stdout;
112
+ if (listing.length > 0 && !listing.endsWith("\0"))
113
+ throw new Error("Historical Git tree listing is incomplete");
114
+ const entries = new Map();
115
+ for (const entry of listing.split("\0").filter(Boolean)) {
116
+ const separator = entry.indexOf("\t");
117
+ if (separator < 0)
118
+ throw new Error("Historical Git tree listing is malformed");
119
+ const path = entry.slice(separator + 1);
120
+ if (!selected.has(path))
121
+ continue;
122
+ entries.set(path, entries.has(path) ? null : entry.slice(0, separator));
123
+ }
124
+ const files = new Map();
125
+ return (path) => {
126
+ const relativePath = relativePaths.get(path);
127
+ if (relativePath === undefined)
128
+ throw new Error(`Git revision reader did not select path: ${path}`);
129
+ const cached = files.get(path);
130
+ if (cached)
131
+ return cached;
132
+ const entry = entries.get(relativePath);
133
+ if (entry === null)
134
+ throw new Error(`Historical Git tree has duplicate path: ${relativePath}`);
135
+ if (entry === undefined) {
136
+ const missing = { path, identity: "missing" };
137
+ files.set(path, missing);
138
+ return missing;
139
+ }
140
+ if (!/^100(?:644|755) blob [0-9a-f]+$/.test(entry)) {
141
+ throw new Error(`Historical State Flow file is not a regular blob: ${path}`);
142
+ }
143
+ // Selected state/runtime blobs have no semantic byte cap; Node's default pipe budget is only 1 MiB.
144
+ const content = git(repositoryRoot, ["show", `${revision}:${relativePath}`], { maxBuffer: Infinity }).stdout;
145
+ const file = { path, identity: `sha256:${createHash("sha256").update(content).digest("hex")}`, content };
146
+ files.set(path, file);
147
+ return file;
148
+ };
149
+ }
150
+ function revisionFile(repositoryRoot, revision, path) {
151
+ return revisionFileReader(repositoryRoot, revision, [path])(path);
152
+ }
153
+ function assertReadableRevision(root, revision) {
154
+ if (!/^[0-9a-f]{40,64}$/.test(revision)
155
+ || git(root, ["cat-file", "-e", `${revision}^{commit}`], { allowFailure: true }).status !== 0) {
156
+ throw new Error(`State Flow revision is not a readable Git commit: ${revision}`);
157
+ }
158
+ }
159
+ export function captureTemporalGitBase(cwd, sessionId, repositoryRoot, sessionKey = sessionId) {
160
+ return withPublicationLock(repositoryRoot, (root) => captureTemporalBaseUnderLock(cwd, sessionId, root, sessionKey));
161
+ }
162
+ function captureTemporalBaseUnderLock(cwd, sessionId, root, sessionKey = sessionId) {
163
+ return { head: currentHead(root), files: captureTemporalFileBases(cwd, sessionId, root, sessionKey) };
164
+ }
165
+ function revisionScopeFiles(read, paths) {
166
+ return {
167
+ paths,
168
+ checkpoint: read(paths.checkpoint),
169
+ patches: read(paths.patches),
170
+ meta: read(paths.meta),
171
+ };
172
+ }
173
+ /** Cold scope-stream reconstruction from canonical revision paths only. */
174
+ export function loadTemporalRevision(cwd, sessionId, repositoryRoot, revision, sessionKey = sessionId) {
175
+ const root = assertRepositoryRoot(repositoryRoot);
176
+ assertReadableRevision(root, revision);
177
+ const scopePaths = ["global", "cwd", "session"].map((scope) => ({
178
+ scope, paths: temporalScopePaths(cwd, sessionId, scope, root, sessionKey),
179
+ }));
180
+ const canonicalRuntime = sessionRuntimePaths(cwd, sessionId, root, sessionKey);
181
+ const readFile = revisionFileReader(root, revision, [
182
+ ...scopePaths.flatMap(({ paths }) => [paths.checkpoint, paths.patches, paths.meta]),
183
+ canonicalRuntime.config, canonicalRuntime.meta,
184
+ ]);
185
+ const files = [];
186
+ const scopes = {};
187
+ const provenance = { global: {}, cwd: {}, session: {} };
188
+ for (const { scope, paths } of scopePaths) {
189
+ const selected = revisionScopeFiles(readFile, paths);
190
+ files.push(selected.checkpoint, selected.patches, ...(scope === "session" ? [] : [selected.meta]));
191
+ if (scope !== "session")
192
+ provenance[scope] = parseScopeProvenance(selected.meta.content, selected.meta.path);
193
+ try {
194
+ scopes[scope] = parseScopeStream(selected.checkpoint.content, selected.patches.content, scope, scope === "cwd" ? cwd : undefined, selected.meta.content);
195
+ }
196
+ catch (error) {
197
+ throw new Error(`Invalid historical State Flow ${scope} scope`, { cause: error });
198
+ }
199
+ }
200
+ const readRuntime = (paths) => ({
201
+ paths, config: readFile(paths.config), meta: readFile(paths.meta),
202
+ });
203
+ const { paths: runtimePaths, config, meta } = readRuntime(canonicalRuntime);
204
+ files.push(config, meta);
205
+ const document = parseSessionRuntime(config.content, meta.content, cwd, sessionId);
206
+ if (document === undefined)
207
+ return { base: { head: revision, files }, scopes, provenance };
208
+ provenance.session = parseArtifactProvenanceRegistry(document.meta.artifacts, "State Flow session artifact provenance");
209
+ const owner = git(root, ["log", "-1", "--format=%H", revision, "--",
210
+ relativeOwnedPath(runtimePaths.config, root), relativeOwnedPath(runtimePaths.meta, root),
211
+ ]).stdout.trim();
212
+ assertReadableRevision(root, owner);
213
+ let temporalRevision = document.meta.temporalRevision === undefined || document.meta.temporalRevision === "self"
214
+ ? owner : document.meta.temporalRevision;
215
+ if (temporalRevision !== revision) {
216
+ const ancestor = git(root, ["merge-base", "--is-ancestor", temporalRevision, revision], { allowFailure: true }).status === 0;
217
+ const parents = git(root, ["rev-list", "--parents", "-n", "1", revision]).stdout.trim().split(/\s+/);
218
+ // A store-wide semantic migration intentionally replaces all prior history with one root.
219
+ // Its complete tree owns every scope, so predecessor temporal pointers collapse to self.
220
+ if (!ancestor && parents.length === 1)
221
+ temporalRevision = owner;
222
+ else if (!ancestor) {
223
+ throw new Error("Temporal revision must be an ancestor of its runtime owner");
224
+ }
225
+ const selected = loadTemporalRevision(cwd, sessionId, root, temporalRevision, sessionKey);
226
+ Object.assign(scopes, selected.scopes);
227
+ Object.assign(provenance, selected.provenance);
228
+ }
229
+ if (scopes.global === undefined || scopes.cwd === undefined || scopes.session === undefined) {
230
+ throw new Error("Session runtime has incomplete temporal scope storage");
231
+ }
232
+ validateTemporalState({ lineage: document.meta.lineage, scopes: { global: scopes.global, cwd: scopes.cwd, session: scopes.session } });
233
+ return { base: { head: revision, files }, scopes, runtime: { document, revision: owner }, provenance };
234
+ }
235
+ function relativeOwnedPath(path, repositoryRoot) {
236
+ const output = relative(repositoryRoot, path);
237
+ if (output === "" || output === ".." || output.startsWith(`..${sep}`) || !isStateFlowOwnedPath(path, repositoryRoot)) {
238
+ throw new Error(`Git publication received a non-State Flow path: ${path}`);
239
+ }
240
+ return output.split(sep).join("/");
241
+ }
242
+ function commitOwnedFiles(repositoryRoot, updates, expectedHead, scopes, operation = "persist", rootCommit = false) {
243
+ assertOwnedFileUpdates(updates, repositoryRoot);
244
+ const branchRef = currentBranchRef(repositoryRoot);
245
+ const observedHead = currentHead(repositoryRoot);
246
+ if (observedHead !== expectedHead) {
247
+ throw new Error("Durable State Flow Git base changed concurrently; reload before publishing");
248
+ }
249
+ const temporary = mkdtempSync(`${tmpdir()}${sep}state-flow-index-`);
250
+ const indexPath = `${temporary}${sep}index`;
251
+ const env = { GIT_INDEX_FILE: indexPath };
252
+ try {
253
+ if (expectedHead === undefined)
254
+ git(repositoryRoot, ["read-tree", "--empty"], { env });
255
+ else
256
+ git(repositoryRoot, ["read-tree", expectedHead], { env });
257
+ // A State Flow commit carries the complete non-ignored worktree delta, including user edits
258
+ // and manual deletions, while `.gitignore` stays authoritative for untracked files. The
259
+ // transient publication lock is ours, not repository content.
260
+ git(repositoryRoot, ["add", "-A", "--", ".", ":(exclude).state-flow-publication.lock"], { env });
261
+ const entries = [];
262
+ for (const update of updates) {
263
+ const relativePath = relativeOwnedPath(update.path, repositoryRoot);
264
+ if (update.content === undefined) {
265
+ git(repositoryRoot, ["update-index", "--force-remove", "--", relativePath], { env });
266
+ continue;
267
+ }
268
+ const blob = git(repositoryRoot, ["hash-object", "-w", "--stdin"], { input: update.content }).stdout.trim();
269
+ entries.push(`100644 ${blob}\t${relativePath}\0`);
270
+ }
271
+ // NUL framing preserves literal path characters while the blobs retain exact prepared bytes.
272
+ if (entries.length > 0)
273
+ git(repositoryRoot, ["update-index", "-z", "--index-info"], { env, input: entries.join("") });
274
+ const tree = git(repositoryRoot, ["write-tree"], { env }).stdout.trim();
275
+ if (expectedHead !== undefined && !rootCommit) {
276
+ const previousTree = git(repositoryRoot, ["rev-parse", `${expectedHead}^{tree}`]).stdout.trim();
277
+ if (tree === previousTree)
278
+ return undefined;
279
+ }
280
+ const message = `state-flow: ${operation} ${scopes.join("+") || "runtime"} transition\n\n${STATE_FLOW_COMMIT_TRAILER}\n`;
281
+ const commitArgs = ["commit-tree", tree];
282
+ if (expectedHead !== undefined && !rootCommit)
283
+ commitArgs.push("-p", expectedHead);
284
+ const commit = git(repositoryRoot, commitArgs, { input: message }).stdout.trim();
285
+ const zero = "0".repeat(40);
286
+ assertOwnedFileUpdates(updates, repositoryRoot);
287
+ git(repositoryRoot, ["update-ref", branchRef, commit, expectedHead ?? zero]);
288
+ try {
289
+ // Align the caller-visible index with the committed tree so advancing HEAD through the
290
+ // isolated index leaves no artificial staged/unstaged status entries behind.
291
+ git(repositoryRoot, ["read-tree", commit]);
292
+ }
293
+ catch (error) {
294
+ git(repositoryRoot, ["update-ref", branchRef, expectedHead ?? zero, commit]);
295
+ throw error;
296
+ }
297
+ return commit;
298
+ }
299
+ finally {
300
+ rmSync(temporary, { recursive: true, force: true });
301
+ }
302
+ }
303
+ /** Explicit migration entrypoint; initialization adopts it only with the temporal writer cutover. */
304
+ export function migrateLegacyStorageToGit(cwd, sessionId, repositoryRoot, sessionKey = sessionId) {
305
+ return withPublicationLock(repositoryRoot, (root) => migrateLegacyStorageUnderLock(cwd, sessionId, root, sessionKey));
306
+ }
307
+ function migrateLegacyStorageUnderLock(cwd, sessionId, root, sessionKey = sessionId) {
308
+ const plan = planLegacyStorageMigration(cwd, sessionId, root, undefined, sessionKey);
309
+ if (plan.updates.length === 0)
310
+ return { scopes: [] };
311
+ const current = captureOwnedFileBases(plan.bases.map(({ path }) => path), root);
312
+ if (current.some((base, index) => base.identity !== plan.bases[index].identity)) {
313
+ throw new Error("State Flow storage changed concurrently while planning migration");
314
+ }
315
+ return { scopes: plan.scopes, ...publishOwnedCohort(root, plan.updates, plan.bases, currentHead(root), plan.scopes, "migrate", false, true) };
316
+ }
317
+ function publishOwnedCohort(root, updates, bases, head, scopes, operation, push = true, rootCommit = false) {
318
+ let published = false;
319
+ try {
320
+ writeOwnedFileUpdates(updates, bases, root);
321
+ published = true;
322
+ const commit = commitOwnedFiles(root, updates, head, scopes, operation, rootCommit);
323
+ return commit === undefined ? {} : push ? { commit, push: pushGitCommit(root, commit) } : { commit };
324
+ }
325
+ catch (error) {
326
+ if (published) {
327
+ try {
328
+ const touched = new Set(updates.map(({ path }) => path));
329
+ restoreDurableFileBases(bases.filter(({ path }) => touched.has(path)), root, updates);
330
+ }
331
+ catch (rollbackError) {
332
+ throw new AggregateError([error, rollbackError], "State Flow publication and rollback failed");
333
+ }
334
+ }
335
+ throw error;
336
+ }
337
+ }
338
+ /** Explicit current-file adoption, not reconstruction or invention of pre-Git history. */
339
+ export function adoptFileStateToGit(cwd, sessionId, repositoryRoot, revision, snapshot, sessionKey = sessionId, push = true) {
340
+ const selected = loadTemporalFileRevision(cwd, sessionId, repositoryRoot, revision, sessionKey);
341
+ if (snapshot.meta.step !== selected.runtime.meta.step)
342
+ throw new Error("Git adoption must preserve the semantic step");
343
+ const runtime = createSessionRuntime(snapshot, cwd, sessionId, selected.view.lineage, "unconfirmed", selected.provenance.session);
344
+ runtime.meta.temporalRevision = "self";
345
+ const sources = serializeSessionRuntime(runtime, cwd, sessionId, selected.view.scopes.session, selected.base.files.find(({ path }) => path === sessionRuntimePaths(cwd, sessionId, repositoryRoot, sessionKey).meta)?.content);
346
+ initializeGitRepository(repositoryRoot);
347
+ return withPublicationLock(repositoryRoot, (root) => {
348
+ const current = captureTemporalBaseUnderLock(cwd, sessionId, root, sessionKey);
349
+ assertTemporalFileBase(selected.base, current);
350
+ const paths = sessionRuntimePaths(cwd, sessionId, root, sessionKey);
351
+ const provenancePaths = new Set([
352
+ temporalScopePaths(cwd, sessionId, "global", root, sessionKey).meta,
353
+ temporalScopePaths(cwd, sessionId, "cwd", root, sessionKey).meta,
354
+ ]);
355
+ // Preserve exact valid scope bytes; only runtime provenance changes representation.
356
+ const updates = current.files.filter(({ path, identity }) => path.endsWith("checkpoint.json")
357
+ || path.endsWith("patches.jsonl")
358
+ || (provenancePaths.has(path) && identity !== "missing"))
359
+ .map(({ path, content }) => ({ path, content: content }));
360
+ updates.push({ path: paths.config, content: sources.config }, { path: paths.meta, content: sources.meta });
361
+ const existing = current.head && updates.every(({ path, content }) => revisionFile(root, current.head, path).content === content)
362
+ ? loadTemporalRevision(cwd, sessionId, root, current.head, sessionKey) : undefined;
363
+ if (existing && (!existing.runtime || !sameJson({ lineage: existing.runtime.document.meta.lineage, scopes: existing.scopes }, selected.view))) {
364
+ throw new Error("Existing Git runtime does not anchor the selected file cohort");
365
+ }
366
+ const publication = publishOwnedCohort(root, updates, current.files, current.head, [], "persist", push);
367
+ const target = publication.commit ?? existing.runtime.revision;
368
+ const remote = push ? publication.push ?? pushGitCommit(root, target) : undefined;
369
+ return { ...publication, revision: target, ...(remote === undefined ? {} : { push: remote }), view: selected.view, provenance: selected.provenance,
370
+ base: { head: publication.commit ?? current.head, files: temporalFileReceipts(current, updates) } };
371
+ });
372
+ }
373
+ /** Working-tree equality alone cannot prove that a new commit contains the selected cohort. */
374
+ function includeUncommittedCohort(cwd, sessionId, root, current, updates, changedScopes, scopes, runtime, sessionKey = sessionId) {
375
+ const targets = new Map(updates.map((update) => [update.path, update]));
376
+ const desired = (paths) => paths.map((path) => targets.get(path) ?? { path, content: current.files.find((file) => file.path === path).content });
377
+ const pairs = ["global", "cwd", "session"].map((scope) => {
378
+ const paths = temporalScopePaths(cwd, sessionId, scope, root, sessionKey);
379
+ return { scope, pair: desired([paths.checkpoint, paths.patches]) };
380
+ });
381
+ const runtimePaths = runtime ? sessionRuntimePaths(cwd, sessionId, root, sessionKey) : undefined;
382
+ const runtimePair = runtimePaths ? desired([runtimePaths.config, runtimePaths.meta]) : [];
383
+ const readFile = current.head === undefined ? undefined : revisionFileReader(root, current.head, [...pairs.flatMap(({ pair }) => pair), ...runtimePair].map(({ path }) => path));
384
+ const absentFromHead = (files) => files.some(({ path, content }) => readFile === undefined || readFile(path).content !== content);
385
+ for (const { scope, pair } of pairs) {
386
+ if (!absentFromHead(pair))
387
+ continue;
388
+ if (!scopes.includes(scope))
389
+ throw new Error(`Temporal scope update omitted an uncommitted stream: ${scope}`);
390
+ for (const update of pair)
391
+ targets.set(update.path, update);
392
+ if (!changedScopes.includes(scope))
393
+ changedScopes.push(scope);
394
+ }
395
+ if (absentFromHead(runtimePair))
396
+ for (const update of runtimePair)
397
+ targets.set(update.path, update);
398
+ updates.splice(0, updates.length, ...targets.values());
399
+ }
400
+ /** Persist selected streams from one validated view, never derive checkpoints from current state. */
401
+ export function publishTemporalStateToGit(cwd, sessionId, view, scopes, base, repositoryRoot, runtime, sessionKey = sessionId, push = true, provenance) {
402
+ return withPublicationLock(repositoryRoot, (root) => {
403
+ const current = captureTemporalBaseUnderLock(cwd, sessionId, root, sessionKey);
404
+ assertTemporalFileBase(base, current);
405
+ if (runtime?.meta.publication === "files")
406
+ throw new Error("Git publication requires explicit Git provenance");
407
+ const runtimePaths = sessionRuntimePaths(cwd, sessionId, root, sessionKey);
408
+ const previousRuntime = parseSessionRuntime(current.files.find(({ path }) => path === runtimePaths.config)?.content, current.files.find(({ path }) => path === runtimePaths.meta)?.content, cwd, sessionId);
409
+ if (previousRuntime?.meta.publication === "files")
410
+ throw new Error("File-only storage requires explicit full-cohort Git adoption");
411
+ const runtimeOnly = runtime?.meta.temporalRevision !== undefined && runtime.meta.temporalRevision !== "self";
412
+ if (runtimeOnly) {
413
+ if (scopes.length !== 0)
414
+ throw new Error("Runtime-only publication cannot write semantic scopes");
415
+ const selected = loadTemporalRevision(cwd, sessionId, root, runtime.meta.temporalRevision, sessionKey);
416
+ if (!sameJson(selected.scopes, view.scopes))
417
+ throw new Error("Runtime temporal reference does not match selected streams");
418
+ }
419
+ const { updates, changedScopes } = planTemporalPublication(cwd, sessionId, view, scopes, current, root, runtime, runtimeOnly, sessionKey, provenance);
420
+ if (!runtimeOnly)
421
+ includeUncommittedCohort(cwd, sessionId, root, current, updates, changedScopes, scopes, runtime !== undefined, sessionKey);
422
+ if (updates.length === 0)
423
+ return { base: current };
424
+ const publication = publishOwnedCohort(root, updates, current.files, current.head, changedScopes, "persist", push);
425
+ const nextFiles = temporalFileReceipts(current, updates);
426
+ return { ...publication, base: { head: publication.commit ?? current.head, files: nextFiles } };
427
+ });
428
+ }
429
+ export function resolveGitPushDestination(repositoryRoot) {
430
+ const root = assertRepositoryRoot(repositoryRoot);
431
+ const common = git(root, ["rev-parse", "--git-common-dir"]).stdout.trim();
432
+ const gitCommonDir = resolve(root, common);
433
+ const destination = pushDestination(root);
434
+ return destination === undefined ? undefined : { gitCommonDir, ...destination };
435
+ }
436
+ function pushDestination(repositoryRoot) {
437
+ const branchRef = currentBranchRef(repositoryRoot);
438
+ const branch = branchRef.slice("refs/heads/".length);
439
+ const configuredRemote = git(repositoryRoot, ["config", "--get", `branch.${branch}.remote`], { allowFailure: true });
440
+ if (configuredRemote.status > 1)
441
+ throw new Error(configuredRemote.stderr || "Cannot inspect Git remote configuration");
442
+ let remote = configuredRemote.status === 0 ? configuredRemote.stdout.trim() : "";
443
+ if (remote.length === 0) {
444
+ const remotes = git(repositoryRoot, ["remote"]).stdout.trim().split(/\s+/).filter(Boolean);
445
+ if (remotes.length === 0)
446
+ return undefined;
447
+ if (remotes.includes("origin"))
448
+ remote = "origin";
449
+ else if (remotes.length === 1)
450
+ remote = remotes[0];
451
+ else
452
+ throw new Error("State Flow durable publication cannot select a Git remote");
453
+ }
454
+ if (remote === ".")
455
+ throw new Error("State Flow durable publication requires a non-local Git remote");
456
+ const configuredMerge = git(repositoryRoot, ["config", "--get", `branch.${branch}.merge`], { allowFailure: true });
457
+ const ref = configuredMerge.status === 0 && configuredMerge.stdout.trim().length > 0
458
+ ? configuredMerge.stdout.trim()
459
+ : branchRef;
460
+ return { remote, ref };
461
+ }
462
+ /** Read-only publication policy; configuration errors are not local-only success. */
463
+ export function isLocalGitRepository(repositoryRoot) {
464
+ return pushDestination(assertRepositoryRoot(repositoryRoot)) === undefined;
465
+ }
466
+ /** Push an already-created commit exactly; failures are publication state, not transition rejection. */
467
+ export function isGitCommitAncestor(repositoryRoot, ancestor, descendant) {
468
+ const root = assertRepositoryRoot(repositoryRoot);
469
+ assertReadableRevision(root, ancestor);
470
+ assertReadableRevision(root, descendant);
471
+ const result = git(root, ["merge-base", "--is-ancestor", ancestor, descendant], { allowFailure: true });
472
+ if (result.status === 0)
473
+ return true;
474
+ if (result.status === 1)
475
+ return false;
476
+ throw new Error(`Cannot inspect Git commit ancestry: ${result.stderr || `exit ${result.status}`}`);
477
+ }
478
+ /** Own one non-interactive exact-target push; cancellation is not confirmation of child exit. */
479
+ export function pushGitTarget(repositoryRoot, destination, commit, signal) {
480
+ if (typeof commit !== "string" || !/^[0-9a-f]{40,64}$/.test(commit))
481
+ return Promise.reject(new Error("Git push target must be an exact commit"));
482
+ if (signal?.aborted)
483
+ return Promise.reject(new Error("Git push aborted"));
484
+ return new Promise((resolve, reject) => {
485
+ const child = spawn("git", ["-C", repositoryRoot, "push", "--", destination.remote, `${commit}:${destination.ref}`], {
486
+ detached: process.platform !== "win32", // Own the POSIX group, not a detached daemon; retain the child handle.
487
+ stdio: ["ignore", "ignore", "pipe"],
488
+ windowsHide: true,
489
+ env: { ...process.env, GIT_TERMINAL_PROMPT: "0", GCM_INTERACTIVE: "never" },
490
+ });
491
+ let stderr = "";
492
+ let failure;
493
+ let settled = false;
494
+ function terminate(error) {
495
+ failure ??= error;
496
+ if (child.exitCode !== null || child.signalCode !== null) {
497
+ child.stderr?.destroy(); // Do not wait indefinitely for an outliving helper's inherited pipe.
498
+ return;
499
+ }
500
+ if (!child.pid)
501
+ return;
502
+ try {
503
+ if (process.platform === "win32")
504
+ child.kill("SIGKILL");
505
+ else
506
+ process.kill(-child.pid, "SIGKILL");
507
+ }
508
+ catch {
509
+ // No exit proof: keep the promise and caller's lease outstanding, even if signalling fails.
510
+ }
511
+ }
512
+ const abort = () => terminate(new Error("Git push aborted"));
513
+ const timeout = setTimeout(() => terminate(new Error(`Git push timed out after ${GIT_TIMEOUT_MS}ms`)), GIT_TIMEOUT_MS);
514
+ function finish(error) {
515
+ if (settled)
516
+ return;
517
+ settled = true;
518
+ clearTimeout(timeout);
519
+ signal?.removeEventListener("abort", abort);
520
+ if (error)
521
+ reject(error);
522
+ else
523
+ resolve();
524
+ }
525
+ child.stderr?.on("data", (chunk) => { stderr = (stderr + chunk.toString("utf8")).slice(-1000); });
526
+ child.on("error", (error) => {
527
+ failure ??= error;
528
+ if (!child.pid)
529
+ finish(error); // Spawn failure owns no live process; kill errors do not prove exit.
530
+ });
531
+ child.once("exit", () => { if (failure)
532
+ child.stderr?.destroy(); });
533
+ child.once("close", (code, endedBy) => finish(failure ?? (code === 0 ? undefined
534
+ : new Error(`Git push failed (${endedBy ?? code}): ${stderr.trim() || "no diagnostic output"}`))));
535
+ signal?.addEventListener("abort", abort, { once: true });
536
+ if (signal?.aborted)
537
+ abort();
538
+ });
539
+ }
540
+ export function pushGitCommit(repositoryRoot, commit) {
541
+ try {
542
+ const root = assertRepositoryRoot(repositoryRoot);
543
+ assertReadableRevision(root, commit);
544
+ const destination = pushDestination(root);
545
+ if (destination === undefined)
546
+ return { status: "local", commit };
547
+ const remote = git(root, ["ls-remote", destination.remote, destination.ref], { allowFailure: true });
548
+ const remoteHead = remote.stdout.trim().split(/\s+/)[0];
549
+ if (remote.status === 0 && remoteHead && /^[0-9a-f]{40,64}$/.test(remoteHead)
550
+ && git(root, ["merge-base", "--is-ancestor", commit, remoteHead], { allowFailure: true }).status === 0) {
551
+ return { status: "pushed", commit };
552
+ }
553
+ const result = git(root, ["push", destination.remote, `${commit}:${destination.ref}`], { allowFailure: true });
554
+ if (result.status === 0)
555
+ return { status: "pushed", commit };
556
+ return {
557
+ status: "pending",
558
+ commit,
559
+ error: (result.stderr.trim() || result.stdout.trim() || `exit status ${result.status}`),
560
+ };
561
+ }
562
+ catch (error) {
563
+ return { status: "pending", commit, error: error instanceof Error ? error.message : String(error) };
564
+ }
565
+ }
@@ -0,0 +1,22 @@
1
+ import type { ScopePatch, ScopedStates, StateScope } from "./state.ts";
2
+ export declare const RECENT_TRANSITION_LIMIT = 7;
3
+ export interface RecentScopePatch {
4
+ scope: StateScope;
5
+ patch: ScopePatch & {
6
+ response?: string;
7
+ };
8
+ }
9
+ /** Exact accepted replay cohort; temporal runtime owns its causal boundary. */
10
+ export interface AcceptedTransition {
11
+ id: string;
12
+ transitions: RecentScopePatch[];
13
+ }
14
+ /** Compact lineage projection; at is a branch-local position, not a clock. */
15
+ export interface RecentTransition extends AcceptedTransition {
16
+ at: number;
17
+ }
18
+ export type RecentTransitionWindow = RecentTransition[];
19
+ export declare function validateRecentTransition(value: unknown): asserts value is RecentTransition;
20
+ export declare function createAcceptedTransition(currentStates: ScopedStates, nextStates: ScopedStates, id?: string): AcceptedTransition | undefined;
21
+ /** Preserve the configured per-scope budget, filtering in selected-lineage order. */
22
+ export declare function projectRecentTransitionsWithLimit(limit: number, lineage: readonly RecentTransition[]): RecentTransitionWindow;