@caupulican/pi-adaptative 0.81.39 → 0.81.40

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 (667) hide show
  1. package/CHANGELOG.md +52 -0
  2. package/README.md +2 -0
  3. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts +2 -0
  4. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.d.ts.map +1 -1
  5. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js +2 -0
  6. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.js.map +1 -1
  7. package/dist/bundled-resources/extensions/tmux-agent-manager/dispatch-grant.ts +3 -0
  8. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts +9 -0
  9. package/dist/bundled-resources/extensions/tmux-agent-manager/index.d.ts.map +1 -1
  10. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js +290 -107
  11. package/dist/bundled-resources/extensions/tmux-agent-manager/index.js.map +1 -1
  12. package/dist/bundled-resources/extensions/tmux-agent-manager/index.ts +357 -122
  13. package/dist/bundled-resources/skills/tool-call-repair/references/repair-catalogue.md +2 -2
  14. package/dist/cli/args.d.ts +2 -0
  15. package/dist/cli/args.d.ts.map +1 -1
  16. package/dist/cli/args.js +9 -0
  17. package/dist/cli/args.js.map +1 -1
  18. package/dist/core/agent-directory-layout.d.ts +15 -0
  19. package/dist/core/agent-directory-layout.d.ts.map +1 -0
  20. package/dist/core/agent-directory-layout.js +72 -0
  21. package/dist/core/agent-directory-layout.js.map +1 -0
  22. package/dist/core/agent-paths.d.ts +19 -2
  23. package/dist/core/agent-paths.d.ts.map +1 -1
  24. package/dist/core/agent-paths.js +67 -4
  25. package/dist/core/agent-paths.js.map +1 -1
  26. package/dist/core/agent-session-runtime.d.ts +52 -8
  27. package/dist/core/agent-session-runtime.d.ts.map +1 -1
  28. package/dist/core/agent-session-runtime.js +397 -79
  29. package/dist/core/agent-session-runtime.js.map +1 -1
  30. package/dist/core/agent-session-services.d.ts +1 -0
  31. package/dist/core/agent-session-services.d.ts.map +1 -1
  32. package/dist/core/agent-session-services.js +1 -0
  33. package/dist/core/agent-session-services.js.map +1 -1
  34. package/dist/core/agent-session.d.ts +71 -136
  35. package/dist/core/agent-session.d.ts.map +1 -1
  36. package/dist/core/agent-session.js +477 -1318
  37. package/dist/core/agent-session.js.map +1 -1
  38. package/dist/core/autonomy/approval-gate.d.ts +3 -2
  39. package/dist/core/autonomy/approval-gate.d.ts.map +1 -1
  40. package/dist/core/autonomy/approval-gate.js +6 -28
  41. package/dist/core/autonomy/approval-gate.js.map +1 -1
  42. package/dist/core/autonomy/bounded-completion.d.ts +1 -1
  43. package/dist/core/autonomy/bounded-completion.d.ts.map +1 -1
  44. package/dist/core/autonomy/bounded-completion.js +1 -1
  45. package/dist/core/autonomy/bounded-completion.js.map +1 -1
  46. package/dist/core/autonomy/contracts.d.ts +20 -12
  47. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  48. package/dist/core/autonomy/contracts.js.map +1 -1
  49. package/dist/core/autonomy/foreground-envelope.d.ts +8 -2
  50. package/dist/core/autonomy/foreground-envelope.d.ts.map +1 -1
  51. package/dist/core/autonomy/foreground-envelope.js +8 -25
  52. package/dist/core/autonomy/foreground-envelope.js.map +1 -1
  53. package/dist/core/autonomy/gates.d.ts.map +1 -1
  54. package/dist/core/autonomy/gates.js +8 -10
  55. package/dist/core/autonomy/gates.js.map +1 -1
  56. package/dist/core/autonomy/lane-private-paths.d.ts +2 -0
  57. package/dist/core/autonomy/lane-private-paths.d.ts.map +1 -0
  58. package/dist/core/autonomy/lane-private-paths.js +16 -0
  59. package/dist/core/autonomy/lane-private-paths.js.map +1 -0
  60. package/dist/core/autonomy/lane-tool-surface.d.ts +10 -0
  61. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  62. package/dist/core/autonomy/lane-tool-surface.js +46 -8
  63. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  64. package/dist/core/autonomy/lane-tracker.d.ts +14 -0
  65. package/dist/core/autonomy/lane-tracker.d.ts.map +1 -1
  66. package/dist/core/autonomy/lane-tracker.js +38 -0
  67. package/dist/core/autonomy/lane-tracker.js.map +1 -1
  68. package/dist/core/autonomy/risk-assessment.d.ts +1 -2
  69. package/dist/core/autonomy/risk-assessment.d.ts.map +1 -1
  70. package/dist/core/autonomy/risk-assessment.js +1 -123
  71. package/dist/core/autonomy/risk-assessment.js.map +1 -1
  72. package/dist/core/autonomy/session-lane-record.d.ts +4 -4
  73. package/dist/core/autonomy/session-lane-record.d.ts.map +1 -1
  74. package/dist/core/autonomy/session-lane-record.js +16 -29
  75. package/dist/core/autonomy/session-lane-record.js.map +1 -1
  76. package/dist/core/autonomy/telemetry-events.d.ts +1 -1
  77. package/dist/core/autonomy/telemetry-events.d.ts.map +1 -1
  78. package/dist/core/autonomy/telemetry-events.js +1 -1
  79. package/dist/core/autonomy/telemetry-events.js.map +1 -1
  80. package/dist/core/autonomy-telemetry.d.ts +7 -7
  81. package/dist/core/autonomy-telemetry.d.ts.map +1 -1
  82. package/dist/core/autonomy-telemetry.js +9 -9
  83. package/dist/core/autonomy-telemetry.js.map +1 -1
  84. package/dist/core/background-lane-controller.d.ts +54 -236
  85. package/dist/core/background-lane-controller.d.ts.map +1 -1
  86. package/dist/core/background-lane-controller.js +140 -1273
  87. package/dist/core/background-lane-controller.js.map +1 -1
  88. package/dist/core/capability-contract.d.ts +4 -0
  89. package/dist/core/capability-contract.d.ts.map +1 -0
  90. package/dist/core/capability-contract.js +28 -0
  91. package/dist/core/capability-contract.js.map +1 -0
  92. package/dist/core/compaction-controller.d.ts +90 -0
  93. package/dist/core/compaction-controller.d.ts.map +1 -0
  94. package/dist/core/compaction-controller.js +452 -0
  95. package/dist/core/compaction-controller.js.map +1 -0
  96. package/dist/core/compaction-support.d.ts +12 -11
  97. package/dist/core/compaction-support.d.ts.map +1 -1
  98. package/dist/core/compaction-support.js.map +1 -1
  99. package/dist/core/context/context-artifacts.d.ts +6 -2
  100. package/dist/core/context/context-artifacts.d.ts.map +1 -1
  101. package/dist/core/context/context-artifacts.js +34 -2
  102. package/dist/core/context/context-artifacts.js.map +1 -1
  103. package/dist/core/context/context-store-retention.d.ts +8 -2
  104. package/dist/core/context/context-store-retention.d.ts.map +1 -1
  105. package/dist/core/context/context-store-retention.js +158 -35
  106. package/dist/core/context/context-store-retention.js.map +1 -1
  107. package/dist/core/context/okf-memory.d.ts.map +1 -1
  108. package/dist/core/context/okf-memory.js +9 -11
  109. package/dist/core/context/okf-memory.js.map +1 -1
  110. package/dist/core/context/sqlite-runtime-index.d.ts.map +1 -1
  111. package/dist/core/context/sqlite-runtime-index.js +6 -8
  112. package/dist/core/context/sqlite-runtime-index.js.map +1 -1
  113. package/dist/core/context-gc.d.ts +3 -0
  114. package/dist/core/context-gc.d.ts.map +1 -1
  115. package/dist/core/context-gc.js +10 -5
  116. package/dist/core/context-gc.js.map +1 -1
  117. package/dist/core/context-pipeline.d.ts.map +1 -1
  118. package/dist/core/context-pipeline.js +9 -4
  119. package/dist/core/context-pipeline.js.map +1 -1
  120. package/dist/core/default-tool-surface.d.ts.map +1 -1
  121. package/dist/core/default-tool-surface.js +1 -0
  122. package/dist/core/default-tool-surface.js.map +1 -1
  123. package/dist/core/delegation/managed-lane-controller.d.ts +34 -0
  124. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -0
  125. package/dist/core/delegation/managed-lane-controller.js +217 -0
  126. package/dist/core/delegation/managed-lane-controller.js.map +1 -0
  127. package/dist/core/delegation/session-worker-claim.d.ts +44 -0
  128. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -0
  129. package/dist/core/delegation/session-worker-claim.js +98 -0
  130. package/dist/core/delegation/session-worker-claim.js.map +1 -0
  131. package/dist/core/delegation/worker-actions.d.ts +7 -5
  132. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  133. package/dist/core/delegation/worker-actions.js +20 -4
  134. package/dist/core/delegation/worker-actions.js.map +1 -1
  135. package/dist/core/delegation/{worker-result.d.ts → worker-claim.d.ts} +13 -13
  136. package/dist/core/delegation/worker-claim.d.ts.map +1 -0
  137. package/dist/core/delegation/{worker-result.js → worker-claim.js} +61 -51
  138. package/dist/core/delegation/worker-claim.js.map +1 -0
  139. package/dist/core/delegation/worker-delegation-controller.d.ts +110 -0
  140. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -0
  141. package/dist/core/delegation/worker-delegation-controller.js +861 -0
  142. package/dist/core/delegation/worker-delegation-controller.js.map +1 -0
  143. package/dist/core/delegation/worker-delegation-request.d.ts +11 -0
  144. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -0
  145. package/dist/core/delegation/worker-delegation-request.js +2 -0
  146. package/dist/core/delegation/worker-delegation-request.js.map +1 -0
  147. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +40 -0
  148. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -0
  149. package/dist/core/delegation/worker-dispatch-scheduler.js +93 -0
  150. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -0
  151. package/dist/core/delegation/worker-execution-policy.d.ts +62 -0
  152. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -0
  153. package/dist/core/delegation/worker-execution-policy.js +160 -0
  154. package/dist/core/delegation/worker-execution-policy.js.map +1 -0
  155. package/dist/core/delegation/worker-lane-projection.d.ts +14 -0
  156. package/dist/core/delegation/worker-lane-projection.d.ts.map +1 -0
  157. package/dist/core/delegation/worker-lane-projection.js +100 -0
  158. package/dist/core/delegation/worker-lane-projection.js.map +1 -0
  159. package/dist/core/delegation/worker-lifecycle.d.ts +97 -0
  160. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -0
  161. package/dist/core/delegation/worker-lifecycle.js +339 -0
  162. package/dist/core/delegation/worker-lifecycle.js.map +1 -0
  163. package/dist/core/delegation/worker-notification-coordinator.d.ts +36 -0
  164. package/dist/core/delegation/worker-notification-coordinator.d.ts.map +1 -0
  165. package/dist/core/delegation/worker-notification-coordinator.js +90 -0
  166. package/dist/core/delegation/worker-notification-coordinator.js.map +1 -0
  167. package/dist/core/delegation/worker-profile-resolver.d.ts +55 -0
  168. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -0
  169. package/dist/core/delegation/worker-profile-resolver.js +113 -0
  170. package/dist/core/delegation/worker-profile-resolver.js.map +1 -0
  171. package/dist/core/delegation/worker-runner.d.ts +25 -14
  172. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  173. package/dist/core/delegation/worker-runner.js +122 -53
  174. package/dist/core/delegation/worker-runner.js.map +1 -1
  175. package/dist/core/delegation/worker-task-label.d.ts +3 -0
  176. package/dist/core/delegation/worker-task-label.d.ts.map +1 -0
  177. package/dist/core/delegation/worker-task-label.js +11 -0
  178. package/dist/core/delegation/worker-task-label.js.map +1 -0
  179. package/dist/core/doctor.d.ts +8 -0
  180. package/dist/core/doctor.d.ts.map +1 -1
  181. package/dist/core/doctor.js +32 -1
  182. package/dist/core/doctor.js.map +1 -1
  183. package/dist/core/extensions/index.d.ts +1 -1
  184. package/dist/core/extensions/index.d.ts.map +1 -1
  185. package/dist/core/extensions/index.js.map +1 -1
  186. package/dist/core/extensions/loader.d.ts +5 -1
  187. package/dist/core/extensions/loader.d.ts.map +1 -1
  188. package/dist/core/extensions/loader.js +50 -15
  189. package/dist/core/extensions/loader.js.map +1 -1
  190. package/dist/core/extensions/runner.d.ts.map +1 -1
  191. package/dist/core/extensions/runner.js +6 -0
  192. package/dist/core/extensions/runner.js.map +1 -1
  193. package/dist/core/extensions/storage.d.ts +8 -0
  194. package/dist/core/extensions/storage.d.ts.map +1 -0
  195. package/dist/core/extensions/storage.js +28 -0
  196. package/dist/core/extensions/storage.js.map +1 -0
  197. package/dist/core/extensions/types.d.ts +70 -21
  198. package/dist/core/extensions/types.d.ts.map +1 -1
  199. package/dist/core/extensions/types.js.map +1 -1
  200. package/dist/core/failure-corpus.d.ts +1 -15
  201. package/dist/core/failure-corpus.d.ts.map +1 -1
  202. package/dist/core/failure-corpus.js +9 -37
  203. package/dist/core/failure-corpus.js.map +1 -1
  204. package/dist/core/foreground-recovery-controller.d.ts +52 -0
  205. package/dist/core/foreground-recovery-controller.d.ts.map +1 -0
  206. package/dist/core/foreground-recovery-controller.js +111 -0
  207. package/dist/core/foreground-recovery-controller.js.map +1 -0
  208. package/dist/core/gateways/channel-provider.d.ts +3 -0
  209. package/dist/core/gateways/channel-provider.d.ts.map +1 -1
  210. package/dist/core/gateways/channel-provider.js +31 -6
  211. package/dist/core/gateways/channel-provider.js.map +1 -1
  212. package/dist/core/goals/goal-acceptance.d.ts +11 -0
  213. package/dist/core/goals/goal-acceptance.d.ts.map +1 -0
  214. package/dist/core/goals/goal-acceptance.js +25 -0
  215. package/dist/core/goals/goal-acceptance.js.map +1 -0
  216. package/dist/core/goals/goal-auto-continue-controller.d.ts +27 -0
  217. package/dist/core/goals/goal-auto-continue-controller.d.ts.map +1 -0
  218. package/dist/core/goals/goal-auto-continue-controller.js +93 -0
  219. package/dist/core/goals/goal-auto-continue-controller.js.map +1 -0
  220. package/dist/core/goals/goal-continuation-controller.d.ts +1 -1
  221. package/dist/core/goals/goal-continuation-controller.d.ts.map +1 -1
  222. package/dist/core/goals/goal-continuation-controller.js +10 -0
  223. package/dist/core/goals/goal-continuation-controller.js.map +1 -1
  224. package/dist/core/goals/goal-continuation-prompt.d.ts +1 -1
  225. package/dist/core/goals/goal-continuation-prompt.d.ts.map +1 -1
  226. package/dist/core/goals/goal-continuation-prompt.js +6 -6
  227. package/dist/core/goals/goal-continuation-prompt.js.map +1 -1
  228. package/dist/core/goals/goal-lifecycle.d.ts +20 -0
  229. package/dist/core/goals/goal-lifecycle.d.ts.map +1 -0
  230. package/dist/core/goals/goal-lifecycle.js +17 -0
  231. package/dist/core/goals/goal-lifecycle.js.map +1 -0
  232. package/dist/core/goals/goal-runtime-snapshot.d.ts +11 -9
  233. package/dist/core/goals/goal-runtime-snapshot.d.ts.map +1 -1
  234. package/dist/core/goals/goal-runtime-snapshot.js +10 -8
  235. package/dist/core/goals/goal-runtime-snapshot.js.map +1 -1
  236. package/dist/core/goals/goal-state.d.ts +1 -0
  237. package/dist/core/goals/goal-state.d.ts.map +1 -1
  238. package/dist/core/goals/goal-state.js +7 -10
  239. package/dist/core/goals/goal-state.js.map +1 -1
  240. package/dist/core/goals/goal-tool-core.d.ts +8 -6
  241. package/dist/core/goals/goal-tool-core.d.ts.map +1 -1
  242. package/dist/core/goals/goal-tool-core.js +11 -41
  243. package/dist/core/goals/goal-tool-core.js.map +1 -1
  244. package/dist/core/goals/session-goal-state.d.ts +2 -4
  245. package/dist/core/goals/session-goal-state.d.ts.map +1 -1
  246. package/dist/core/goals/session-goal-state.js +10 -33
  247. package/dist/core/goals/session-goal-state.js.map +1 -1
  248. package/dist/core/human-input.d.ts +100 -0
  249. package/dist/core/human-input.d.ts.map +1 -0
  250. package/dist/core/human-input.js +362 -0
  251. package/dist/core/human-input.js.map +1 -0
  252. package/dist/core/index.d.ts +9 -1
  253. package/dist/core/index.d.ts.map +1 -1
  254. package/dist/core/index.js +9 -1
  255. package/dist/core/index.js.map +1 -1
  256. package/dist/core/{telemetry.d.ts → install-telemetry.d.ts} +1 -1
  257. package/dist/core/install-telemetry.d.ts.map +1 -0
  258. package/dist/core/{telemetry.js → install-telemetry.js} +1 -1
  259. package/dist/core/install-telemetry.js.map +1 -0
  260. package/dist/core/keybindings.d.ts +17 -1
  261. package/dist/core/keybindings.d.ts.map +1 -1
  262. package/dist/core/keybindings.js +24 -6
  263. package/dist/core/keybindings.js.map +1 -1
  264. package/dist/core/learning/learning-audit.d.ts +2 -4
  265. package/dist/core/learning/learning-audit.d.ts.map +1 -1
  266. package/dist/core/learning/learning-audit.js +9 -29
  267. package/dist/core/learning/learning-audit.js.map +1 -1
  268. package/dist/core/learning/learning-gate.d.ts.map +1 -1
  269. package/dist/core/learning/learning-gate.js +1 -6
  270. package/dist/core/learning/learning-gate.js.map +1 -1
  271. package/dist/core/learning/session-learning-decision.d.ts +2 -4
  272. package/dist/core/learning/session-learning-decision.d.ts.map +1 -1
  273. package/dist/core/learning/session-learning-decision.js +9 -29
  274. package/dist/core/learning/session-learning-decision.js.map +1 -1
  275. package/dist/core/memory-controller.d.ts.map +1 -1
  276. package/dist/core/memory-controller.js +4 -4
  277. package/dist/core/memory-controller.js.map +1 -1
  278. package/dist/core/model-capability.d.ts.map +1 -1
  279. package/dist/core/model-capability.js +1 -0
  280. package/dist/core/model-capability.js.map +1 -1
  281. package/dist/core/model-resolver.d.ts +1 -1
  282. package/dist/core/model-resolver.d.ts.map +1 -1
  283. package/dist/core/model-resolver.js +6 -9
  284. package/dist/core/model-resolver.js.map +1 -1
  285. package/dist/core/model-router/intent-classifier.d.ts +1 -4
  286. package/dist/core/model-router/intent-classifier.d.ts.map +1 -1
  287. package/dist/core/model-router/intent-classifier.js +1 -156
  288. package/dist/core/model-router/intent-classifier.js.map +1 -1
  289. package/dist/core/model-router-controller.d.ts.map +1 -1
  290. package/dist/core/model-router-controller.js +2 -2
  291. package/dist/core/model-router-controller.js.map +1 -1
  292. package/dist/core/model-selection-controller.d.ts +4 -4
  293. package/dist/core/model-selection-controller.d.ts.map +1 -1
  294. package/dist/core/model-selection-controller.js.map +1 -1
  295. package/dist/core/model-tool-protocol.d.ts +23 -0
  296. package/dist/core/model-tool-protocol.d.ts.map +1 -0
  297. package/dist/core/model-tool-protocol.js +43 -0
  298. package/dist/core/model-tool-protocol.js.map +1 -0
  299. package/dist/core/models/adaptation-store.d.ts +4 -6
  300. package/dist/core/models/adaptation-store.d.ts.map +1 -1
  301. package/dist/core/models/adaptation-store.js +95 -83
  302. package/dist/core/models/adaptation-store.js.map +1 -1
  303. package/dist/core/models/fitness-store.d.ts +2 -12
  304. package/dist/core/models/fitness-store.d.ts.map +1 -1
  305. package/dist/core/models/fitness-store.js +84 -57
  306. package/dist/core/models/fitness-store.js.map +1 -1
  307. package/dist/core/models/host-state-store.d.ts +34 -0
  308. package/dist/core/models/host-state-store.d.ts.map +1 -0
  309. package/dist/core/models/host-state-store.js +86 -0
  310. package/dist/core/models/host-state-store.js.map +1 -0
  311. package/dist/core/orchestration/agent-resume.d.ts +24 -0
  312. package/dist/core/orchestration/agent-resume.d.ts.map +1 -0
  313. package/dist/core/orchestration/agent-resume.js +90 -0
  314. package/dist/core/orchestration/agent-resume.js.map +1 -0
  315. package/dist/core/orchestration/capability-gateway.d.ts +61 -0
  316. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -0
  317. package/dist/core/orchestration/capability-gateway.js +152 -0
  318. package/dist/core/orchestration/capability-gateway.js.map +1 -0
  319. package/dist/core/orchestration/contracts.d.ts +343 -0
  320. package/dist/core/orchestration/contracts.d.ts.map +1 -0
  321. package/dist/core/orchestration/contracts.js +135 -0
  322. package/dist/core/orchestration/contracts.js.map +1 -0
  323. package/dist/core/orchestration/delegation-ledger.d.ts +56 -0
  324. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -0
  325. package/dist/core/orchestration/delegation-ledger.js +197 -0
  326. package/dist/core/orchestration/delegation-ledger.js.map +1 -0
  327. package/dist/core/orchestration/event-store.d.ts +83 -0
  328. package/dist/core/orchestration/event-store.d.ts.map +1 -0
  329. package/dist/core/orchestration/event-store.js +560 -0
  330. package/dist/core/orchestration/event-store.js.map +1 -0
  331. package/dist/core/orchestration/lane-tool-manifests.d.ts +9 -0
  332. package/dist/core/orchestration/lane-tool-manifests.d.ts.map +1 -0
  333. package/dist/core/orchestration/lane-tool-manifests.js +37 -0
  334. package/dist/core/orchestration/lane-tool-manifests.js.map +1 -0
  335. package/dist/core/orchestration/model-binding.d.ts +15 -0
  336. package/dist/core/orchestration/model-binding.d.ts.map +1 -0
  337. package/dist/core/orchestration/model-binding.js +29 -0
  338. package/dist/core/orchestration/model-binding.js.map +1 -0
  339. package/dist/core/orchestration/policy-compiler.d.ts +49 -0
  340. package/dist/core/orchestration/policy-compiler.d.ts.map +1 -0
  341. package/dist/core/orchestration/policy-compiler.js +191 -0
  342. package/dist/core/orchestration/policy-compiler.js.map +1 -0
  343. package/dist/core/orchestration/policy-gate.d.ts +18 -0
  344. package/dist/core/orchestration/policy-gate.d.ts.map +1 -0
  345. package/dist/core/orchestration/policy-gate.js +24 -0
  346. package/dist/core/orchestration/policy-gate.js.map +1 -0
  347. package/dist/core/orchestration/profile-registry.d.ts +51 -0
  348. package/dist/core/orchestration/profile-registry.d.ts.map +1 -0
  349. package/dist/core/orchestration/profile-registry.js +393 -0
  350. package/dist/core/orchestration/profile-registry.js.map +1 -0
  351. package/dist/core/orchestration/profile-store.d.ts +31 -0
  352. package/dist/core/orchestration/profile-store.d.ts.map +1 -0
  353. package/dist/core/orchestration/profile-store.js +136 -0
  354. package/dist/core/orchestration/profile-store.js.map +1 -0
  355. package/dist/core/orchestration/risk-budget.d.ts +9 -0
  356. package/dist/core/orchestration/risk-budget.d.ts.map +1 -0
  357. package/dist/core/orchestration/risk-budget.js +48 -0
  358. package/dist/core/orchestration/risk-budget.js.map +1 -0
  359. package/dist/core/orchestration/task-runtime.d.ts +168 -0
  360. package/dist/core/orchestration/task-runtime.d.ts.map +1 -0
  361. package/dist/core/orchestration/task-runtime.js +1600 -0
  362. package/dist/core/orchestration/task-runtime.js.map +1 -0
  363. package/dist/core/orchestration/work-state-projection.d.ts +32 -0
  364. package/dist/core/orchestration/work-state-projection.d.ts.map +1 -0
  365. package/dist/core/orchestration/work-state-projection.js +116 -0
  366. package/dist/core/orchestration/work-state-projection.js.map +1 -0
  367. package/dist/core/orchestration/worker-execution-contract.d.ts +21 -0
  368. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -0
  369. package/dist/core/orchestration/worker-execution-contract.js +179 -0
  370. package/dist/core/orchestration/worker-execution-contract.js.map +1 -0
  371. package/dist/core/orchestration/worker-result-adapter.d.ts +21 -0
  372. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -0
  373. package/dist/core/orchestration/worker-result-adapter.js +109 -0
  374. package/dist/core/orchestration/worker-result-adapter.js.map +1 -0
  375. package/dist/core/process-identity.d.ts +11 -0
  376. package/dist/core/process-identity.d.ts.map +1 -0
  377. package/dist/core/process-identity.js +26 -0
  378. package/dist/core/process-identity.js.map +1 -0
  379. package/dist/core/process-matrix/codes.d.ts +14 -3
  380. package/dist/core/process-matrix/codes.d.ts.map +1 -1
  381. package/dist/core/process-matrix/codes.js.map +1 -1
  382. package/dist/core/process-matrix/resume-launcher.d.ts +26 -0
  383. package/dist/core/process-matrix/resume-launcher.d.ts.map +1 -0
  384. package/dist/core/process-matrix/resume-launcher.js +62 -0
  385. package/dist/core/process-matrix/resume-launcher.js.map +1 -0
  386. package/dist/core/process-matrix/runtime.d.ts +37 -22
  387. package/dist/core/process-matrix/runtime.d.ts.map +1 -1
  388. package/dist/core/process-matrix/runtime.js +399 -76
  389. package/dist/core/process-matrix/runtime.js.map +1 -1
  390. package/dist/core/process-matrix/store.d.ts +5 -2
  391. package/dist/core/process-matrix/store.d.ts.map +1 -1
  392. package/dist/core/process-matrix/store.js +123 -14
  393. package/dist/core/process-matrix/store.js.map +1 -1
  394. package/dist/core/process-matrix/supervisor.d.ts +10 -7
  395. package/dist/core/process-matrix/supervisor.d.ts.map +1 -1
  396. package/dist/core/process-matrix/supervisor.js +45 -14
  397. package/dist/core/process-matrix/supervisor.js.map +1 -1
  398. package/dist/core/profile-registry.d.ts.map +1 -1
  399. package/dist/core/profile-registry.js +6 -8
  400. package/dist/core/profile-registry.js.map +1 -1
  401. package/dist/core/reflection-controller.d.ts +4 -4
  402. package/dist/core/reflection-controller.d.ts.map +1 -1
  403. package/dist/core/reflection-controller.js +2 -1
  404. package/dist/core/reflection-controller.js.map +1 -1
  405. package/dist/core/reload-blockers.d.ts.map +1 -1
  406. package/dist/core/reload-blockers.js +6 -8
  407. package/dist/core/reload-blockers.js.map +1 -1
  408. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  409. package/dist/core/research/evidence-bundle.js +1 -6
  410. package/dist/core/research/evidence-bundle.js.map +1 -1
  411. package/dist/core/research/lane-model-resolver.d.ts +33 -0
  412. package/dist/core/research/lane-model-resolver.d.ts.map +1 -0
  413. package/dist/core/research/lane-model-resolver.js +65 -0
  414. package/dist/core/research/lane-model-resolver.js.map +1 -0
  415. package/dist/core/research/model-fitness-controller.d.ts +38 -0
  416. package/dist/core/research/model-fitness-controller.d.ts.map +1 -0
  417. package/dist/core/research/model-fitness-controller.js +106 -0
  418. package/dist/core/research/model-fitness-controller.js.map +1 -0
  419. package/dist/core/research/model-fitness.d.ts +1 -1
  420. package/dist/core/research/model-fitness.d.ts.map +1 -1
  421. package/dist/core/research/model-fitness.js +4 -4
  422. package/dist/core/research/model-fitness.js.map +1 -1
  423. package/dist/core/research/research-gate.d.ts.map +1 -1
  424. package/dist/core/research/research-gate.js +7 -7
  425. package/dist/core/research/research-gate.js.map +1 -1
  426. package/dist/core/research/research-lane-controller.d.ts +62 -0
  427. package/dist/core/research/research-lane-controller.d.ts.map +1 -0
  428. package/dist/core/research/research-lane-controller.js +292 -0
  429. package/dist/core/research/research-lane-controller.js.map +1 -0
  430. package/dist/core/research/session-evidence-bundle.d.ts +2 -4
  431. package/dist/core/research/session-evidence-bundle.d.ts.map +1 -1
  432. package/dist/core/research/session-evidence-bundle.js +10 -46
  433. package/dist/core/research/session-evidence-bundle.js.map +1 -1
  434. package/dist/core/resource-loader.d.ts.map +1 -1
  435. package/dist/core/resource-loader.js +7 -2
  436. package/dist/core/resource-loader.js.map +1 -1
  437. package/dist/core/risk-classifier.d.ts +6 -0
  438. package/dist/core/risk-classifier.d.ts.map +1 -0
  439. package/dist/core/risk-classifier.js +225 -0
  440. package/dist/core/risk-classifier.js.map +1 -0
  441. package/dist/core/runtime-builder.d.ts +26 -20
  442. package/dist/core/runtime-builder.d.ts.map +1 -1
  443. package/dist/core/runtime-builder.js +237 -178
  444. package/dist/core/runtime-builder.js.map +1 -1
  445. package/dist/core/sdk.d.ts +6 -3
  446. package/dist/core/sdk.d.ts.map +1 -1
  447. package/dist/core/sdk.js +61 -24
  448. package/dist/core/sdk.js.map +1 -1
  449. package/dist/core/session-analytics.d.ts.map +1 -1
  450. package/dist/core/session-analytics.js +28 -1
  451. package/dist/core/session-analytics.js.map +1 -1
  452. package/dist/core/session-image-store.d.ts +33 -0
  453. package/dist/core/session-image-store.d.ts.map +1 -0
  454. package/dist/core/session-image-store.js +283 -0
  455. package/dist/core/session-image-store.js.map +1 -0
  456. package/dist/core/session-role.d.ts +6 -4
  457. package/dist/core/session-role.d.ts.map +1 -1
  458. package/dist/core/session-role.js +10 -4
  459. package/dist/core/session-role.js.map +1 -1
  460. package/dist/core/session-snapshot.d.ts +34 -0
  461. package/dist/core/session-snapshot.d.ts.map +1 -0
  462. package/dist/core/session-snapshot.js +68 -0
  463. package/dist/core/session-snapshot.js.map +1 -0
  464. package/dist/core/session-supervision-runtime.d.ts +31 -0
  465. package/dist/core/session-supervision-runtime.d.ts.map +1 -0
  466. package/dist/core/session-supervision-runtime.js +97 -0
  467. package/dist/core/session-supervision-runtime.js.map +1 -0
  468. package/dist/core/settings-manager.d.ts +9 -4
  469. package/dist/core/settings-manager.d.ts.map +1 -1
  470. package/dist/core/settings-manager.js +80 -28
  471. package/dist/core/settings-manager.js.map +1 -1
  472. package/dist/core/tasks/session-task-state.d.ts +2 -4
  473. package/dist/core/tasks/session-task-state.d.ts.map +1 -1
  474. package/dist/core/tasks/session-task-state.js +10 -28
  475. package/dist/core/tasks/session-task-state.js.map +1 -1
  476. package/dist/core/tasks/task-projection.d.ts +20 -0
  477. package/dist/core/tasks/task-projection.d.ts.map +1 -0
  478. package/dist/core/tasks/task-projection.js +47 -0
  479. package/dist/core/tasks/task-projection.js.map +1 -0
  480. package/dist/core/tasks/task-state.d.ts +4 -0
  481. package/dist/core/tasks/task-state.d.ts.map +1 -1
  482. package/dist/core/tasks/task-state.js +28 -11
  483. package/dist/core/tasks/task-state.js.map +1 -1
  484. package/dist/core/tool-capability-policy.d.ts +13 -0
  485. package/dist/core/tool-capability-policy.d.ts.map +1 -0
  486. package/dist/core/tool-capability-policy.js +85 -0
  487. package/dist/core/tool-capability-policy.js.map +1 -0
  488. package/dist/core/tool-protocol-controller.d.ts +91 -0
  489. package/dist/core/tool-protocol-controller.d.ts.map +1 -0
  490. package/dist/core/tool-protocol-controller.js +512 -0
  491. package/dist/core/tool-protocol-controller.js.map +1 -0
  492. package/dist/core/tool-recovery-log-records.d.ts +2 -3
  493. package/dist/core/tool-recovery-log-records.d.ts.map +1 -1
  494. package/dist/core/tool-recovery-log-records.js +9 -35
  495. package/dist/core/tool-recovery-log-records.js.map +1 -1
  496. package/dist/core/tool-selection/tool-performance-store.d.ts +3 -7
  497. package/dist/core/tool-selection/tool-performance-store.d.ts.map +1 -1
  498. package/dist/core/tool-selection/tool-performance-store.js +97 -138
  499. package/dist/core/tool-selection/tool-performance-store.js.map +1 -1
  500. package/dist/core/tools/ask-question.d.ts +124 -0
  501. package/dist/core/tools/ask-question.d.ts.map +1 -0
  502. package/dist/core/tools/ask-question.js +693 -0
  503. package/dist/core/tools/ask-question.js.map +1 -0
  504. package/dist/core/tools/delegate-status.d.ts +31 -3
  505. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  506. package/dist/core/tools/delegate-status.js +149 -29
  507. package/dist/core/tools/delegate-status.js.map +1 -1
  508. package/dist/core/tools/delegate.d.ts +15 -13
  509. package/dist/core/tools/delegate.d.ts.map +1 -1
  510. package/dist/core/tools/delegate.js +108 -23
  511. package/dist/core/tools/delegate.js.map +1 -1
  512. package/dist/core/tools/extensionify.d.ts.map +1 -1
  513. package/dist/core/tools/extensionify.js +1 -0
  514. package/dist/core/tools/extensionify.js.map +1 -1
  515. package/dist/core/tools/goal.d.ts +5 -5
  516. package/dist/core/tools/goal.d.ts.map +1 -1
  517. package/dist/core/tools/goal.js +10 -10
  518. package/dist/core/tools/goal.js.map +1 -1
  519. package/dist/core/tools/model-fitness.d.ts.map +1 -1
  520. package/dist/core/tools/model-fitness.js +2 -2
  521. package/dist/core/tools/model-fitness.js.map +1 -1
  522. package/dist/core/tools/orchestration-panel.d.ts +43 -0
  523. package/dist/core/tools/orchestration-panel.d.ts.map +1 -0
  524. package/dist/core/tools/orchestration-panel.js +168 -0
  525. package/dist/core/tools/orchestration-panel.js.map +1 -0
  526. package/dist/core/tools/run-process.d.ts +26 -0
  527. package/dist/core/tools/run-process.d.ts.map +1 -0
  528. package/dist/core/tools/run-process.js +138 -0
  529. package/dist/core/tools/run-process.js.map +1 -0
  530. package/dist/core/tools/task-steps.d.ts +2 -0
  531. package/dist/core/tools/task-steps.d.ts.map +1 -1
  532. package/dist/core/tools/task-steps.js +102 -0
  533. package/dist/core/tools/task-steps.js.map +1 -1
  534. package/dist/core/tools/tmux-dispatch.d.ts +3 -5
  535. package/dist/core/tools/tmux-dispatch.d.ts.map +1 -1
  536. package/dist/core/tools/tmux-dispatch.js +4 -4
  537. package/dist/core/tools/tmux-dispatch.js.map +1 -1
  538. package/dist/core/tools/windows-shell-engine.d.ts.map +1 -1
  539. package/dist/core/tools/windows-shell-engine.js +4 -6
  540. package/dist/core/tools/windows-shell-engine.js.map +1 -1
  541. package/dist/core/util/bounded-jsonl.d.ts +10 -0
  542. package/dist/core/util/bounded-jsonl.d.ts.map +1 -0
  543. package/dist/core/util/bounded-jsonl.js +75 -0
  544. package/dist/core/util/bounded-jsonl.js.map +1 -0
  545. package/dist/core/util/value-guards.d.ts +5 -0
  546. package/dist/core/util/value-guards.d.ts.map +1 -0
  547. package/dist/core/util/value-guards.js +12 -0
  548. package/dist/core/util/value-guards.js.map +1 -0
  549. package/dist/core/worktree-sync/store.d.ts +3 -3
  550. package/dist/core/worktree-sync/store.d.ts.map +1 -1
  551. package/dist/core/worktree-sync/store.js +10 -5
  552. package/dist/core/worktree-sync/store.js.map +1 -1
  553. package/dist/index.d.ts +13 -3
  554. package/dist/index.d.ts.map +1 -1
  555. package/dist/index.js +12 -2
  556. package/dist/index.js.map +1 -1
  557. package/dist/main.d.ts.map +1 -1
  558. package/dist/main.js +128 -44
  559. package/dist/main.js.map +1 -1
  560. package/dist/migrations.d.ts +4 -6
  561. package/dist/migrations.d.ts.map +1 -1
  562. package/dist/migrations.js +186 -28
  563. package/dist/migrations.js.map +1 -1
  564. package/dist/modes/interactive/clipboard-input.d.ts +7 -1
  565. package/dist/modes/interactive/clipboard-input.d.ts.map +1 -1
  566. package/dist/modes/interactive/clipboard-input.js +44 -6
  567. package/dist/modes/interactive/clipboard-input.js.map +1 -1
  568. package/dist/modes/interactive/components/settings-selector.d.ts.map +1 -1
  569. package/dist/modes/interactive/components/settings-selector.js +2 -2
  570. package/dist/modes/interactive/components/settings-selector.js.map +1 -1
  571. package/dist/modes/interactive/config-backup.d.ts.map +1 -1
  572. package/dist/modes/interactive/config-backup.js +5 -4
  573. package/dist/modes/interactive/config-backup.js.map +1 -1
  574. package/dist/modes/interactive/extension-ui-host.d.ts +14 -0
  575. package/dist/modes/interactive/extension-ui-host.d.ts.map +1 -1
  576. package/dist/modes/interactive/extension-ui-host.js +76 -15
  577. package/dist/modes/interactive/extension-ui-host.js.map +1 -1
  578. package/dist/modes/interactive/interactive-mode.d.ts +3 -0
  579. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  580. package/dist/modes/interactive/interactive-mode.js +63 -1
  581. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  582. package/dist/modes/interactive/key-handlers.d.ts.map +1 -1
  583. package/dist/modes/interactive/key-handlers.js +1 -1
  584. package/dist/modes/interactive/key-handlers.js.map +1 -1
  585. package/dist/modes/interactive/profile-menu-controller.d.ts.map +1 -1
  586. package/dist/modes/interactive/profile-menu-controller.js +7 -7
  587. package/dist/modes/interactive/profile-menu-controller.js.map +1 -1
  588. package/dist/modes/interactive/report-commands.d.ts.map +1 -1
  589. package/dist/modes/interactive/report-commands.js +21 -0
  590. package/dist/modes/interactive/report-commands.js.map +1 -1
  591. package/dist/modes/interactive/session-flow-commands.d.ts +17 -2
  592. package/dist/modes/interactive/session-flow-commands.d.ts.map +1 -1
  593. package/dist/modes/interactive/session-flow-commands.js +50 -17
  594. package/dist/modes/interactive/session-flow-commands.js.map +1 -1
  595. package/dist/modes/interactive/session-io-commands.d.ts.map +1 -1
  596. package/dist/modes/interactive/session-io-commands.js +16 -6
  597. package/dist/modes/interactive/session-io-commands.js.map +1 -1
  598. package/dist/modes/interactive/session-replacement-errors.d.ts +7 -0
  599. package/dist/modes/interactive/session-replacement-errors.d.ts.map +1 -0
  600. package/dist/modes/interactive/session-replacement-errors.js +15 -0
  601. package/dist/modes/interactive/session-replacement-errors.js.map +1 -0
  602. package/dist/modes/interactive/startup-checks.d.ts.map +1 -1
  603. package/dist/modes/interactive/startup-checks.js +1 -1
  604. package/dist/modes/interactive/startup-checks.js.map +1 -1
  605. package/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
  606. package/dist/modes/rpc/rpc-mode.js +82 -23
  607. package/dist/modes/rpc/rpc-mode.js.map +1 -1
  608. package/dist/modes/rpc/rpc-types.d.ts +15 -0
  609. package/dist/modes/rpc/rpc-types.d.ts.map +1 -1
  610. package/dist/modes/rpc/rpc-types.js +138 -1
  611. package/dist/modes/rpc/rpc-types.js.map +1 -1
  612. package/dist/utils/clipboard-image.d.ts.map +1 -1
  613. package/dist/utils/clipboard-image.js +2 -13
  614. package/dist/utils/clipboard-image.js.map +1 -1
  615. package/dist/utils/clipboard-native.d.ts +1 -0
  616. package/dist/utils/clipboard-native.d.ts.map +1 -1
  617. package/dist/utils/clipboard-native.js.map +1 -1
  618. package/dist/utils/clipboard.d.ts +1 -0
  619. package/dist/utils/clipboard.d.ts.map +1 -1
  620. package/dist/utils/clipboard.js +52 -1
  621. package/dist/utils/clipboard.js.map +1 -1
  622. package/dist/utils/platform.d.ts +3 -0
  623. package/dist/utils/platform.d.ts.map +1 -0
  624. package/dist/utils/platform.js +8 -0
  625. package/dist/utils/platform.js.map +1 -0
  626. package/dist/utils/work-directory.d.ts +11 -0
  627. package/dist/utils/work-directory.d.ts.map +1 -1
  628. package/dist/utils/work-directory.js +30 -9
  629. package/dist/utils/work-directory.js.map +1 -1
  630. package/docs/UI_POLISH_ORCHESTRATION.md +44 -0
  631. package/docs/UI_QUALITY_ORCHESTRATION.md +30 -0
  632. package/docs/docs.json +4 -0
  633. package/docs/extensions.md +62 -2
  634. package/docs/harness-architecture.md +156 -0
  635. package/docs/keybindings.md +11 -1
  636. package/docs/process-matrix.md +59 -26
  637. package/docs/rpc.md +45 -2
  638. package/docs/sessions.md +15 -0
  639. package/docs/settings.md +125 -11
  640. package/docs/task-steps.md +8 -0
  641. package/docs/telemetry.md +19 -0
  642. package/docs/tmux-agent-manager.md +10 -3
  643. package/docs/ui-reference/README.md +9 -0
  644. package/docs/ui-reference/orchestration-after.txt +7 -0
  645. package/docs/ui-reference/orchestration-before.txt +7 -0
  646. package/docs/ui-reference/orchestration-reference.txt +6 -0
  647. package/docs/usage.md +14 -2
  648. package/docs/work-directory.md +19 -8
  649. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  650. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  651. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  652. package/examples/extensions/question.ts +34 -245
  653. package/examples/extensions/questionnaire.ts +41 -407
  654. package/examples/extensions/sandbox/package-lock.json +2 -2
  655. package/examples/extensions/sandbox/package.json +1 -1
  656. package/examples/extensions/with-deps/package-lock.json +2 -2
  657. package/examples/extensions/with-deps/package.json +1 -1
  658. package/npm-shrinkwrap.json +12 -12
  659. package/package.json +4 -4
  660. package/dist/core/delegation/session-worker-result.d.ts +0 -46
  661. package/dist/core/delegation/session-worker-result.d.ts.map +0 -1
  662. package/dist/core/delegation/session-worker-result.js +0 -113
  663. package/dist/core/delegation/session-worker-result.js.map +0 -1
  664. package/dist/core/delegation/worker-result.d.ts.map +0 -1
  665. package/dist/core/delegation/worker-result.js.map +0 -1
  666. package/dist/core/telemetry.d.ts.map +0 -1
  667. package/dist/core/telemetry.js.map +0 -1
@@ -0,0 +1,283 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync, lstatSync, mkdirSync, opendirSync, readFileSync, unlinkSync, writeFileSync } from "node:fs";
3
+ import { homedir } from "node:os";
4
+ import { isAbsolute, resolve } from "node:path";
5
+ import { attachmentsDir } from "./agent-paths.js";
6
+ const FILE_PREFIX = "pi-clip";
7
+ const MAX_SCANNED_ENTRIES = 10_000;
8
+ const MAX_STORED_FILES = 512;
9
+ const MAX_TOTAL_BYTES = 512 * 1024 * 1024;
10
+ const MAX_IMAGE_BYTES = 50 * 1024 * 1024;
11
+ const MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;
12
+ const MAX_SEQUENCE = 999_999;
13
+ const FILE_PATTERN = /^pi-clip-([0-9a-f]{16})-(\d{6})-([0-9a-f]{12})\.(png|jpg|webp|gif)$/;
14
+ function extensionForMimeType(mimeType) {
15
+ switch (mimeType.split(";", 1)[0]?.trim().toLowerCase()) {
16
+ case "image/jpeg":
17
+ return "jpg";
18
+ case "image/webp":
19
+ return "webp";
20
+ case "image/gif":
21
+ return "gif";
22
+ default:
23
+ return "png";
24
+ }
25
+ }
26
+ function mimeTypeForExtension(extension) {
27
+ switch (extension) {
28
+ case "jpg":
29
+ return "image/jpeg";
30
+ case "webp":
31
+ return "image/webp";
32
+ case "gif":
33
+ return "image/gif";
34
+ default:
35
+ return "image/png";
36
+ }
37
+ }
38
+ function resolveConfiguredDirectory(directory, cwd) {
39
+ const trimmed = directory.trim();
40
+ const expanded = trimmed === "~" ? homedir() : trimmed.replace(/^~(?=[/\\])/, homedir());
41
+ return resolve(isAbsolute(expanded) ? expanded : resolve(cwd, expanded));
42
+ }
43
+ export function resolveSessionImageDirectory(options) {
44
+ return options.directory?.trim()
45
+ ? resolveConfiguredDirectory(options.directory, options.cwd)
46
+ : attachmentsDir(options.agentDir);
47
+ }
48
+ export class SessionImageStore {
49
+ directory;
50
+ sessionKey;
51
+ now;
52
+ constructor(options) {
53
+ this.directory = resolveSessionImageDirectory(options);
54
+ this.sessionKey = createHash("sha256").update(options.sessionId).digest("hex").slice(0, 16);
55
+ this.now = options.now ?? Date.now;
56
+ }
57
+ /** Validate and durably retain provider-neutral image content, reusing its claimed sequence only
58
+ * when that sequence already contains the exact same bytes and normalized MIME type. */
59
+ retainContent(content, preferredSequence) {
60
+ const compactBase64 = content.data.trim();
61
+ if (!/^image\/(?:png|jpeg|webp|gif)(?:;|$)/iu.test(content.mimeType.trim())) {
62
+ throw new Error(`Unsupported image MIME type: ${content.mimeType}`);
63
+ }
64
+ if (!/^[A-Za-z0-9+/]*={0,2}$/.test(compactBase64) || compactBase64.length % 4 === 1) {
65
+ throw new Error("Image content is not valid base64");
66
+ }
67
+ const bytes = Buffer.from(compactBase64, "base64");
68
+ if (bytes.toString("base64").replace(/=+$/u, "") !== compactBase64.replace(/=+$/u, "")) {
69
+ throw new Error("Image content is not canonical base64");
70
+ }
71
+ const normalizedMimeType = mimeTypeForExtension(extensionForMimeType(content.mimeType));
72
+ if (preferredSequence !== undefined) {
73
+ const existing = this.read(preferredSequence);
74
+ if (existing && existing.mimeType === normalizedMimeType && Buffer.from(existing.bytes).equals(bytes)) {
75
+ return existing;
76
+ }
77
+ }
78
+ return this.write(bytes, normalizedMimeType);
79
+ }
80
+ write(bytes, mimeType) {
81
+ if (bytes.byteLength === 0 || bytes.byteLength > MAX_IMAGE_BYTES) {
82
+ throw new Error(`Clipboard image must be between 1 byte and ${MAX_IMAGE_BYTES} bytes`);
83
+ }
84
+ mkdirSync(this.directory, { recursive: true });
85
+ const directoryStats = lstatSync(this.directory);
86
+ if (!directoryStats.isDirectory()) {
87
+ throw new Error(`Attachment path is not a directory: ${this.directory}`);
88
+ }
89
+ const before = this.scan();
90
+ if (!before.complete) {
91
+ throw new Error(`Attachment directory exceeds the ${MAX_SCANNED_ENTRIES}-entry inspection bound`);
92
+ }
93
+ let sequence = Math.max(0, ...before.entries.filter((entry) => entry.sessionKey === this.sessionKey).map((entry) => entry.sequence));
94
+ const digest = createHash("sha256").update(bytes).digest("hex").slice(0, 12);
95
+ const extension = extensionForMimeType(mimeType);
96
+ let path = "";
97
+ let written = false;
98
+ while (sequence < MAX_SEQUENCE) {
99
+ sequence++;
100
+ path = resolve(this.directory, `${FILE_PREFIX}-${this.sessionKey}-${String(sequence).padStart(6, "0")}-${digest}.${extension}`);
101
+ try {
102
+ writeFileSync(path, bytes, { flag: "wx" });
103
+ written = true;
104
+ break;
105
+ }
106
+ catch (error) {
107
+ if (error.code !== "EEXIST")
108
+ throw error;
109
+ }
110
+ }
111
+ if (!written) {
112
+ throw new Error("Clipboard image sequence is exhausted");
113
+ }
114
+ try {
115
+ this.prune(path);
116
+ }
117
+ catch (error) {
118
+ try {
119
+ unlinkSync(path);
120
+ }
121
+ catch { }
122
+ throw error;
123
+ }
124
+ return { sequence, path, mimeType: mimeTypeForExtension(extension), bytes: new Uint8Array(bytes) };
125
+ }
126
+ read(sequence) {
127
+ if (!Number.isSafeInteger(sequence) || sequence < 1 || sequence > MAX_SEQUENCE)
128
+ return undefined;
129
+ const scan = this.scan();
130
+ if (!scan.complete)
131
+ return undefined;
132
+ const entry = scan.entries.find((candidate) => candidate.sessionKey === this.sessionKey && candidate.sequence === sequence);
133
+ return entry ? this.readEntry(entry) : undefined;
134
+ }
135
+ readLatest() {
136
+ const scan = this.scan();
137
+ if (!scan.complete)
138
+ return undefined;
139
+ const entries = scan.entries
140
+ .filter((entry) => entry.sessionKey === this.sessionKey)
141
+ .sort((left, right) => right.sequence - left.sequence);
142
+ for (const entry of entries) {
143
+ const image = this.readEntry(entry);
144
+ if (image)
145
+ return image;
146
+ }
147
+ return undefined;
148
+ }
149
+ resolveReferences(text) {
150
+ try {
151
+ const explicitSequences = [];
152
+ const explicitPattern = /(?:\[\s*)?(?:image|screenshot|picture|photo)\s*#?\s*(\d{1,6})(?:\s*\])?/gi;
153
+ for (const match of text.matchAll(explicitPattern)) {
154
+ const sequence = Number(match[1]);
155
+ if (!explicitSequences.includes(sequence))
156
+ explicitSequences.push(sequence);
157
+ }
158
+ const resolved = explicitSequences
159
+ .map((sequence) => this.read(sequence))
160
+ .filter((image) => image !== undefined);
161
+ if (resolved.length === 0 && this.referencesLatestImage(text)) {
162
+ const latest = this.readLatest();
163
+ if (latest)
164
+ resolved.push(latest);
165
+ }
166
+ return resolved.map((image) => ({
167
+ type: "image",
168
+ data: Buffer.from(image.bytes).toString("base64"),
169
+ mimeType: image.mimeType,
170
+ }));
171
+ }
172
+ catch {
173
+ return [];
174
+ }
175
+ }
176
+ referencesLatestImage(text) {
177
+ return (/\b(?:the|this|that|latest|last|pasted|attached|clipboard)\s+(?:image|screenshot|picture|photo)\b/i.test(text) ||
178
+ /\b(?:look at|inspect|review|describe|analy[sz]e|check)\s+(?:(?:the|this|that|latest|last|pasted|attached|clipboard)\s+)?(?:image|screenshot|picture|photo)\b/i.test(text));
179
+ }
180
+ readEntry(entry) {
181
+ try {
182
+ const stats = lstatSync(entry.path);
183
+ if (!stats.isFile() || stats.isSymbolicLink() || stats.size < 1 || stats.size > MAX_IMAGE_BYTES)
184
+ return undefined;
185
+ const bytes = readFileSync(entry.path);
186
+ const digest = createHash("sha256").update(bytes).digest("hex").slice(0, 12);
187
+ if (digest !== entry.digest)
188
+ return undefined;
189
+ return {
190
+ sequence: entry.sequence,
191
+ path: entry.path,
192
+ mimeType: entry.mimeType,
193
+ bytes: new Uint8Array(bytes),
194
+ };
195
+ }
196
+ catch {
197
+ return undefined;
198
+ }
199
+ }
200
+ scan() {
201
+ if (!existsSync(this.directory))
202
+ return { entries: [], complete: true };
203
+ const entries = [];
204
+ let scanned = 0;
205
+ let complete = true;
206
+ const handle = opendirSync(this.directory);
207
+ try {
208
+ while (true) {
209
+ const directoryEntry = handle.readSync();
210
+ if (!directoryEntry)
211
+ break;
212
+ if (scanned >= MAX_SCANNED_ENTRIES) {
213
+ complete = false;
214
+ break;
215
+ }
216
+ scanned++;
217
+ if (!directoryEntry.isFile() || directoryEntry.isSymbolicLink())
218
+ continue;
219
+ const match = FILE_PATTERN.exec(directoryEntry.name);
220
+ if (!match)
221
+ continue;
222
+ const path = resolve(this.directory, directoryEntry.name);
223
+ try {
224
+ const stats = lstatSync(path);
225
+ if (!stats.isFile() || stats.isSymbolicLink())
226
+ continue;
227
+ entries.push({
228
+ path,
229
+ sessionKey: match[1],
230
+ sequence: Number(match[2]),
231
+ digest: match[3],
232
+ mimeType: mimeTypeForExtension(match[4]),
233
+ bytes: stats.size,
234
+ mtimeMs: stats.mtimeMs,
235
+ });
236
+ }
237
+ catch { }
238
+ }
239
+ }
240
+ finally {
241
+ handle.closeSync();
242
+ }
243
+ return { entries, complete };
244
+ }
245
+ prune(protectedPath) {
246
+ const scan = this.scan();
247
+ if (!scan.complete) {
248
+ throw new Error(`Attachment directory exceeds the ${MAX_SCANNED_ENTRIES}-entry inspection bound`);
249
+ }
250
+ const now = this.now();
251
+ for (const entry of scan.entries) {
252
+ if (entry.path !== protectedPath && now - entry.mtimeMs > MAX_AGE_MS) {
253
+ try {
254
+ unlinkSync(entry.path);
255
+ }
256
+ catch { }
257
+ }
258
+ }
259
+ const retained = this.scan();
260
+ if (!retained.complete) {
261
+ throw new Error(`Attachment directory exceeds the ${MAX_SCANNED_ENTRIES}-entry inspection bound`);
262
+ }
263
+ const oldestFirst = retained.entries.sort((left, right) => left.mtimeMs - right.mtimeMs);
264
+ let totalBytes = oldestFirst.reduce((total, entry) => total + entry.bytes, 0);
265
+ let totalFiles = oldestFirst.length;
266
+ for (const entry of oldestFirst) {
267
+ if (totalFiles <= MAX_STORED_FILES && totalBytes <= MAX_TOTAL_BYTES)
268
+ break;
269
+ if (entry.path === protectedPath)
270
+ continue;
271
+ try {
272
+ unlinkSync(entry.path);
273
+ totalFiles--;
274
+ totalBytes -= entry.bytes;
275
+ }
276
+ catch { }
277
+ }
278
+ if (totalFiles > MAX_STORED_FILES || totalBytes > MAX_TOTAL_BYTES) {
279
+ throw new Error("Attachment retention bounds could not be enforced");
280
+ }
281
+ }
282
+ }
283
+ //# sourceMappingURL=session-image-store.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-image-store.js","sourceRoot":"","sources":["../../src/core/session-image-store.ts"],"names":[],"mappings":"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","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync, lstatSync, mkdirSync, opendirSync, readFileSync, unlinkSync, writeFileSync } from \"node:fs\";\nimport { homedir } from \"node:os\";\nimport { isAbsolute, resolve } from \"node:path\";\nimport type { ImageContent } from \"@caupulican/pi-ai\";\nimport { attachmentsDir } from \"./agent-paths.ts\";\n\nconst FILE_PREFIX = \"pi-clip\";\nconst MAX_SCANNED_ENTRIES = 10_000;\nconst MAX_STORED_FILES = 512;\nconst MAX_TOTAL_BYTES = 512 * 1024 * 1024;\nconst MAX_IMAGE_BYTES = 50 * 1024 * 1024;\nconst MAX_AGE_MS = 30 * 24 * 60 * 60 * 1000;\nconst MAX_SEQUENCE = 999_999;\nconst FILE_PATTERN = /^pi-clip-([0-9a-f]{16})-(\\d{6})-([0-9a-f]{12})\\.(png|jpg|webp|gif)$/;\n\nexport interface StoredSessionImage {\n\treadonly sequence: number;\n\treadonly path: string;\n\treadonly mimeType: string;\n\treadonly bytes: Uint8Array;\n}\n\nexport interface SessionImageStoreOptions {\n\tagentDir: string;\n\tcwd: string;\n\tsessionId: string;\n\tdirectory?: string;\n\tnow?: () => number;\n}\n\ninterface StoredImageEntry {\n\tpath: string;\n\tsessionKey: string;\n\tsequence: number;\n\tdigest: string;\n\tmimeType: string;\n\tbytes: number;\n\tmtimeMs: number;\n}\n\ninterface StoreScan {\n\tentries: StoredImageEntry[];\n\tcomplete: boolean;\n}\n\nfunction extensionForMimeType(mimeType: string): \"png\" | \"jpg\" | \"webp\" | \"gif\" {\n\tswitch (mimeType.split(\";\", 1)[0]?.trim().toLowerCase()) {\n\t\tcase \"image/jpeg\":\n\t\t\treturn \"jpg\";\n\t\tcase \"image/webp\":\n\t\t\treturn \"webp\";\n\t\tcase \"image/gif\":\n\t\t\treturn \"gif\";\n\t\tdefault:\n\t\t\treturn \"png\";\n\t}\n}\n\nfunction mimeTypeForExtension(extension: string): string {\n\tswitch (extension) {\n\t\tcase \"jpg\":\n\t\t\treturn \"image/jpeg\";\n\t\tcase \"webp\":\n\t\t\treturn \"image/webp\";\n\t\tcase \"gif\":\n\t\t\treturn \"image/gif\";\n\t\tdefault:\n\t\t\treturn \"image/png\";\n\t}\n}\n\nfunction resolveConfiguredDirectory(directory: string, cwd: string): string {\n\tconst trimmed = directory.trim();\n\tconst expanded = trimmed === \"~\" ? homedir() : trimmed.replace(/^~(?=[/\\\\])/, homedir());\n\treturn resolve(isAbsolute(expanded) ? expanded : resolve(cwd, expanded));\n}\n\nexport function resolveSessionImageDirectory(options: SessionImageStoreOptions): string {\n\treturn options.directory?.trim()\n\t\t? resolveConfiguredDirectory(options.directory, options.cwd)\n\t\t: attachmentsDir(options.agentDir);\n}\n\nexport class SessionImageStore {\n\treadonly directory: string;\n\tprivate readonly sessionKey: string;\n\tprivate readonly now: () => number;\n\n\tconstructor(options: SessionImageStoreOptions) {\n\t\tthis.directory = resolveSessionImageDirectory(options);\n\t\tthis.sessionKey = createHash(\"sha256\").update(options.sessionId).digest(\"hex\").slice(0, 16);\n\t\tthis.now = options.now ?? Date.now;\n\t}\n\n\t/** Validate and durably retain provider-neutral image content, reusing its claimed sequence only\n\t * when that sequence already contains the exact same bytes and normalized MIME type. */\n\tretainContent(content: ImageContent, preferredSequence?: number): StoredSessionImage {\n\t\tconst compactBase64 = content.data.trim();\n\t\tif (!/^image\\/(?:png|jpeg|webp|gif)(?:;|$)/iu.test(content.mimeType.trim())) {\n\t\t\tthrow new Error(`Unsupported image MIME type: ${content.mimeType}`);\n\t\t}\n\t\tif (!/^[A-Za-z0-9+/]*={0,2}$/.test(compactBase64) || compactBase64.length % 4 === 1) {\n\t\t\tthrow new Error(\"Image content is not valid base64\");\n\t\t}\n\t\tconst bytes = Buffer.from(compactBase64, \"base64\");\n\t\tif (bytes.toString(\"base64\").replace(/=+$/u, \"\") !== compactBase64.replace(/=+$/u, \"\")) {\n\t\t\tthrow new Error(\"Image content is not canonical base64\");\n\t\t}\n\t\tconst normalizedMimeType = mimeTypeForExtension(extensionForMimeType(content.mimeType));\n\t\tif (preferredSequence !== undefined) {\n\t\t\tconst existing = this.read(preferredSequence);\n\t\t\tif (existing && existing.mimeType === normalizedMimeType && Buffer.from(existing.bytes).equals(bytes)) {\n\t\t\t\treturn existing;\n\t\t\t}\n\t\t}\n\t\treturn this.write(bytes, normalizedMimeType);\n\t}\n\n\twrite(bytes: Uint8Array, mimeType: string): StoredSessionImage {\n\t\tif (bytes.byteLength === 0 || bytes.byteLength > MAX_IMAGE_BYTES) {\n\t\t\tthrow new Error(`Clipboard image must be between 1 byte and ${MAX_IMAGE_BYTES} bytes`);\n\t\t}\n\t\tmkdirSync(this.directory, { recursive: true });\n\t\tconst directoryStats = lstatSync(this.directory);\n\t\tif (!directoryStats.isDirectory()) {\n\t\t\tthrow new Error(`Attachment path is not a directory: ${this.directory}`);\n\t\t}\n\n\t\tconst before = this.scan();\n\t\tif (!before.complete) {\n\t\t\tthrow new Error(`Attachment directory exceeds the ${MAX_SCANNED_ENTRIES}-entry inspection bound`);\n\t\t}\n\t\tlet sequence = Math.max(\n\t\t\t0,\n\t\t\t...before.entries.filter((entry) => entry.sessionKey === this.sessionKey).map((entry) => entry.sequence),\n\t\t);\n\t\tconst digest = createHash(\"sha256\").update(bytes).digest(\"hex\").slice(0, 12);\n\t\tconst extension = extensionForMimeType(mimeType);\n\t\tlet path = \"\";\n\t\tlet written = false;\n\t\twhile (sequence < MAX_SEQUENCE) {\n\t\t\tsequence++;\n\t\t\tpath = resolve(\n\t\t\t\tthis.directory,\n\t\t\t\t`${FILE_PREFIX}-${this.sessionKey}-${String(sequence).padStart(6, \"0\")}-${digest}.${extension}`,\n\t\t\t);\n\t\t\ttry {\n\t\t\t\twriteFileSync(path, bytes, { flag: \"wx\" });\n\t\t\t\twritten = true;\n\t\t\t\tbreak;\n\t\t\t} catch (error) {\n\t\t\t\tif ((error as NodeJS.ErrnoException).code !== \"EEXIST\") throw error;\n\t\t\t}\n\t\t}\n\t\tif (!written) {\n\t\t\tthrow new Error(\"Clipboard image sequence is exhausted\");\n\t\t}\n\n\t\ttry {\n\t\t\tthis.prune(path);\n\t\t} catch (error) {\n\t\t\ttry {\n\t\t\t\tunlinkSync(path);\n\t\t\t} catch {}\n\t\t\tthrow error;\n\t\t}\n\t\treturn { sequence, path, mimeType: mimeTypeForExtension(extension), bytes: new Uint8Array(bytes) };\n\t}\n\n\tread(sequence: number): StoredSessionImage | undefined {\n\t\tif (!Number.isSafeInteger(sequence) || sequence < 1 || sequence > MAX_SEQUENCE) return undefined;\n\t\tconst scan = this.scan();\n\t\tif (!scan.complete) return undefined;\n\t\tconst entry = scan.entries.find(\n\t\t\t(candidate) => candidate.sessionKey === this.sessionKey && candidate.sequence === sequence,\n\t\t);\n\t\treturn entry ? this.readEntry(entry) : undefined;\n\t}\n\n\treadLatest(): StoredSessionImage | undefined {\n\t\tconst scan = this.scan();\n\t\tif (!scan.complete) return undefined;\n\t\tconst entries = scan.entries\n\t\t\t.filter((entry) => entry.sessionKey === this.sessionKey)\n\t\t\t.sort((left, right) => right.sequence - left.sequence);\n\t\tfor (const entry of entries) {\n\t\t\tconst image = this.readEntry(entry);\n\t\t\tif (image) return image;\n\t\t}\n\t\treturn undefined;\n\t}\n\n\tresolveReferences(text: string): ImageContent[] {\n\t\ttry {\n\t\t\tconst explicitSequences: number[] = [];\n\t\t\tconst explicitPattern = /(?:\\[\\s*)?(?:image|screenshot|picture|photo)\\s*#?\\s*(\\d{1,6})(?:\\s*\\])?/gi;\n\t\t\tfor (const match of text.matchAll(explicitPattern)) {\n\t\t\t\tconst sequence = Number(match[1]);\n\t\t\t\tif (!explicitSequences.includes(sequence)) explicitSequences.push(sequence);\n\t\t\t}\n\n\t\t\tconst resolved = explicitSequences\n\t\t\t\t.map((sequence) => this.read(sequence))\n\t\t\t\t.filter((image): image is StoredSessionImage => image !== undefined);\n\t\t\tif (resolved.length === 0 && this.referencesLatestImage(text)) {\n\t\t\t\tconst latest = this.readLatest();\n\t\t\t\tif (latest) resolved.push(latest);\n\t\t\t}\n\t\t\treturn resolved.map((image) => ({\n\t\t\t\ttype: \"image\",\n\t\t\t\tdata: Buffer.from(image.bytes).toString(\"base64\"),\n\t\t\t\tmimeType: image.mimeType,\n\t\t\t}));\n\t\t} catch {\n\t\t\treturn [];\n\t\t}\n\t}\n\n\tprivate referencesLatestImage(text: string): boolean {\n\t\treturn (\n\t\t\t/\\b(?:the|this|that|latest|last|pasted|attached|clipboard)\\s+(?:image|screenshot|picture|photo)\\b/i.test(\n\t\t\t\ttext,\n\t\t\t) ||\n\t\t\t/\\b(?:look at|inspect|review|describe|analy[sz]e|check)\\s+(?:(?:the|this|that|latest|last|pasted|attached|clipboard)\\s+)?(?:image|screenshot|picture|photo)\\b/i.test(\n\t\t\t\ttext,\n\t\t\t)\n\t\t);\n\t}\n\n\tprivate readEntry(entry: StoredImageEntry): StoredSessionImage | undefined {\n\t\ttry {\n\t\t\tconst stats = lstatSync(entry.path);\n\t\t\tif (!stats.isFile() || stats.isSymbolicLink() || stats.size < 1 || stats.size > MAX_IMAGE_BYTES)\n\t\t\t\treturn undefined;\n\t\t\tconst bytes = readFileSync(entry.path);\n\t\t\tconst digest = createHash(\"sha256\").update(bytes).digest(\"hex\").slice(0, 12);\n\t\t\tif (digest !== entry.digest) return undefined;\n\t\t\treturn {\n\t\t\t\tsequence: entry.sequence,\n\t\t\t\tpath: entry.path,\n\t\t\t\tmimeType: entry.mimeType,\n\t\t\t\tbytes: new Uint8Array(bytes),\n\t\t\t};\n\t\t} catch {\n\t\t\treturn undefined;\n\t\t}\n\t}\n\n\tprivate scan(): StoreScan {\n\t\tif (!existsSync(this.directory)) return { entries: [], complete: true };\n\t\tconst entries: StoredImageEntry[] = [];\n\t\tlet scanned = 0;\n\t\tlet complete = true;\n\t\tconst handle = opendirSync(this.directory);\n\t\ttry {\n\t\t\twhile (true) {\n\t\t\t\tconst directoryEntry = handle.readSync();\n\t\t\t\tif (!directoryEntry) break;\n\t\t\t\tif (scanned >= MAX_SCANNED_ENTRIES) {\n\t\t\t\t\tcomplete = false;\n\t\t\t\t\tbreak;\n\t\t\t\t}\n\t\t\t\tscanned++;\n\t\t\t\tif (!directoryEntry.isFile() || directoryEntry.isSymbolicLink()) continue;\n\t\t\t\tconst match = FILE_PATTERN.exec(directoryEntry.name);\n\t\t\t\tif (!match) continue;\n\t\t\t\tconst path = resolve(this.directory, directoryEntry.name);\n\t\t\t\ttry {\n\t\t\t\t\tconst stats = lstatSync(path);\n\t\t\t\t\tif (!stats.isFile() || stats.isSymbolicLink()) continue;\n\t\t\t\t\tentries.push({\n\t\t\t\t\t\tpath,\n\t\t\t\t\t\tsessionKey: match[1]!,\n\t\t\t\t\t\tsequence: Number(match[2]),\n\t\t\t\t\t\tdigest: match[3]!,\n\t\t\t\t\t\tmimeType: mimeTypeForExtension(match[4]!),\n\t\t\t\t\t\tbytes: stats.size,\n\t\t\t\t\t\tmtimeMs: stats.mtimeMs,\n\t\t\t\t\t});\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t} finally {\n\t\t\thandle.closeSync();\n\t\t}\n\t\treturn { entries, complete };\n\t}\n\n\tprivate prune(protectedPath: string): void {\n\t\tconst scan = this.scan();\n\t\tif (!scan.complete) {\n\t\t\tthrow new Error(`Attachment directory exceeds the ${MAX_SCANNED_ENTRIES}-entry inspection bound`);\n\t\t}\n\t\tconst now = this.now();\n\t\tfor (const entry of scan.entries) {\n\t\t\tif (entry.path !== protectedPath && now - entry.mtimeMs > MAX_AGE_MS) {\n\t\t\t\ttry {\n\t\t\t\t\tunlinkSync(entry.path);\n\t\t\t\t} catch {}\n\t\t\t}\n\t\t}\n\n\t\tconst retained = this.scan();\n\t\tif (!retained.complete) {\n\t\t\tthrow new Error(`Attachment directory exceeds the ${MAX_SCANNED_ENTRIES}-entry inspection bound`);\n\t\t}\n\t\tconst oldestFirst = retained.entries.sort((left, right) => left.mtimeMs - right.mtimeMs);\n\t\tlet totalBytes = oldestFirst.reduce((total, entry) => total + entry.bytes, 0);\n\t\tlet totalFiles = oldestFirst.length;\n\t\tfor (const entry of oldestFirst) {\n\t\t\tif (totalFiles <= MAX_STORED_FILES && totalBytes <= MAX_TOTAL_BYTES) break;\n\t\t\tif (entry.path === protectedPath) continue;\n\t\t\ttry {\n\t\t\t\tunlinkSync(entry.path);\n\t\t\t\ttotalFiles--;\n\t\t\t\ttotalBytes -= entry.bytes;\n\t\t\t} catch {}\n\t\t}\n\t\tif (totalFiles > MAX_STORED_FILES || totalBytes > MAX_TOTAL_BYTES) {\n\t\t\tthrow new Error(\"Attachment retention bounds could not be enforced\");\n\t\t}\n\t}\n}\n"]}
@@ -5,7 +5,8 @@
5
5
  * tool's worker scoping, and the read-only store options threaded through the persistence layer).
6
6
  *
7
7
  * A session is a worker iff EITHER:
8
- * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration), or
8
+ * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration),
9
+ * - a valid `PI_PARENT_PID` declares this process as a managed child, or
9
10
  * - it is bound to a worktree-sync lane (`PI_WORKTREE_LANE`; see worktree-sync/runtime.ts) — a
10
11
  * lane-bound session is a worker by construction, regardless of how it was launched.
11
12
  *
@@ -20,9 +21,10 @@ export declare function getSessionRole(env?: NodeJS.ProcessEnv): SessionRole;
20
21
  export declare function isWorkerSession(env?: NodeJS.ProcessEnv): boolean;
21
22
  /**
22
23
  * Tools a worker session may never activate: the orchestration/self-adaptation surface that would
23
- * let a worker spawn its own sub-orchestration, mutate settings-driven learning/model state, or
24
- * shell out to the unbounded `python` execution contract. `python` is load-bearing for the
25
- * zero-footprint guarantee (it can write anywhere the interpreter can reach); `context_scout` is
24
+ * let a worker spawn its own sub-orchestration, bypass its parent to request owner input, mutate
25
+ * settings-driven learning/model state, or shell out to the unbounded `python` execution contract.
26
+ * `python` is load-bearing for the zero-footprint guarantee (it can write anywhere the interpreter
27
+ * can reach); `context_scout` is
26
28
  * sub-orchestration (spawns its own isolated agent loop). `bash` is deliberately NOT included: it
27
29
  * stays available as the documented cooperative boundary (see docs/worktree-sync.md) — the same
28
30
  * trust model the lane gate already applies to foreign CLIs it cannot structurally contain.
@@ -1 +1 @@
1
- {"version":3,"file":"session-role.d.ts","sourceRoot":"","sources":["../../src/core/session-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAIH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAI5C,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CAIhF;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE7E;AAED;;;;;;;;GAQG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAYrD,CAAC","sourcesContent":["/**\n * Session-role identity: distinguishes a MAIN session (an interactive/direct `pi` session) from a\n * WORKER session (lane-bound or explicitly dispatched) — the seam every worker-scoped UAC ceiling\n * and zero-footprint store gates on (see runtime-builder.ts's `isAllowedTool`, the worktree_sync\n * tool's worker scoping, and the read-only store options threaded through the persistence layer).\n *\n * A session is a worker iff EITHER:\n * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration), or\n * - it is bound to a worktree-sync lane (`PI_WORKTREE_LANE`; see worktree-sync/runtime.ts) — a\n * lane-bound session is a worker by construction, regardless of how it was launched.\n *\n * `PI_SESSION_ROLE=main` is deliberately NOT an escalation: it can never override a bound lane.\n * There is no environment value a lane-bound process can set to shed the worker ceiling — the env\n * var is additive evidence for \"worker\", never a downgrade signal.\n */\n\nimport { getBoundWorktreeLaneKey } from \"./worktree-sync/runtime.ts\";\n\nexport type SessionRole = \"main\" | \"worker\";\n\nconst PI_SESSION_ROLE_ENV = \"PI_SESSION_ROLE\";\n\n/** Derive this process's session role from the environment (env-injectable for tests). */\nexport function getSessionRole(env: NodeJS.ProcessEnv = process.env): SessionRole {\n\tif (env[PI_SESSION_ROLE_ENV] === \"worker\") return \"worker\";\n\tif (getBoundWorktreeLaneKey(env) !== undefined) return \"worker\";\n\treturn \"main\";\n}\n\n/** True iff this process is a worker session (lane-bound or explicitly declared). */\nexport function isWorkerSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn getSessionRole(env) === \"worker\";\n}\n\n/**\n * Tools a worker session may never activate: the orchestration/self-adaptation surface that would\n * let a worker spawn its own sub-orchestration, mutate settings-driven learning/model state, or\n * shell out to the unbounded `python` execution contract. `python` is load-bearing for the\n * zero-footprint guarantee (it can write anywhere the interpreter can reach); `context_scout` is\n * sub-orchestration (spawns its own isolated agent loop). `bash` is deliberately NOT included: it\n * stays available as the documented cooperative boundary (see docs/worktree-sync.md) — the same\n * trust model the lane gate already applies to foreign CLIs it cannot structurally contain.\n */\nexport const WORKER_FORBIDDEN_TOOLS: ReadonlySet<string> = new Set([\n\t\"goal\",\n\t\"delegate\",\n\t\"delegate_status\",\n\t\"improvement_loop\",\n\t\"extensionify\",\n\t\"skillify\",\n\t\"run_toolkit_script\",\n\t\"model_fitness\",\n\t\"tmux_agent_manager\",\n\t\"context_scout\",\n\t\"python\",\n]);\n"]}
1
+ {"version":3,"file":"session-role.d.ts","sourceRoot":"","sources":["../../src/core/session-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAKH,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,QAAQ,CAAC;AAI5C,0FAA0F;AAC1F,wBAAgB,cAAc,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,WAAW,CAKhF;AAED,qFAAqF;AACrF,wBAAgB,eAAe,CAAC,GAAG,GAAE,MAAM,CAAC,UAAwB,GAAG,OAAO,CAE7E;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,sBAAsB,EAAE,WAAW,CAAC,MAAM,CAarD,CAAC","sourcesContent":["/**\n * Session-role identity: distinguishes a MAIN session (an interactive/direct `pi` session) from a\n * WORKER session (lane-bound or explicitly dispatched) — the seam every worker-scoped UAC ceiling\n * and zero-footprint store gates on (see runtime-builder.ts's `isAllowedTool`, the worktree_sync\n * tool's worker scoping, and the read-only store options threaded through the persistence layer).\n *\n * A session is a worker iff EITHER:\n * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration),\n * - a valid `PI_PARENT_PID` declares this process as a managed child, or\n * - it is bound to a worktree-sync lane (`PI_WORKTREE_LANE`; see worktree-sync/runtime.ts) — a\n * lane-bound session is a worker by construction, regardless of how it was launched.\n *\n * `PI_SESSION_ROLE=main` is deliberately NOT an escalation: it can never override a bound lane.\n * There is no environment value a lane-bound process can set to shed the worker ceiling — the env\n * var is additive evidence for \"worker\", never a downgrade signal.\n */\n\nimport { getParentPid } from \"./process-identity.ts\";\nimport { getBoundWorktreeLaneKey } from \"./worktree-sync/runtime.ts\";\n\nexport type SessionRole = \"main\" | \"worker\";\n\nconst PI_SESSION_ROLE_ENV = \"PI_SESSION_ROLE\";\n\n/** Derive this process's session role from the environment (env-injectable for tests). */\nexport function getSessionRole(env: NodeJS.ProcessEnv = process.env): SessionRole {\n\tif (env[PI_SESSION_ROLE_ENV] === \"worker\") return \"worker\";\n\tif (getParentPid(env) !== undefined) return \"worker\";\n\tif (getBoundWorktreeLaneKey(env) !== undefined) return \"worker\";\n\treturn \"main\";\n}\n\n/** True iff this process is a worker session (lane-bound or explicitly declared). */\nexport function isWorkerSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn getSessionRole(env) === \"worker\";\n}\n\n/**\n * Tools a worker session may never activate: the orchestration/self-adaptation surface that would\n * let a worker spawn its own sub-orchestration, bypass its parent to request owner input, mutate\n * settings-driven learning/model state, or shell out to the unbounded `python` execution contract.\n * `python` is load-bearing for the zero-footprint guarantee (it can write anywhere the interpreter\n * can reach); `context_scout` is\n * sub-orchestration (spawns its own isolated agent loop). `bash` is deliberately NOT included: it\n * stays available as the documented cooperative boundary (see docs/worktree-sync.md) — the same\n * trust model the lane gate already applies to foreign CLIs it cannot structurally contain.\n */\nexport const WORKER_FORBIDDEN_TOOLS: ReadonlySet<string> = new Set([\n\t\"goal\",\n\t\"ask_question\",\n\t\"delegate\",\n\t\"delegate_status\",\n\t\"improvement_loop\",\n\t\"extensionify\",\n\t\"skillify\",\n\t\"run_toolkit_script\",\n\t\"model_fitness\",\n\t\"tmux_agent_manager\",\n\t\"context_scout\",\n\t\"python\",\n]);\n"]}
@@ -5,7 +5,8 @@
5
5
  * tool's worker scoping, and the read-only store options threaded through the persistence layer).
6
6
  *
7
7
  * A session is a worker iff EITHER:
8
- * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration), or
8
+ * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration),
9
+ * - a valid `PI_PARENT_PID` declares this process as a managed child, or
9
10
  * - it is bound to a worktree-sync lane (`PI_WORKTREE_LANE`; see worktree-sync/runtime.ts) — a
10
11
  * lane-bound session is a worker by construction, regardless of how it was launched.
11
12
  *
@@ -13,12 +14,15 @@
13
14
  * There is no environment value a lane-bound process can set to shed the worker ceiling — the env
14
15
  * var is additive evidence for "worker", never a downgrade signal.
15
16
  */
17
+ import { getParentPid } from "./process-identity.js";
16
18
  import { getBoundWorktreeLaneKey } from "./worktree-sync/runtime.js";
17
19
  const PI_SESSION_ROLE_ENV = "PI_SESSION_ROLE";
18
20
  /** Derive this process's session role from the environment (env-injectable for tests). */
19
21
  export function getSessionRole(env = process.env) {
20
22
  if (env[PI_SESSION_ROLE_ENV] === "worker")
21
23
  return "worker";
24
+ if (getParentPid(env) !== undefined)
25
+ return "worker";
22
26
  if (getBoundWorktreeLaneKey(env) !== undefined)
23
27
  return "worker";
24
28
  return "main";
@@ -29,15 +33,17 @@ export function isWorkerSession(env = process.env) {
29
33
  }
30
34
  /**
31
35
  * Tools a worker session may never activate: the orchestration/self-adaptation surface that would
32
- * let a worker spawn its own sub-orchestration, mutate settings-driven learning/model state, or
33
- * shell out to the unbounded `python` execution contract. `python` is load-bearing for the
34
- * zero-footprint guarantee (it can write anywhere the interpreter can reach); `context_scout` is
36
+ * let a worker spawn its own sub-orchestration, bypass its parent to request owner input, mutate
37
+ * settings-driven learning/model state, or shell out to the unbounded `python` execution contract.
38
+ * `python` is load-bearing for the zero-footprint guarantee (it can write anywhere the interpreter
39
+ * can reach); `context_scout` is
35
40
  * sub-orchestration (spawns its own isolated agent loop). `bash` is deliberately NOT included: it
36
41
  * stays available as the documented cooperative boundary (see docs/worktree-sync.md) — the same
37
42
  * trust model the lane gate already applies to foreign CLIs it cannot structurally contain.
38
43
  */
39
44
  export const WORKER_FORBIDDEN_TOOLS = new Set([
40
45
  "goal",
46
+ "ask_question",
41
47
  "delegate",
42
48
  "delegate_status",
43
49
  "improvement_loop",
@@ -1 +1 @@
1
- {"version":3,"file":"session-role.js","sourceRoot":"","sources":["../../src/core/session-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAE9C,0FAA0F;AAC1F,MAAM,UAAU,cAAc,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAe;IACjF,IAAI,GAAG,CAAC,mBAAmB,CAAC,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC3D,IAAI,uBAAuB,CAAC,GAAG,CAAC,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAChE,OAAO,MAAM,CAAC;AAAA,CACd;AAED,qFAAqF;AACrF,MAAM,UAAU,eAAe,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAW;IAC9E,OAAO,cAAc,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AAAA,CACxC;AAED;;;;;;;;GAQG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC;IAClE,MAAM;IACN,UAAU;IACV,iBAAiB;IACjB,kBAAkB;IAClB,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,eAAe;IACf,oBAAoB;IACpB,eAAe;IACf,QAAQ;CACR,CAAC,CAAC","sourcesContent":["/**\n * Session-role identity: distinguishes a MAIN session (an interactive/direct `pi` session) from a\n * WORKER session (lane-bound or explicitly dispatched) — the seam every worker-scoped UAC ceiling\n * and zero-footprint store gates on (see runtime-builder.ts's `isAllowedTool`, the worktree_sync\n * tool's worker scoping, and the read-only store options threaded through the persistence layer).\n *\n * A session is a worker iff EITHER:\n * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration), or\n * - it is bound to a worktree-sync lane (`PI_WORKTREE_LANE`; see worktree-sync/runtime.ts) — a\n * lane-bound session is a worker by construction, regardless of how it was launched.\n *\n * `PI_SESSION_ROLE=main` is deliberately NOT an escalation: it can never override a bound lane.\n * There is no environment value a lane-bound process can set to shed the worker ceiling — the env\n * var is additive evidence for \"worker\", never a downgrade signal.\n */\n\nimport { getBoundWorktreeLaneKey } from \"./worktree-sync/runtime.ts\";\n\nexport type SessionRole = \"main\" | \"worker\";\n\nconst PI_SESSION_ROLE_ENV = \"PI_SESSION_ROLE\";\n\n/** Derive this process's session role from the environment (env-injectable for tests). */\nexport function getSessionRole(env: NodeJS.ProcessEnv = process.env): SessionRole {\n\tif (env[PI_SESSION_ROLE_ENV] === \"worker\") return \"worker\";\n\tif (getBoundWorktreeLaneKey(env) !== undefined) return \"worker\";\n\treturn \"main\";\n}\n\n/** True iff this process is a worker session (lane-bound or explicitly declared). */\nexport function isWorkerSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn getSessionRole(env) === \"worker\";\n}\n\n/**\n * Tools a worker session may never activate: the orchestration/self-adaptation surface that would\n * let a worker spawn its own sub-orchestration, mutate settings-driven learning/model state, or\n * shell out to the unbounded `python` execution contract. `python` is load-bearing for the\n * zero-footprint guarantee (it can write anywhere the interpreter can reach); `context_scout` is\n * sub-orchestration (spawns its own isolated agent loop). `bash` is deliberately NOT included: it\n * stays available as the documented cooperative boundary (see docs/worktree-sync.md) — the same\n * trust model the lane gate already applies to foreign CLIs it cannot structurally contain.\n */\nexport const WORKER_FORBIDDEN_TOOLS: ReadonlySet<string> = new Set([\n\t\"goal\",\n\t\"delegate\",\n\t\"delegate_status\",\n\t\"improvement_loop\",\n\t\"extensionify\",\n\t\"skillify\",\n\t\"run_toolkit_script\",\n\t\"model_fitness\",\n\t\"tmux_agent_manager\",\n\t\"context_scout\",\n\t\"python\",\n]);\n"]}
1
+ {"version":3,"file":"session-role.js","sourceRoot":"","sources":["../../src/core/session-role.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,uBAAuB,CAAC;AACrD,OAAO,EAAE,uBAAuB,EAAE,MAAM,4BAA4B,CAAC;AAIrE,MAAM,mBAAmB,GAAG,iBAAiB,CAAC;AAE9C,0FAA0F;AAC1F,MAAM,UAAU,cAAc,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAe;IACjF,IAAI,GAAG,CAAC,mBAAmB,CAAC,KAAK,QAAQ;QAAE,OAAO,QAAQ,CAAC;IAC3D,IAAI,YAAY,CAAC,GAAG,CAAC,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IACrD,IAAI,uBAAuB,CAAC,GAAG,CAAC,KAAK,SAAS;QAAE,OAAO,QAAQ,CAAC;IAChE,OAAO,MAAM,CAAC;AAAA,CACd;AAED,qFAAqF;AACrF,MAAM,UAAU,eAAe,CAAC,GAAG,GAAsB,OAAO,CAAC,GAAG,EAAW;IAC9E,OAAO,cAAc,CAAC,GAAG,CAAC,KAAK,QAAQ,CAAC;AAAA,CACxC;AAED;;;;;;;;;GASG;AACH,MAAM,CAAC,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC;IAClE,MAAM;IACN,cAAc;IACd,UAAU;IACV,iBAAiB;IACjB,kBAAkB;IAClB,cAAc;IACd,UAAU;IACV,oBAAoB;IACpB,eAAe;IACf,oBAAoB;IACpB,eAAe;IACf,QAAQ;CACR,CAAC,CAAC","sourcesContent":["/**\n * Session-role identity: distinguishes a MAIN session (an interactive/direct `pi` session) from a\n * WORKER session (lane-bound or explicitly dispatched) — the seam every worker-scoped UAC ceiling\n * and zero-footprint store gates on (see runtime-builder.ts's `isAllowedTool`, the worktree_sync\n * tool's worker scoping, and the read-only store options threaded through the persistence layer).\n *\n * A session is a worker iff EITHER:\n * - `PI_SESSION_ROLE=worker` is set (an explicit launcher declaration),\n * - a valid `PI_PARENT_PID` declares this process as a managed child, or\n * - it is bound to a worktree-sync lane (`PI_WORKTREE_LANE`; see worktree-sync/runtime.ts) — a\n * lane-bound session is a worker by construction, regardless of how it was launched.\n *\n * `PI_SESSION_ROLE=main` is deliberately NOT an escalation: it can never override a bound lane.\n * There is no environment value a lane-bound process can set to shed the worker ceiling — the env\n * var is additive evidence for \"worker\", never a downgrade signal.\n */\n\nimport { getParentPid } from \"./process-identity.ts\";\nimport { getBoundWorktreeLaneKey } from \"./worktree-sync/runtime.ts\";\n\nexport type SessionRole = \"main\" | \"worker\";\n\nconst PI_SESSION_ROLE_ENV = \"PI_SESSION_ROLE\";\n\n/** Derive this process's session role from the environment (env-injectable for tests). */\nexport function getSessionRole(env: NodeJS.ProcessEnv = process.env): SessionRole {\n\tif (env[PI_SESSION_ROLE_ENV] === \"worker\") return \"worker\";\n\tif (getParentPid(env) !== undefined) return \"worker\";\n\tif (getBoundWorktreeLaneKey(env) !== undefined) return \"worker\";\n\treturn \"main\";\n}\n\n/** True iff this process is a worker session (lane-bound or explicitly declared). */\nexport function isWorkerSession(env: NodeJS.ProcessEnv = process.env): boolean {\n\treturn getSessionRole(env) === \"worker\";\n}\n\n/**\n * Tools a worker session may never activate: the orchestration/self-adaptation surface that would\n * let a worker spawn its own sub-orchestration, bypass its parent to request owner input, mutate\n * settings-driven learning/model state, or shell out to the unbounded `python` execution contract.\n * `python` is load-bearing for the zero-footprint guarantee (it can write anywhere the interpreter\n * can reach); `context_scout` is\n * sub-orchestration (spawns its own isolated agent loop). `bash` is deliberately NOT included: it\n * stays available as the documented cooperative boundary (see docs/worktree-sync.md) — the same\n * trust model the lane gate already applies to foreign CLIs it cannot structurally contain.\n */\nexport const WORKER_FORBIDDEN_TOOLS: ReadonlySet<string> = new Set([\n\t\"goal\",\n\t\"ask_question\",\n\t\"delegate\",\n\t\"delegate_status\",\n\t\"improvement_loop\",\n\t\"extensionify\",\n\t\"skillify\",\n\t\"run_toolkit_script\",\n\t\"model_fitness\",\n\t\"tmux_agent_manager\",\n\t\"context_scout\",\n\t\"python\",\n]);\n"]}
@@ -0,0 +1,34 @@
1
+ import type { SessionEntry, SessionManager } from "@caupulican/pi-agent-core/node";
2
+ export type SessionSnapshotPayload<ValueKey extends string, Value extends object> = {
3
+ version: 1;
4
+ } & {
5
+ [Key in ValueKey]: Value;
6
+ };
7
+ export interface SessionSnapshotCodec<Value extends object, ValueKey extends string> {
8
+ customType: string;
9
+ valueKey: ValueKey;
10
+ isValue(value: unknown): value is Value;
11
+ clone(value: Value): Value;
12
+ }
13
+ export interface SessionBranchEntrySource {
14
+ getBranch?: () => readonly SessionEntry[];
15
+ getEntries?: () => readonly SessionEntry[];
16
+ }
17
+ type VersionOneSnapshotPayload = Record<string, unknown> & {
18
+ version: 1;
19
+ };
20
+ /** Active branch when available; linear entry history only for narrow stores that expose no branch API. */
21
+ export declare function getActiveSessionBranchEntries(source: SessionBranchEntrySource): readonly SessionEntry[];
22
+ export declare function isVersionOneSessionSnapshotPayload(data: unknown): data is VersionOneSnapshotPayload;
23
+ export declare function createSessionSnapshotPayload<Value extends object, ValueKey extends string>(codec: SessionSnapshotCodec<Value, ValueKey>, value: Value): SessionSnapshotPayload<ValueKey, Value>;
24
+ export declare function appendSessionSnapshot<Value extends object, ValueKey extends string>(sessionManager: Pick<SessionManager, "appendCustomEntry">, codec: SessionSnapshotCodec<Value, ValueKey>, value: Value): string;
25
+ export declare function decodeSessionSnapshotPayload<Value extends object, ValueKey extends string>(data: unknown, codec: SessionSnapshotCodec<Value, ValueKey>): Value | undefined;
26
+ export declare function getSessionSnapshots<Value extends object, ValueKey extends string>(entries: readonly SessionEntry[], codec: SessionSnapshotCodec<Value, ValueKey>): Value[];
27
+ export declare function getLatestSessionSnapshot<Value extends object, ValueKey extends string>(entries: readonly SessionEntry[], codec: SessionSnapshotCodec<Value, ValueKey>): Value | undefined;
28
+ /**
29
+ * Resolves the newest valid snapshot on the active branch. Malformed entries are skipped while
30
+ * walking leaf to root so they cannot hide an older valid checkpoint.
31
+ */
32
+ export declare function getLatestSessionSnapshotOnBranch<Value extends object, ValueKey extends string>(sessionManager: Pick<SessionManager, "getLatestCustomEntryOnBranch">, codec: SessionSnapshotCodec<Value, ValueKey>): Value | undefined;
33
+ export {};
34
+ //# sourceMappingURL=session-snapshot.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-snapshot.d.ts","sourceRoot":"","sources":["../../src/core/session-snapshot.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AAGnF,MAAM,MAAM,sBAAsB,CAAC,QAAQ,SAAS,MAAM,EAAE,KAAK,SAAS,MAAM,IAAI;IACnF,OAAO,EAAE,CAAC,CAAC;CACX,GAAG;KACF,GAAG,IAAI,QAAQ,GAAG,KAAK;CACxB,CAAC;AAEF,MAAM,WAAW,oBAAoB,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM;IAClF,UAAU,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,QAAQ,CAAC;IACnB,OAAO,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,KAAK,CAAC;IACxC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,KAAK,CAAC;CAC3B;AAED,MAAM,WAAW,wBAAwB;IACxC,SAAS,CAAC,EAAE,MAAM,SAAS,YAAY,EAAE,CAAC;IAC1C,UAAU,CAAC,EAAE,MAAM,SAAS,YAAY,EAAE,CAAC;CAC3C;AAED,KAAK,yBAAyB,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;IAAE,OAAO,EAAE,CAAC,CAAA;CAAE,CAAC;AAE1E,2GAA2G;AAC3G,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,wBAAwB,GAAG,SAAS,YAAY,EAAE,CAIvG;AAED,wBAAgB,kCAAkC,CAAC,IAAI,EAAE,OAAO,GAAG,IAAI,IAAI,yBAAyB,CAEnG;AAED,wBAAgB,4BAA4B,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,EACzF,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,EAC5C,KAAK,EAAE,KAAK,GACV,sBAAsB,CAAC,QAAQ,EAAE,KAAK,CAAC,CAKzC;AAED,wBAAgB,qBAAqB,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,EAClF,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,EACzD,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,EAC5C,KAAK,EAAE,KAAK,GACV,MAAM,CAER;AAED,wBAAgB,4BAA4B,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,EACzF,IAAI,EAAE,OAAO,EACb,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAC1C,KAAK,GAAG,SAAS,CAInB;AAED,wBAAgB,mBAAmB,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,EAChF,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAC1C,KAAK,EAAE,CAQT;AAED,wBAAgB,wBAAwB,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,EACrF,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAC1C,KAAK,GAAG,SAAS,CAQnB;AAED;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,KAAK,SAAS,MAAM,EAAE,QAAQ,SAAS,MAAM,EAC7F,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,8BAA8B,CAAC,EACpE,KAAK,EAAE,oBAAoB,CAAC,KAAK,EAAE,QAAQ,CAAC,GAC1C,KAAK,GAAG,SAAS,CAUnB","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport { isPlainRecord } from \"./util/value-guards.ts\";\n\nexport type SessionSnapshotPayload<ValueKey extends string, Value extends object> = {\n\tversion: 1;\n} & {\n\t[Key in ValueKey]: Value;\n};\n\nexport interface SessionSnapshotCodec<Value extends object, ValueKey extends string> {\n\tcustomType: string;\n\tvalueKey: ValueKey;\n\tisValue(value: unknown): value is Value;\n\tclone(value: Value): Value;\n}\n\nexport interface SessionBranchEntrySource {\n\tgetBranch?: () => readonly SessionEntry[];\n\tgetEntries?: () => readonly SessionEntry[];\n}\n\ntype VersionOneSnapshotPayload = Record<string, unknown> & { version: 1 };\n\n/** Active branch when available; linear entry history only for narrow stores that expose no branch API. */\nexport function getActiveSessionBranchEntries(source: SessionBranchEntrySource): readonly SessionEntry[] {\n\tif (typeof source.getBranch === \"function\") return source.getBranch();\n\tif (typeof source.getEntries === \"function\") return source.getEntries();\n\tthrow new TypeError(\"Session branch entry source exposes neither getBranch nor getEntries\");\n}\n\nexport function isVersionOneSessionSnapshotPayload(data: unknown): data is VersionOneSnapshotPayload {\n\treturn isPlainRecord(data) && data.version === 1;\n}\n\nexport function createSessionSnapshotPayload<Value extends object, ValueKey extends string>(\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n\tvalue: Value,\n): SessionSnapshotPayload<ValueKey, Value> {\n\treturn {\n\t\tversion: 1,\n\t\t[codec.valueKey]: codec.clone(value),\n\t} as SessionSnapshotPayload<ValueKey, Value>;\n}\n\nexport function appendSessionSnapshot<Value extends object, ValueKey extends string>(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n\tvalue: Value,\n): string {\n\treturn sessionManager.appendCustomEntry(codec.customType, createSessionSnapshotPayload(codec, value));\n}\n\nexport function decodeSessionSnapshotPayload<Value extends object, ValueKey extends string>(\n\tdata: unknown,\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value | undefined {\n\tif (!isVersionOneSessionSnapshotPayload(data)) return undefined;\n\tconst value = data[codec.valueKey];\n\treturn codec.isValue(value) ? codec.clone(value) : undefined;\n}\n\nexport function getSessionSnapshots<Value extends object, ValueKey extends string>(\n\tentries: readonly SessionEntry[],\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value[] {\n\tconst snapshots: Value[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== codec.customType) continue;\n\t\tconst snapshot = decodeSessionSnapshotPayload(entry.data, codec);\n\t\tif (snapshot !== undefined) snapshots.push(snapshot);\n\t}\n\treturn snapshots;\n}\n\nexport function getLatestSessionSnapshot<Value extends object, ValueKey extends string>(\n\tentries: readonly SessionEntry[],\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value | undefined {\n\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\tconst entry = entries[index];\n\t\tif (entry.type !== \"custom\" || entry.customType !== codec.customType) continue;\n\t\tconst snapshot = decodeSessionSnapshotPayload(entry.data, codec);\n\t\tif (snapshot !== undefined) return snapshot;\n\t}\n\treturn undefined;\n}\n\n/**\n * Resolves the newest valid snapshot on the active branch. Malformed entries are skipped while\n * walking leaf to root so they cannot hide an older valid checkpoint.\n */\nexport function getLatestSessionSnapshotOnBranch<Value extends object, ValueKey extends string>(\n\tsessionManager: Pick<SessionManager, \"getLatestCustomEntryOnBranch\">,\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value | undefined {\n\tlet fromId: string | undefined;\n\tfor (;;) {\n\t\tconst entry = sessionManager.getLatestCustomEntryOnBranch(codec.customType, fromId);\n\t\tif (!entry) return undefined;\n\t\tconst snapshot = decodeSessionSnapshotPayload(entry.data, codec);\n\t\tif (snapshot !== undefined) return snapshot;\n\t\tif (entry.parentId === null) return undefined;\n\t\tfromId = entry.parentId;\n\t}\n}\n"]}
@@ -0,0 +1,68 @@
1
+ import { isPlainRecord } from "./util/value-guards.js";
2
+ /** Active branch when available; linear entry history only for narrow stores that expose no branch API. */
3
+ export function getActiveSessionBranchEntries(source) {
4
+ if (typeof source.getBranch === "function")
5
+ return source.getBranch();
6
+ if (typeof source.getEntries === "function")
7
+ return source.getEntries();
8
+ throw new TypeError("Session branch entry source exposes neither getBranch nor getEntries");
9
+ }
10
+ export function isVersionOneSessionSnapshotPayload(data) {
11
+ return isPlainRecord(data) && data.version === 1;
12
+ }
13
+ export function createSessionSnapshotPayload(codec, value) {
14
+ return {
15
+ version: 1,
16
+ [codec.valueKey]: codec.clone(value),
17
+ };
18
+ }
19
+ export function appendSessionSnapshot(sessionManager, codec, value) {
20
+ return sessionManager.appendCustomEntry(codec.customType, createSessionSnapshotPayload(codec, value));
21
+ }
22
+ export function decodeSessionSnapshotPayload(data, codec) {
23
+ if (!isVersionOneSessionSnapshotPayload(data))
24
+ return undefined;
25
+ const value = data[codec.valueKey];
26
+ return codec.isValue(value) ? codec.clone(value) : undefined;
27
+ }
28
+ export function getSessionSnapshots(entries, codec) {
29
+ const snapshots = [];
30
+ for (const entry of entries) {
31
+ if (entry.type !== "custom" || entry.customType !== codec.customType)
32
+ continue;
33
+ const snapshot = decodeSessionSnapshotPayload(entry.data, codec);
34
+ if (snapshot !== undefined)
35
+ snapshots.push(snapshot);
36
+ }
37
+ return snapshots;
38
+ }
39
+ export function getLatestSessionSnapshot(entries, codec) {
40
+ for (let index = entries.length - 1; index >= 0; index--) {
41
+ const entry = entries[index];
42
+ if (entry.type !== "custom" || entry.customType !== codec.customType)
43
+ continue;
44
+ const snapshot = decodeSessionSnapshotPayload(entry.data, codec);
45
+ if (snapshot !== undefined)
46
+ return snapshot;
47
+ }
48
+ return undefined;
49
+ }
50
+ /**
51
+ * Resolves the newest valid snapshot on the active branch. Malformed entries are skipped while
52
+ * walking leaf to root so they cannot hide an older valid checkpoint.
53
+ */
54
+ export function getLatestSessionSnapshotOnBranch(sessionManager, codec) {
55
+ let fromId;
56
+ for (;;) {
57
+ const entry = sessionManager.getLatestCustomEntryOnBranch(codec.customType, fromId);
58
+ if (!entry)
59
+ return undefined;
60
+ const snapshot = decodeSessionSnapshotPayload(entry.data, codec);
61
+ if (snapshot !== undefined)
62
+ return snapshot;
63
+ if (entry.parentId === null)
64
+ return undefined;
65
+ fromId = entry.parentId;
66
+ }
67
+ }
68
+ //# sourceMappingURL=session-snapshot.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-snapshot.js","sourceRoot":"","sources":["../../src/core/session-snapshot.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport { isPlainRecord } from \"./util/value-guards.ts\";\n\nexport type SessionSnapshotPayload<ValueKey extends string, Value extends object> = {\n\tversion: 1;\n} & {\n\t[Key in ValueKey]: Value;\n};\n\nexport interface SessionSnapshotCodec<Value extends object, ValueKey extends string> {\n\tcustomType: string;\n\tvalueKey: ValueKey;\n\tisValue(value: unknown): value is Value;\n\tclone(value: Value): Value;\n}\n\nexport interface SessionBranchEntrySource {\n\tgetBranch?: () => readonly SessionEntry[];\n\tgetEntries?: () => readonly SessionEntry[];\n}\n\ntype VersionOneSnapshotPayload = Record<string, unknown> & { version: 1 };\n\n/** Active branch when available; linear entry history only for narrow stores that expose no branch API. */\nexport function getActiveSessionBranchEntries(source: SessionBranchEntrySource): readonly SessionEntry[] {\n\tif (typeof source.getBranch === \"function\") return source.getBranch();\n\tif (typeof source.getEntries === \"function\") return source.getEntries();\n\tthrow new TypeError(\"Session branch entry source exposes neither getBranch nor getEntries\");\n}\n\nexport function isVersionOneSessionSnapshotPayload(data: unknown): data is VersionOneSnapshotPayload {\n\treturn isPlainRecord(data) && data.version === 1;\n}\n\nexport function createSessionSnapshotPayload<Value extends object, ValueKey extends string>(\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n\tvalue: Value,\n): SessionSnapshotPayload<ValueKey, Value> {\n\treturn {\n\t\tversion: 1,\n\t\t[codec.valueKey]: codec.clone(value),\n\t} as SessionSnapshotPayload<ValueKey, Value>;\n}\n\nexport function appendSessionSnapshot<Value extends object, ValueKey extends string>(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n\tvalue: Value,\n): string {\n\treturn sessionManager.appendCustomEntry(codec.customType, createSessionSnapshotPayload(codec, value));\n}\n\nexport function decodeSessionSnapshotPayload<Value extends object, ValueKey extends string>(\n\tdata: unknown,\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value | undefined {\n\tif (!isVersionOneSessionSnapshotPayload(data)) return undefined;\n\tconst value = data[codec.valueKey];\n\treturn codec.isValue(value) ? codec.clone(value) : undefined;\n}\n\nexport function getSessionSnapshots<Value extends object, ValueKey extends string>(\n\tentries: readonly SessionEntry[],\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value[] {\n\tconst snapshots: Value[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== codec.customType) continue;\n\t\tconst snapshot = decodeSessionSnapshotPayload(entry.data, codec);\n\t\tif (snapshot !== undefined) snapshots.push(snapshot);\n\t}\n\treturn snapshots;\n}\n\nexport function getLatestSessionSnapshot<Value extends object, ValueKey extends string>(\n\tentries: readonly SessionEntry[],\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value | undefined {\n\tfor (let index = entries.length - 1; index >= 0; index--) {\n\t\tconst entry = entries[index];\n\t\tif (entry.type !== \"custom\" || entry.customType !== codec.customType) continue;\n\t\tconst snapshot = decodeSessionSnapshotPayload(entry.data, codec);\n\t\tif (snapshot !== undefined) return snapshot;\n\t}\n\treturn undefined;\n}\n\n/**\n * Resolves the newest valid snapshot on the active branch. Malformed entries are skipped while\n * walking leaf to root so they cannot hide an older valid checkpoint.\n */\nexport function getLatestSessionSnapshotOnBranch<Value extends object, ValueKey extends string>(\n\tsessionManager: Pick<SessionManager, \"getLatestCustomEntryOnBranch\">,\n\tcodec: SessionSnapshotCodec<Value, ValueKey>,\n): Value | undefined {\n\tlet fromId: string | undefined;\n\tfor (;;) {\n\t\tconst entry = sessionManager.getLatestCustomEntryOnBranch(codec.customType, fromId);\n\t\tif (!entry) return undefined;\n\t\tconst snapshot = decodeSessionSnapshotPayload(entry.data, codec);\n\t\tif (snapshot !== undefined) return snapshot;\n\t\tif (entry.parentId === null) return undefined;\n\t\tfromId = entry.parentId;\n\t}\n}\n"]}
@@ -0,0 +1,31 @@
1
+ import type { AgentSession } from "./agent-session.ts";
2
+ import type { AgentSessionRuntimeResource } from "./agent-session-runtime.ts";
3
+ import type { ResumablePayload } from "./process-matrix/codes.ts";
4
+ import { type ResumeWorkerLaunchOutcome } from "./process-matrix/runtime.ts";
5
+ export interface SessionSupervisionRuntimeOptions {
6
+ agentDir: string;
7
+ hasUI: boolean;
8
+ orchestrationProfileId?: string;
9
+ isProcessAlive: (pid: number) => boolean;
10
+ promptConfirm: (message: string) => Promise<boolean>;
11
+ resumeWorker: (payload: ResumablePayload, parentSessionId: string) => Promise<ResumeWorkerLaunchOutcome>;
12
+ onDiagnostic: (message: string) => void;
13
+ requestExit: (session: AgentSession) => void;
14
+ }
15
+ /**
16
+ * Owns the process-matrix and worktree-sync handles for the currently active session.
17
+ * Replacement stops the old generation before a new one is started, so no watcher can retain a
18
+ * disposed session or deliver a notice across a `/new`, `/resume`, or `/fork` boundary.
19
+ */
20
+ export declare class SessionSupervisionRuntime implements AgentSessionRuntimeResource {
21
+ private readonly options;
22
+ private generation;
23
+ private processMatrix?;
24
+ private worktreeSync?;
25
+ constructor(options: SessionSupervisionRuntimeOptions);
26
+ start(session: AgentSession): Promise<void>;
27
+ stop(): Promise<void>;
28
+ private stopHandles;
29
+ private notify;
30
+ }
31
+ //# sourceMappingURL=session-supervision-runtime.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"session-supervision-runtime.d.ts","sourceRoot":"","sources":["../../src/core/session-supervision-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AACvD,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,4BAA4B,CAAC;AAE9E,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2BAA2B,CAAC;AAClE,OAAO,EAIN,KAAK,yBAAyB,EAE9B,MAAM,6BAA6B,CAAC;AAIrC,MAAM,WAAW,gCAAgC;IAChD,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,OAAO,CAAC;IACf,sBAAsB,CAAC,EAAE,MAAM,CAAC;IAChC,cAAc,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACzC,aAAa,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAC;IACrD,YAAY,EAAE,CAAC,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,KAAK,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACzG,YAAY,EAAE,CAAC,OAAO,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,WAAW,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC;CAC7C;AAED;;;;GAIG;AACH,qBAAa,yBAA0B,YAAW,2BAA2B;IAC5E,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAmC;IAC3D,OAAO,CAAC,UAAU,CAAK;IACvB,OAAO,CAAC,aAAa,CAAC,CAA6B;IACnD,OAAO,CAAC,YAAY,CAAC,CAA4B;IAEjD,YAAY,OAAO,EAAE,gCAAgC,EAEpD;IAEK,KAAK,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,IAAI,CAAC,CA4DhD;IAEK,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC,CAG1B;YAEa,WAAW;YAQX,MAAM;CAYpB","sourcesContent":["import type { AgentSession } from \"./agent-session.ts\";\nimport type { AgentSessionRuntimeResource } from \"./agent-session-runtime.ts\";\nimport { createAgentIdentity } from \"./orchestration/agent-resume.ts\";\nimport type { ResumablePayload } from \"./process-matrix/codes.ts\";\nimport {\n\tgetOrchestrationAgentId,\n\tgetProcessTaskRef,\n\ttype ProcessMatrixRuntimeHandle,\n\ttype ResumeWorkerLaunchOutcome,\n\tstartProcessMatrixRuntime,\n} from \"./process-matrix/runtime.ts\";\nimport type { WorktreeSyncRuntimeHandle } from \"./worktree-sync/runtime.ts\";\nimport { getBoundWorktreeLaneKey, startWorktreeSyncRuntime } from \"./worktree-sync/runtime.ts\";\n\nexport interface SessionSupervisionRuntimeOptions {\n\tagentDir: string;\n\thasUI: boolean;\n\torchestrationProfileId?: string;\n\tisProcessAlive: (pid: number) => boolean;\n\tpromptConfirm: (message: string) => Promise<boolean>;\n\tresumeWorker: (payload: ResumablePayload, parentSessionId: string) => Promise<ResumeWorkerLaunchOutcome>;\n\tonDiagnostic: (message: string) => void;\n\trequestExit: (session: AgentSession) => void;\n}\n\n/**\n * Owns the process-matrix and worktree-sync handles for the currently active session.\n * Replacement stops the old generation before a new one is started, so no watcher can retain a\n * disposed session or deliver a notice across a `/new`, `/resume`, or `/fork` boundary.\n */\nexport class SessionSupervisionRuntime implements AgentSessionRuntimeResource {\n\tprivate readonly options: SessionSupervisionRuntimeOptions;\n\tprivate generation = 0;\n\tprivate processMatrix?: ProcessMatrixRuntimeHandle;\n\tprivate worktreeSync?: WorktreeSyncRuntimeHandle;\n\n\tconstructor(options: SessionSupervisionRuntimeOptions) {\n\t\tthis.options = options;\n\t}\n\n\tasync start(session: AgentSession): Promise<void> {\n\t\tconst generation = ++this.generation;\n\t\tawait this.stopHandles();\n\t\tconst sessionManager = session.sessionManager;\n\t\tconst sessionId = sessionManager.getSessionId();\n\t\tconst boundWorktreeLaneKey = getBoundWorktreeLaneKey();\n\t\tconst orchestrationProfileId =\n\t\t\tthis.options.orchestrationProfileId ??\n\t\t\tsession.capabilityEnvelope?.profileId ??\n\t\t\tsession.settingsManager.getActiveOrchestrationProfile();\n\t\tconst sessionFile = sessionManager.getSessionFile();\n\t\tconst goal = session.getGoalStateSnapshot();\n\t\tconst taskRef = getProcessTaskRef() ?? goal?.goalId;\n\t\tconst agent = createAgentIdentity(getOrchestrationAgentId() ?? sessionId, {\n\t\t\tprovider: \"pi\",\n\t\t\tsessionId,\n\t\t\tsessionDir: sessionManager.getSessionDir(),\n\t\t\t...(sessionFile ? { sessionFile } : {}),\n\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t...(boundWorktreeLaneKey ? { worktreeLaneKey: boundWorktreeLaneKey } : {}),\n\t\t\t...(orchestrationProfileId ? { orchestrationProfileId } : {}),\n\t\t\tresourceProfileNames: session.settingsManager.getActiveResourceProfileNames(),\n\t\t\t...(session.model ? { modelRef: `${session.model.provider}/${session.model.id}` } : {}),\n\t\t\tcontextPointers: [],\n\t\t});\n\n\t\tconst [worktreeSync, processMatrix] = await Promise.all([\n\t\t\tstartWorktreeSyncRuntime({\n\t\t\t\tcwd: sessionManager.getCwd(),\n\t\t\t\tagentDir: this.options.agentDir,\n\t\t\t\tsettingsManager: session.settingsManager,\n\t\t\t\tsessionId,\n\t\t\t\tnotify: (text) => {\n\t\t\t\t\tvoid this.notify(session, \"worktree-sync-notice\", text).catch(() => {});\n\t\t\t\t},\n\t\t\t\tonDiagnostic: this.options.onDiagnostic,\n\t\t\t}),\n\t\t\tstartProcessMatrixRuntime({\n\t\t\t\tagentDir: this.options.agentDir,\n\t\t\t\tagent,\n\t\t\t\t...(taskRef ? { taskRef } : {}),\n\t\t\t\ttaskSummary: goal?.userGoal,\n\t\t\t\tallowAutomaticRecovery: goal === undefined || goal.status === \"active\",\n\t\t\t\tresumeWorker: (payload) => this.options.resumeWorker(payload, sessionId),\n\t\t\t\thasUI: this.options.hasUI,\n\t\t\t\tsettings: session.settingsManager.getProcessMatrixSettings(),\n\t\t\t\tisProcessAlive: this.options.isProcessAlive,\n\t\t\t\tpromptConfirm: this.options.promptConfirm,\n\t\t\t\tnotify: (text) => this.notify(session, \"process-matrix-notice\", text),\n\t\t\t\tonDiagnostic: this.options.onDiagnostic,\n\t\t\t\trequestExit: () => this.options.requestExit(session),\n\t\t\t}),\n\t\t]);\n\n\t\tif (generation !== this.generation) {\n\t\t\tawait Promise.all([worktreeSync.stop(), processMatrix.stop()]);\n\t\t\treturn;\n\t\t}\n\t\tthis.worktreeSync = worktreeSync;\n\t\tthis.processMatrix = processMatrix;\n\t}\n\n\tasync stop(): Promise<void> {\n\t\tthis.generation++;\n\t\tawait this.stopHandles();\n\t}\n\n\tprivate async stopHandles(): Promise<void> {\n\t\tconst worktreeSync = this.worktreeSync;\n\t\tconst processMatrix = this.processMatrix;\n\t\tthis.worktreeSync = undefined;\n\t\tthis.processMatrix = undefined;\n\t\tawait Promise.all([worktreeSync?.stop(), processMatrix?.stop()]);\n\t}\n\n\tprivate async notify(session: AgentSession, customType: string, text: string): Promise<void> {\n\t\ttry {\n\t\t\tawait session.sendCustomMessage(\n\t\t\t\t{ customType, content: text, display: true },\n\t\t\t\t{ triggerTurn: true, deliverAs: \"steer\" },\n\t\t\t);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tthis.options.onDiagnostic(`${customType}: failed to notify session: ${message}`);\n\t\t\tthrow error;\n\t\t}\n\t}\n}\n"]}