@phyzess/pappra 0.1.0-beta.13 → 0.1.0-beta.18

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 (357) hide show
  1. package/README.md +134 -15
  2. package/assets/integrations/skills/pappra/SKILL.md +28 -7
  3. package/assets/integrations/skills/pappra/references/collaboration.md +633 -0
  4. package/assets/integrations/skills/pappra/references/environment.md +360 -0
  5. package/assets/integrations/skills/pappra/references/hosts.md +20 -0
  6. package/assets/integrations/skills/pappra/references/operations.md +36 -5
  7. package/dist/adapters/pi/recovery-extension.d.ts +65 -0
  8. package/dist/adapters/pi/recovery-extension.js +238 -0
  9. package/dist/adapters/pi/session-transition-extension.d.ts +30 -0
  10. package/dist/adapters/pi/session-transition-extension.js +265 -0
  11. package/dist/app/automatic-handoff-events.d.ts +26 -0
  12. package/dist/app/automatic-handoff-events.js +134 -0
  13. package/dist/app/bounded-file.d.ts +2 -0
  14. package/dist/app/bounded-file.js +2 -0
  15. package/dist/app/capability-evidence/claude.d.ts +37 -0
  16. package/dist/app/capability-evidence/claude.js +206 -0
  17. package/dist/app/capability-evidence/codex.d.ts +35 -0
  18. package/dist/app/capability-evidence/codex.js +193 -0
  19. package/dist/app/capability-evidence/index.d.ts +33 -0
  20. package/dist/app/capability-evidence/index.js +117 -0
  21. package/dist/app/capability-evidence/pi.d.ts +73 -0
  22. package/dist/app/capability-evidence/pi.js +669 -0
  23. package/dist/app/capability-evidence/shared.d.ts +69 -0
  24. package/dist/app/capability-evidence/shared.js +195 -0
  25. package/dist/app/collab-auto-handoff.d.ts +55 -0
  26. package/dist/app/collab-auto-handoff.js +384 -0
  27. package/dist/app/collab-bindings.d.ts +57 -0
  28. package/dist/app/collab-bindings.js +1006 -0
  29. package/dist/app/collab-bootstrap-transport.d.ts +163 -0
  30. package/dist/app/collab-bootstrap-transport.js +769 -0
  31. package/dist/app/collab-bootstrap.d.ts +137 -0
  32. package/dist/app/collab-bootstrap.js +3455 -0
  33. package/dist/app/collab-handoff.d.ts +12 -0
  34. package/dist/app/collab-handoff.js +511 -0
  35. package/dist/app/collab-messages.d.ts +2 -0
  36. package/dist/app/collab-messages.js +2 -0
  37. package/dist/app/collab-notify.d.ts +156 -0
  38. package/dist/app/collab-notify.js +1208 -0
  39. package/dist/app/collab-preflight.d.ts +34 -0
  40. package/dist/app/collab-preflight.js +96 -0
  41. package/dist/app/collab-recovery-executor.d.ts +161 -0
  42. package/dist/app/collab-recovery-executor.js +1153 -0
  43. package/dist/app/collab-recovery-projection.d.ts +103 -0
  44. package/dist/app/collab-recovery-projection.js +659 -0
  45. package/dist/app/collab-recovery.d.ts +25 -0
  46. package/dist/app/collab-recovery.js +429 -0
  47. package/dist/app/collab-resources.d.ts +16 -0
  48. package/dist/app/collab-resources.js +278 -0
  49. package/dist/app/collab-role-events.d.ts +22 -0
  50. package/dist/app/collab-role-events.js +329 -0
  51. package/dist/app/collab-role-orchestration.d.ts +53 -0
  52. package/dist/app/collab-role-orchestration.js +601 -0
  53. package/dist/app/collab-role-plan.d.ts +81 -0
  54. package/dist/app/collab-role-plan.js +504 -0
  55. package/dist/app/collab-role-repair.d.ts +109 -0
  56. package/dist/app/collab-role-repair.js +821 -0
  57. package/dist/app/collab-rollover.d.ts +263 -0
  58. package/dist/app/collab-rollover.js +1112 -0
  59. package/dist/app/collab-route.d.ts +64 -0
  60. package/dist/app/collab-route.js +240 -0
  61. package/dist/app/collab-session-transition.d.ts +221 -0
  62. package/dist/app/collab-session-transition.js +3334 -0
  63. package/dist/app/collab-state.d.ts +7 -0
  64. package/dist/app/collab-state.js +162 -0
  65. package/dist/app/collab-task-store.d.ts +22 -0
  66. package/dist/app/collab-task-store.js +204 -0
  67. package/dist/app/collab-work-execution.d.ts +127 -0
  68. package/dist/app/collab-work-execution.js +1027 -0
  69. package/dist/app/collab-work-plan.d.ts +87 -0
  70. package/dist/app/collab-work-plan.js +437 -0
  71. package/dist/app/collaboration.d.ts +8 -2
  72. package/dist/app/collaboration.js +101 -12
  73. package/dist/app/doctor.js +108 -5
  74. package/dist/app/host-mcp.js +34 -8
  75. package/dist/app/host-probe.js +4 -4
  76. package/dist/app/init.d.ts +58 -4
  77. package/dist/app/init.js +768 -155
  78. package/dist/app/managed-pi-bootstrap-admission.d.ts +14 -0
  79. package/dist/app/managed-pi-bootstrap-admission.js +104 -0
  80. package/dist/app/managed-pi-bootstrap-refresh.d.ts +10 -0
  81. package/dist/app/managed-pi-bootstrap-refresh.js +78 -0
  82. package/dist/app/managed-pi-delivery.d.ts +8 -0
  83. package/dist/app/managed-pi-delivery.js +110 -0
  84. package/dist/app/managed-pi-handoff-receiver.d.ts +15 -0
  85. package/dist/app/managed-pi-handoff-receiver.js +263 -0
  86. package/dist/app/managed-pi-handoff-reference.d.ts +3 -0
  87. package/dist/app/managed-pi-handoff-reference.js +60 -0
  88. package/dist/app/managed-pi-herdr.d.ts +21 -0
  89. package/dist/app/managed-pi-herdr.js +185 -0
  90. package/dist/app/managed-pi-initial-admission.d.ts +28 -0
  91. package/dist/app/managed-pi-initial-admission.js +416 -0
  92. package/dist/app/managed-pi-initial-launch.d.ts +5 -0
  93. package/dist/app/managed-pi-initial-launch.js +61 -0
  94. package/dist/app/managed-pi-native-observation.d.ts +36 -0
  95. package/dist/app/managed-pi-native-observation.js +191 -0
  96. package/dist/app/managed-pi-readiness.d.ts +29 -0
  97. package/dist/app/managed-pi-readiness.js +288 -0
  98. package/dist/app/managed-pi-repair-stop.d.ts +21 -0
  99. package/dist/app/managed-pi-repair-stop.js +371 -0
  100. package/dist/app/managed-pi-resume-admission.d.ts +32 -0
  101. package/dist/app/managed-pi-resume-admission.js +618 -0
  102. package/dist/app/managed-pi-retirement.d.ts +28 -0
  103. package/dist/app/managed-pi-retirement.js +112 -0
  104. package/dist/app/managed-pi-sdk-control.d.ts +7 -0
  105. package/dist/app/managed-pi-sdk-control.js +169 -0
  106. package/dist/app/managed-pi-sdk-runtime.d.ts +3 -0
  107. package/dist/app/managed-pi-sdk-runtime.js +483 -0
  108. package/dist/app/managed-pi-source-admission.d.ts +14 -0
  109. package/dist/app/managed-pi-source-admission.js +323 -0
  110. package/dist/app/managed-pi-transition-host.d.ts +36 -0
  111. package/dist/app/managed-pi-transition-host.js +292 -0
  112. package/dist/app/managed-pi.d.ts +54 -0
  113. package/dist/app/managed-pi.js +248 -0
  114. package/dist/app/shell-readiness.d.ts +66 -0
  115. package/dist/app/shell-readiness.js +368 -0
  116. package/dist/app/task-pin.d.ts +2 -23
  117. package/dist/app/task-pin.js +2 -113
  118. package/dist/cli/commands/collaboration-binding.d.ts +13 -0
  119. package/dist/cli/commands/collaboration-binding.js +118 -0
  120. package/dist/cli/commands/collaboration-bootstrap.d.ts +10 -0
  121. package/dist/cli/commands/collaboration-bootstrap.js +84 -0
  122. package/dist/cli/commands/collaboration-capabilities.d.ts +13 -0
  123. package/dist/cli/commands/collaboration-capabilities.js +127 -0
  124. package/dist/cli/commands/collaboration-handoff.d.ts +13 -0
  125. package/dist/cli/commands/collaboration-handoff.js +102 -0
  126. package/dist/cli/commands/collaboration-message.d.ts +17 -0
  127. package/dist/cli/commands/collaboration-message.js +177 -0
  128. package/dist/cli/commands/collaboration-plan.d.ts +8 -0
  129. package/dist/cli/commands/collaboration-plan.js +108 -0
  130. package/dist/cli/commands/collaboration-preflight.d.ts +10 -0
  131. package/dist/cli/commands/collaboration-preflight.js +167 -0
  132. package/dist/cli/commands/collaboration-recovery-run.d.ts +46 -0
  133. package/dist/cli/commands/collaboration-recovery-run.js +224 -0
  134. package/dist/cli/commands/collaboration-recovery.d.ts +11 -0
  135. package/dist/cli/commands/collaboration-recovery.js +104 -0
  136. package/dist/cli/commands/collaboration-resources.d.ts +11 -0
  137. package/dist/cli/commands/collaboration-resources.js +96 -0
  138. package/dist/cli/commands/collaboration-role-plan.d.ts +9 -0
  139. package/dist/cli/commands/collaboration-role-plan.js +69 -0
  140. package/dist/cli/commands/collaboration-role-run.d.ts +11 -0
  141. package/dist/cli/commands/collaboration-role-run.js +128 -0
  142. package/dist/cli/commands/collaboration-rollover.d.ts +10 -0
  143. package/dist/cli/commands/collaboration-rollover.js +103 -0
  144. package/dist/cli/commands/collaboration-state.d.ts +10 -0
  145. package/dist/cli/commands/collaboration-state.js +96 -0
  146. package/dist/cli/commands/collaboration-transition.d.ts +10 -0
  147. package/dist/cli/commands/collaboration-transition.js +75 -0
  148. package/dist/cli/commands/collaboration-work-run.d.ts +34 -0
  149. package/dist/cli/commands/collaboration-work-run.js +178 -0
  150. package/dist/cli/commands/collaboration.d.ts +4 -0
  151. package/dist/cli/commands/collaboration.js +39 -4
  152. package/dist/cli/commands/continuity.js +2 -6
  153. package/dist/cli/commands/docs.d.ts +2 -0
  154. package/dist/cli/commands/docs.js +89 -15
  155. package/dist/cli/commands/host.d.ts +7 -1
  156. package/dist/cli/commands/host.js +122 -7
  157. package/dist/cli/commands/init.d.ts +20 -3
  158. package/dist/cli/commands/init.js +897 -232
  159. package/dist/cli/commands/mcp.d.ts +1 -0
  160. package/dist/cli/commands/mcp.js +11 -5
  161. package/dist/cli/commands/repair.d.ts +12 -0
  162. package/dist/cli/commands/repair.js +41 -0
  163. package/dist/cli/commands/runtime.d.ts +1 -1
  164. package/dist/cli/commands/runtime.js +139 -38
  165. package/dist/cli/commands/session.d.ts +7 -0
  166. package/dist/cli/commands/session.js +82 -0
  167. package/dist/cli/commands/task.js +19 -5
  168. package/dist/cli/run.js +866 -24
  169. package/dist/code/identity.d.ts +7 -0
  170. package/dist/code/identity.js +7 -3
  171. package/dist/code/registration.js +7 -0
  172. package/dist/code/service.d.ts +9 -0
  173. package/dist/code/service.js +16 -3
  174. package/dist/code/text.js +19 -7
  175. package/dist/collab/admission.d.ts +91 -66
  176. package/dist/collab/admission.js +21 -6
  177. package/dist/collab/canonical.d.ts +1 -1
  178. package/dist/collab/canonical.js +44 -3
  179. package/dist/collab/envelope.d.ts +2 -2
  180. package/dist/collab/envelope.js +12 -12
  181. package/dist/collab/first-work.d.ts +3 -0
  182. package/dist/collab/first-work.js +15 -0
  183. package/dist/collab/handoff.d.ts +16 -0
  184. package/dist/collab/handoff.js +39 -5
  185. package/dist/collab/index.d.ts +97 -1
  186. package/dist/collab/index.js +9 -1
  187. package/dist/collab/messages.js +126 -3
  188. package/dist/collab/persisted-messages.d.ts +123 -0
  189. package/dist/collab/persisted-messages.js +496 -0
  190. package/dist/collab/preflight.d.ts +1 -1
  191. package/dist/collab/resources.d.ts +13 -3
  192. package/dist/collab/resources.js +37 -6
  193. package/dist/collab/rollover.d.ts +311 -0
  194. package/dist/collab/rollover.js +1024 -0
  195. package/dist/collab/store.d.ts +1 -0
  196. package/dist/collab/store.js +1 -4
  197. package/dist/collab/types.d.ts +2 -354
  198. package/dist/collab/validation.d.ts +2 -10
  199. package/dist/collab/validation.js +2 -303
  200. package/dist/collab/work-plan.d.ts +105 -0
  201. package/dist/collab/work-plan.js +843 -0
  202. package/dist/continuity/context.d.ts +11 -2
  203. package/dist/continuity/context.js +100 -13
  204. package/dist/continuity/handoff-bundle.d.ts +296 -0
  205. package/dist/continuity/handoff-bundle.js +477 -0
  206. package/dist/continuity/index.d.ts +2 -0
  207. package/dist/continuity/index.js +1 -0
  208. package/dist/continuity/paths.js +10 -2
  209. package/dist/continuity/service.js +91 -15
  210. package/dist/continuity/task-pin.d.ts +24 -0
  211. package/dist/continuity/task-pin.js +590 -0
  212. package/dist/doctor.d.ts +1 -0
  213. package/dist/doctor.js +6 -0
  214. package/dist/experimental/index.d.ts +13 -0
  215. package/dist/experimental/index.js +25 -0
  216. package/dist/experimental/pi.d.ts +4 -0
  217. package/dist/experimental/pi.js +12 -0
  218. package/dist/hosts/claude/native.js +1 -1
  219. package/dist/hosts/codex/native.js +1 -1
  220. package/dist/hosts/codex/protocol.js +1 -1
  221. package/dist/hosts/integration/bootstrap-config.d.ts +58 -0
  222. package/dist/hosts/integration/bootstrap-config.js +254 -0
  223. package/dist/hosts/integration/bundle-export.d.ts +44 -0
  224. package/dist/hosts/integration/bundle-export.js +366 -3
  225. package/dist/hosts/integration/bundle.js +3 -0
  226. package/dist/hosts/integration/hook.js +36 -9
  227. package/dist/hosts/integration/pappra-bootstrap-extension.mjs +80 -0
  228. package/dist/hosts/integration/pappra-extension-runtime.mjs +59 -24631
  229. package/dist/hosts/integration/pappra-hook.mjs +61 -24749
  230. package/dist/hosts/integration/pappra-recovery-extension.mjs +259 -0
  231. package/dist/hosts/integration/pappra-session-transition-extension.mjs +276 -0
  232. package/dist/hosts/integration/pi-bootstrap-extension.d.ts +36 -0
  233. package/dist/hosts/integration/pi-bootstrap-extension.js +101 -0
  234. package/dist/hosts/integration/pi-bootstrap-guard.d.ts +125 -0
  235. package/dist/hosts/integration/pi-bootstrap-guard.js +438 -0
  236. package/dist/hosts/integration/pi-bootstrap-runtime.d.ts +63 -0
  237. package/dist/hosts/integration/pi-bootstrap-runtime.js +223 -0
  238. package/dist/hosts/integration/pi-native-events.d.ts +112 -0
  239. package/dist/hosts/integration/pi-native-events.js +348 -0
  240. package/dist/hosts/integration/pi-rollover-extension.d.ts +166 -0
  241. package/dist/hosts/integration/pi-rollover-extension.js +431 -0
  242. package/dist/hosts/integration/recovery-config.d.ts +48 -0
  243. package/dist/hosts/integration/recovery-config.js +117 -0
  244. package/dist/hosts/integration/service.d.ts +6 -1
  245. package/dist/hosts/integration/service.js +485 -35
  246. package/dist/hosts/integration/support.d.ts +7 -0
  247. package/dist/hosts/integration/support.js +9 -1
  248. package/dist/hosts/integration/templates.d.ts +3 -0
  249. package/dist/hosts/integration/templates.js +26 -3
  250. package/dist/hosts/pi/managed-host-identity.d.ts +2 -0
  251. package/dist/hosts/pi/managed-host-identity.js +40 -0
  252. package/dist/hosts/pi/managed-provider-diagnostics.d.ts +6 -0
  253. package/dist/hosts/pi/managed-provider-diagnostics.js +184 -0
  254. package/dist/hosts/pi/managed-sdk-session.d.ts +335 -0
  255. package/dist/hosts/pi/managed-sdk-session.js +1639 -0
  256. package/dist/hosts/pi/managed-session-extension.d.ts +20 -0
  257. package/dist/hosts/pi/managed-session-extension.js +84 -0
  258. package/dist/hosts/pi/managed-session.d.ts +177 -0
  259. package/dist/hosts/pi/managed-session.js +1557 -0
  260. package/dist/hosts/pi/protocol.js +1 -1
  261. package/dist/hosts/pi/query-result.js +1 -1
  262. package/dist/hosts/pi/resume-capability.d.ts +41 -0
  263. package/dist/hosts/pi/resume-capability.js +33 -0
  264. package/dist/hosts/pi/rpc.d.ts +182 -134
  265. package/dist/hosts/pi/rpc.js +230 -37
  266. package/dist/hosts/pilot.d.ts +97 -74
  267. package/dist/hosts/pilot.js +5 -1
  268. package/dist/hosts/version.d.ts +3 -0
  269. package/dist/hosts/version.js +18 -0
  270. package/dist/index.d.ts +0 -1
  271. package/dist/index.js +0 -1
  272. package/dist/infra/bounded-file.d.ts +19 -0
  273. package/dist/infra/bounded-file.js +66 -0
  274. package/dist/infra/fs.js +10 -2
  275. package/dist/infra/git.d.ts +29 -0
  276. package/dist/infra/git.js +45 -9
  277. package/dist/infra/json-property.d.ts +2 -0
  278. package/dist/infra/json-property.js +69 -0
  279. package/dist/infra/json.d.ts +4 -0
  280. package/dist/infra/json.js +24 -0
  281. package/dist/infra/owned-process-group.js +1 -1
  282. package/dist/infra/private-lock.d.ts +16 -0
  283. package/dist/infra/private-lock.js +148 -0
  284. package/dist/infra/private-state.d.ts +7 -0
  285. package/dist/infra/private-state.js +146 -0
  286. package/dist/infra/process-identity.d.ts +12 -0
  287. package/dist/infra/process-identity.js +142 -0
  288. package/dist/infra/validation.d.ts +5 -0
  289. package/dist/infra/validation.js +15 -0
  290. package/dist/init.d.ts +1 -0
  291. package/dist/init.js +6 -0
  292. package/dist/install/apply.d.ts +9 -1
  293. package/dist/install/apply.js +176 -12
  294. package/dist/install/dependencies.d.ts +38 -0
  295. package/dist/install/dependencies.js +282 -0
  296. package/dist/install/ownership.js +30 -1
  297. package/dist/install/references.d.ts +31 -0
  298. package/dist/install/references.js +208 -0
  299. package/dist/install/repair.d.ts +37 -0
  300. package/dist/install/repair.js +798 -0
  301. package/dist/install/reset-local.d.ts +16 -0
  302. package/dist/install/reset-local.js +304 -0
  303. package/dist/install/rollback.d.ts +3 -0
  304. package/dist/install/rollback.js +9 -3
  305. package/dist/install/runtime.d.ts +10 -6
  306. package/dist/install/runtime.js +299 -59
  307. package/dist/install/source-fingerprint.d.ts +2 -0
  308. package/dist/install/source-fingerprint.js +103 -0
  309. package/dist/knowledge/catalog.d.ts +1 -0
  310. package/dist/knowledge/catalog.js +143 -10
  311. package/dist/knowledge/journal.js +17 -7
  312. package/dist/knowledge/paths.js +2 -1
  313. package/dist/knowledge/refs.js +4 -0
  314. package/dist/knowledge/register-batch.d.ts +4 -0
  315. package/dist/knowledge/register-batch.js +225 -0
  316. package/dist/knowledge/relocate.d.ts +5 -0
  317. package/dist/knowledge/relocate.js +92 -0
  318. package/dist/knowledge/scan.js +103 -47
  319. package/dist/knowledge/service.d.ts +3 -0
  320. package/dist/knowledge/service.js +33 -1
  321. package/dist/knowledge/write.d.ts +4 -1
  322. package/dist/knowledge/write.js +1 -1
  323. package/dist/mcp/server.d.ts +4 -2
  324. package/dist/mcp/server.js +87 -136
  325. package/dist/schemas/collaboration-state-validation.d.ts +6 -0
  326. package/dist/schemas/collaboration-state-validation.js +342 -0
  327. package/dist/schemas/collaboration-state.d.ts +436 -0
  328. package/dist/schemas/collaboration-state.js +1 -0
  329. package/dist/schemas/collaboration.d.ts +335 -0
  330. package/dist/schemas/collaboration.js +272 -0
  331. package/dist/schemas/continuity.d.ts +8 -0
  332. package/dist/schemas/continuity.js +13 -3
  333. package/dist/schemas/doctor.d.ts +1 -0
  334. package/dist/schemas/doctor.js +1 -0
  335. package/dist/schemas/document.d.ts +61 -0
  336. package/dist/schemas/document.js +9 -0
  337. package/dist/schemas/errors.d.ts +1 -0
  338. package/dist/schemas/errors.js +1 -0
  339. package/dist/schemas/host.d.ts +24 -0
  340. package/dist/schemas/host.js +19 -0
  341. package/dist/schemas/install.d.ts +8 -2
  342. package/dist/schemas/install.js +11 -1
  343. package/dist/schemas/managed-pi-execution.d.ts +16 -0
  344. package/dist/schemas/managed-pi-execution.js +2 -0
  345. package/dist/schemas/outcome.d.ts +9 -5
  346. package/dist/workspace/config-file.js +1 -3
  347. package/dist/workspace/documents.js +12 -2
  348. package/dist/workspace/repositories.d.ts +7 -0
  349. package/dist/workspace/repositories.js +14 -5
  350. package/package.json +35 -35
  351. package/skills/pappra/SKILL.md +28 -7
  352. package/skills/pappra/references/collaboration.md +633 -0
  353. package/skills/pappra/references/environment.md +360 -0
  354. package/skills/pappra/references/hosts.md +20 -0
  355. package/skills/pappra/references/operations.md +36 -5
  356. package/dist/app/collab-from.d.ts +0 -35
  357. package/dist/app/collab-from.js +0 -84
@@ -0,0 +1,238 @@
1
+ // Pi recovery adapter: composes the opt-in recovery extension above `src/app`
2
+ // and `src/hosts`.
3
+ //
4
+ // Loading this extension installs supported startup/settled/manual
5
+ // reconciliation triggers that each run the durable recovery executor once per
6
+ // observed trigger, gated by the ACTUAL host session (not a configuration
7
+ // assertion) and deduplicated by the executor's durable canonical cause. It does
8
+ // not touch the accepted observation-only native-event producer, never spawns a
9
+ // session or a hidden daemon, never polls for model/worker completion, and never
10
+ // answers approval automatically. There is no known reconnect event: if no
11
+ // supported trigger fires, nothing is reconciled, and a missing host observation
12
+ // stays explicit rather than being manufactured to unblock an enqueue. An initial
13
+ // no-op does not suppress a later genuine cause, and recovery's own settled event
14
+ // cannot re-issue an already-reserved cause (no self-loop).
15
+ //
16
+ // Composition lives here rather than in `src/hosts/integration`: the host layer
17
+ // must not depend on application orchestration. The configuration format is owned
18
+ // by the lower-layer reader re-exported below, so bundle export inside `src/hosts`
19
+ // validates the same bytes without reaching this module.
20
+ import { fileURLToPath } from 'node:url';
21
+ import { createHerdrRecoveryController, executeRecovery, } from '../../app/collab-recovery-executor.js';
22
+ import { readPiRecoveryConfig, } from '../../hosts/integration/recovery-config.js';
23
+ export { PI_RECOVERY_CONFIG_SCHEMA, readPiRecoveryConfig, } from '../../hosts/integration/recovery-config.js';
24
+ export const PI_RECOVERY_STATUS_SCHEMA = 'pappra/pi-recovery-status/1';
25
+ const LIMITATIONS = Object.freeze([
26
+ 'opt_in_explicit_configuration_only_no_ambient_task_discovery',
27
+ 'actual_host_session_gated_not_a_configuration_assertion',
28
+ 'no_known_reconnect_event_missing_observation_stays_explicit',
29
+ 'cause_aware_durable_dedup_prevents_self_wake_loops',
30
+ 'no_new_session_hidden_daemon_completion_poll_or_approval_auto',
31
+ 'submission_or_queue_acceptance_is_not_consumption_or_completion',
32
+ ]);
33
+ /**
34
+ * Build a single-flight reconciler. Every supported trigger may run; a reconcile never overlaps another.
35
+ * The ACTUAL observed host session must match the configured expected session before any work — a config
36
+ * loaded in a foreign session is skipped. Re-issuing the same cause is prevented durably by the executor's
37
+ * canonical-cause reservation, so a later new cause can still progress while recovery's own settled event
38
+ * cannot repeatedly wake itself.
39
+ */
40
+ export function createRecoveryReconciler(config, deps, configDigest = null) {
41
+ const execute = deps.execute ?? executeRecovery;
42
+ const expectedSession = {
43
+ session_id: config.expected.session_id,
44
+ cwd: config.expected.cwd,
45
+ binding_digest: config.expected.binding_digest,
46
+ binding_ref: config.expected.binding_ref,
47
+ target_agent: config.target.agent,
48
+ pane_id: config.expected.pane_id,
49
+ harness: config.expected.harness,
50
+ };
51
+ const issued = new Set();
52
+ let reconcileCount = 0;
53
+ let running = false;
54
+ let last = null;
55
+ const record = (outcome) => {
56
+ last = outcome;
57
+ return outcome;
58
+ };
59
+ return {
60
+ async reconcile(trigger, hostFacts) {
61
+ if (running)
62
+ return record({
63
+ trigger,
64
+ skipped: true,
65
+ reason: 'a reconciliation is already in progress; not overlapping.',
66
+ });
67
+ if (hostFacts === null)
68
+ return record({
69
+ trigger,
70
+ skipped: true,
71
+ reason: 'the actual host session could not be observed; refusing to reconcile without host evidence.',
72
+ });
73
+ if (hostFacts.session_id !== config.expected.session_id)
74
+ return record({
75
+ trigger,
76
+ skipped: true,
77
+ reason: 'the actual host session does not match the configured expected session; refusing to reconcile.',
78
+ });
79
+ if (hostFacts.cwd !== config.expected.cwd)
80
+ return record({
81
+ trigger,
82
+ skipped: true,
83
+ reason: 'the actual host cwd does not match the configured expected cwd; refusing to reconcile.',
84
+ });
85
+ running = true;
86
+ try {
87
+ const result = await execute({
88
+ taskRoot: config.taskRoot,
89
+ planFile: config.planFile,
90
+ self: config.self,
91
+ policy: config.policy,
92
+ requestId: config.requestId,
93
+ mode: config.mode,
94
+ expectedSession,
95
+ }, {
96
+ controller: deps.controller,
97
+ ...(deps.now ? { now: deps.now } : {}),
98
+ ...(deps.sleep ? { sleep: deps.sleep } : {}),
99
+ });
100
+ reconcileCount += 1;
101
+ if (result.reservation &&
102
+ (result.status === 'applied' || result.status === 'deferred'))
103
+ issued.add(result.reservation.key);
104
+ return record({ trigger, skipped: false, result });
105
+ }
106
+ finally {
107
+ running = false;
108
+ }
109
+ },
110
+ status() {
111
+ return {
112
+ schema: PI_RECOVERY_STATUS_SCHEMA,
113
+ registered: true,
114
+ mode: config.mode,
115
+ task_root: config.taskRoot,
116
+ config_digest: configDigest,
117
+ reconcile_count: reconcileCount,
118
+ issued_causes: [...issued],
119
+ last,
120
+ limitations: LIMITATIONS,
121
+ };
122
+ },
123
+ };
124
+ }
125
+ const MAX_HOST_ID_LENGTH = 512;
126
+ function isSafeHostId(value) {
127
+ return (typeof value === 'string' &&
128
+ value.length > 0 &&
129
+ value.length <= MAX_HOST_ID_LENGTH);
130
+ }
131
+ /**
132
+ * Pinned installed Pi API (matching the accepted native-event producer): the running session id is read
133
+ * from `ctx.sessionManager.getSessionId()` with its receiver preserved. Any throwing/missing/invalid access
134
+ * stays null. This is the supported host shape, not a fabricated event field.
135
+ */
136
+ function readHostSessionId(context) {
137
+ try {
138
+ if (typeof context !== 'object' || context === null)
139
+ return null;
140
+ const manager = context.sessionManager;
141
+ if (typeof manager !== 'object' || manager === null)
142
+ return null;
143
+ const getter = manager.getSessionId;
144
+ if (typeof getter !== 'function')
145
+ return null;
146
+ const value = getter.call(manager);
147
+ return isSafeHostId(value) ? value : null;
148
+ }
149
+ catch {
150
+ return null;
151
+ }
152
+ }
153
+ /** Pinned installed Pi API: the working directory is `ctx.cwd`. A throw or non-string stays null. */
154
+ function readHostCwd(context) {
155
+ try {
156
+ if (typeof context !== 'object' || context === null)
157
+ return null;
158
+ const value = context.cwd;
159
+ return typeof value === 'string' && value.length > 0 ? value : null;
160
+ }
161
+ catch {
162
+ return null;
163
+ }
164
+ }
165
+ /**
166
+ * Observe genuine host facts from the supported installed Pi context
167
+ * (`ctx.sessionManager.getSessionId()` and `ctx.cwd`). Returns null when no actual session can be read, so
168
+ * a missing observation stays explicit and is never synthesized.
169
+ */
170
+ export function observeHostFacts(event, context) {
171
+ void event;
172
+ const session_id = readHostSessionId(context);
173
+ if (session_id === null)
174
+ return null;
175
+ return { session_id, cwd: readHostCwd(context) };
176
+ }
177
+ function notify(context, message) {
178
+ if (typeof context !== 'object' || context === null)
179
+ return;
180
+ if ('ui' in context &&
181
+ typeof context.ui === 'object' &&
182
+ context.ui !== null &&
183
+ 'notify' in context.ui &&
184
+ typeof context.ui.notify === 'function') {
185
+ context.ui.notify(message, 'info');
186
+ }
187
+ }
188
+ function configPath() {
189
+ return fileURLToPath(new URL('./recovery.json', import.meta.url));
190
+ }
191
+ /**
192
+ * Opt-in extension entry. Loads the sibling `recovery.json`, builds a live-target-verifying Herdr
193
+ * controller for `apply` mode (a no-op controller for `plan` mode, which never issues an effect), and
194
+ * installs startup/settled triggers plus a manual `pappra-recovery` command. Each trigger observes the
195
+ * ACTUAL host session and reconciles through the durable, cause-deduplicated executor. A load or validation
196
+ * failure disables reconciliation and reports it through the status command; it never throws into the
197
+ * loader and never substitutes a hidden fresh Pi process for the visible workflow.
198
+ */
199
+ export default function recoveryExtension(pi) {
200
+ const host = pi;
201
+ const load = readPiRecoveryConfig(configPath());
202
+ if (!load.ok) {
203
+ host.registerCommand('pappra-recovery', {
204
+ description: 'Opt-in recovery reconciliation (disabled: config not loaded).',
205
+ handler: (_args, context) => {
206
+ notify(context, JSON.stringify({
207
+ schema: PI_RECOVERY_STATUS_SCHEMA,
208
+ registered: false,
209
+ reason: `${load.code}`,
210
+ limitations: LIMITATIONS,
211
+ }));
212
+ },
213
+ });
214
+ return;
215
+ }
216
+ const controller = load.config.mode === 'apply'
217
+ ? createHerdrRecoveryController({ env: process.env }, { agent: load.config.target.agent })
218
+ : {
219
+ id: 'recovery-plan-noop',
220
+ perform: async () => ({
221
+ disposition: 'unknown',
222
+ detail: 'plan mode issues no effect',
223
+ observation: 'none',
224
+ }),
225
+ };
226
+ const reconciler = createRecoveryReconciler(load.config, { controller }, load.digest);
227
+ const run = async (trigger, event, context) => {
228
+ const facts = observeHostFacts(event, context);
229
+ const outcome = await reconciler.reconcile(trigger, facts);
230
+ notify(context, JSON.stringify(outcome));
231
+ };
232
+ host.on('session_start', (event, context) => run('session_start', event, context));
233
+ host.on('agent_settled', (event, context) => run('agent_settled', event, context));
234
+ host.registerCommand('pappra-recovery', {
235
+ description: 'Reconcile durable recovery for the configured task (plan or apply per config).',
236
+ handler: (_args, context) => run('manual', null, context),
237
+ });
238
+ }
@@ -0,0 +1,30 @@
1
+ import { type SessionTransitionHost } from '../../app/collab-session-transition.js';
2
+ import { type NativeEventProducer } from '../../hosts/integration/pi-native-events.js';
3
+ import { type RolloverFreezeController } from '../../hosts/integration/pi-rollover-extension.js';
4
+ export declare const PI_SESSION_TRANSITION_EXTENSION_ID = "pappra/pi-session-transition-host/1";
5
+ export declare const PI_SESSION_TRANSITION_LIMITATIONS: readonly string[];
6
+ export interface PiSessionTransitionContext {
7
+ readonly cwd?: unknown;
8
+ readonly sessionManager?: unknown;
9
+ readonly ui?: unknown;
10
+ }
11
+ interface PiSessionTransitionHostState {
12
+ readonly host: SessionTransitionHost;
13
+ readonly controller: RolloverFreezeController;
14
+ readonly producer: NativeEventProducer;
15
+ readonly sessionId: string;
16
+ readonly cwd: string;
17
+ }
18
+ /**
19
+ * Build the opt-in in-process host adapter from one exact Pi command context. The adapter reports
20
+ * native quiescence as unavailable: supported Pi events cannot provide a complete queue/approval/
21
+ * external-writer inventory or authenticated native stop receipt. Its freeze method is retained
22
+ * only as the existing managed-tool barrier and is never promoted to stop proof.
23
+ */
24
+ export declare function createPiSessionTransitionHost(pi: unknown, context: unknown, env?: NodeJS.ProcessEnv): PiSessionTransitionHostState | null;
25
+ /**
26
+ * Explicit Pi extension entry. Loading registers one command; it does not start a successor,
27
+ * mutate settings, query a model, send a prompt or claim that the host has stop-proof capability.
28
+ */
29
+ export default function piSessionTransitionExtension(pi: unknown): void;
30
+ export {};
@@ -0,0 +1,265 @@
1
+ // Pi session-transition adapter: composes the opt-in transition extension above
2
+ // `src/app` and `src/hosts`.
3
+ //
4
+ // The native observation and freeze primitives stay in `src/hosts/integration`;
5
+ // only the orchestration composition and its application imports live here, so
6
+ // the host layer keeps no application dependency.
7
+ import { object as isRecord } from '../../infra/validation.js';
8
+ import path from 'node:path';
9
+ import { loadSessionTransitionRequest, planSessionTransition, applySessionTransition, } from '../../app/collab-session-transition.js';
10
+ import { registerPiNativeEvents, } from '../../hosts/integration/pi-native-events.js';
11
+ import { registerPiRolloverFreeze, } from '../../hosts/integration/pi-rollover-extension.js';
12
+ export const PI_SESSION_TRANSITION_EXTENSION_ID = 'pappra/pi-session-transition-host/1';
13
+ export const PI_SESSION_TRANSITION_LIMITATIONS = Object.freeze([
14
+ 'no_supported_complete_native_message_queue_or_pending_approval_inventory',
15
+ 'pi_native_event_in_flight_tracking_is_incomplete_and_never_proves_writer_stop',
16
+ 'managed_tool_freeze_is_not_native_process_or_external_writer_stop_proof',
17
+ 'herdr_session_metadata_is_not_process_affiliation',
18
+ 'native_pi_session_archive_is_unavailable',
19
+ ]);
20
+ function contextSessionId(context) {
21
+ try {
22
+ if (!isRecord(context) || !isRecord(context['sessionManager']))
23
+ return null;
24
+ const manager = context['sessionManager'];
25
+ const getter = manager['getSessionId'];
26
+ if (typeof getter !== 'function')
27
+ return null;
28
+ const value = getter.call(manager);
29
+ return typeof value === 'string' && value.length > 0 && value.length <= 256
30
+ ? value
31
+ : null;
32
+ }
33
+ catch {
34
+ return null;
35
+ }
36
+ }
37
+ function contextCwd(context) {
38
+ if (!isRecord(context))
39
+ return null;
40
+ const value = context['cwd'];
41
+ return typeof value === 'string' &&
42
+ path.isAbsolute(value) &&
43
+ value.length <= 4096
44
+ ? value
45
+ : null;
46
+ }
47
+ function paneFromEnvironment(env = process.env) {
48
+ const value = env['HERDR_PANE_ID'];
49
+ return typeof value === 'string' && /^[A-Za-z0-9]+:p[A-Za-z0-9]+$/.test(value)
50
+ ? value
51
+ : null;
52
+ }
53
+ function freezeFailure(token, sessionId) {
54
+ return {
55
+ ok: false,
56
+ reason: token.sessionId === sessionId ? 'conflicting_freeze' : 'wrong_session',
57
+ detail: 'The Pi session-transition adapter does not authorize native stop or ownership transfer.',
58
+ };
59
+ }
60
+ /**
61
+ * Build the opt-in in-process host adapter from one exact Pi command context. The adapter reports
62
+ * native quiescence as unavailable: supported Pi events cannot provide a complete queue/approval/
63
+ * external-writer inventory or authenticated native stop receipt. Its freeze method is retained
64
+ * only as the existing managed-tool barrier and is never promoted to stop proof.
65
+ */
66
+ export function createPiSessionTransitionHost(pi, context, env = process.env) {
67
+ const sessionId = contextSessionId(context);
68
+ const cwd = contextCwd(context);
69
+ if (sessionId === null || cwd === null)
70
+ return null;
71
+ const controller = registerPiRolloverFreeze(pi, {
72
+ sessionId,
73
+ });
74
+ const producer = registerPiNativeEvents(pi, {
75
+ sessionId,
76
+ });
77
+ const host = {
78
+ id: PI_SESSION_TRANSITION_EXTENSION_ID,
79
+ async observe() {
80
+ const currentSession = contextSessionId(context);
81
+ const currentCwd = contextCwd(context);
82
+ const status = controller.status();
83
+ const facts = producer.snapshot();
84
+ return {
85
+ session_id: currentSession,
86
+ cwd: currentCwd,
87
+ pane_id: paneFromEnvironment(env),
88
+ proof_support: 'unavailable',
89
+ proof: null,
90
+ freeze_status: status,
91
+ native_facts: facts,
92
+ unavailable_code: 'pi_native_quiescence_proof_unavailable',
93
+ detail: 'Installed Pi events expose only advisory idle/settled and incomplete in-flight observations. Complete queued messages, approvals, external writers and authenticated native stop are unsupported; a managed freeze latch is not quiescence proof.',
94
+ };
95
+ },
96
+ async freeze(token) {
97
+ const currentSession = contextSessionId(context);
98
+ if (currentSession !== sessionId || currentSession !== token.sessionId)
99
+ return freezeFailure(token, currentSession ?? '');
100
+ return controller.freeze(token);
101
+ },
102
+ };
103
+ return { host, controller, producer, sessionId, cwd };
104
+ }
105
+ function tokenizeCommandArgs(input) {
106
+ if (input.length > 8192 || input.includes('\u0000'))
107
+ return null;
108
+ const tokens = [];
109
+ let current = '';
110
+ let quote = null;
111
+ let escaped = false;
112
+ let started = false;
113
+ for (const char of input) {
114
+ if (escaped) {
115
+ current += char;
116
+ escaped = false;
117
+ started = true;
118
+ continue;
119
+ }
120
+ if (char === '\\' && quote !== 'single') {
121
+ escaped = true;
122
+ started = true;
123
+ continue;
124
+ }
125
+ if (quote === null && char === "'") {
126
+ quote = 'single';
127
+ started = true;
128
+ continue;
129
+ }
130
+ if (quote === 'single' && char === "'") {
131
+ quote = null;
132
+ continue;
133
+ }
134
+ if (quote === null && char === '"') {
135
+ quote = 'double';
136
+ started = true;
137
+ continue;
138
+ }
139
+ if (quote === 'double' && char === '"') {
140
+ quote = null;
141
+ continue;
142
+ }
143
+ if (quote === null && /\s/.test(char)) {
144
+ if (started)
145
+ tokens.push(current);
146
+ current = '';
147
+ started = false;
148
+ continue;
149
+ }
150
+ current += char;
151
+ started = true;
152
+ }
153
+ if (escaped || quote !== null)
154
+ return null;
155
+ if (started)
156
+ tokens.push(current);
157
+ return tokens;
158
+ }
159
+ function parseExtensionCommand(input) {
160
+ const tokens = tokenizeCommandArgs(input);
161
+ if (tokens === null)
162
+ return {
163
+ ok: false,
164
+ message: 'Arguments must be balanced and contain no NUL bytes.',
165
+ };
166
+ const action = tokens[0];
167
+ const requestFile = tokens.length === 2
168
+ ? tokens[1]
169
+ : tokens.length === 3 && tokens[1] === '--request'
170
+ ? tokens[2]
171
+ : undefined;
172
+ if ((action !== 'plan' && action !== 'apply') ||
173
+ requestFile === undefined ||
174
+ !path.isAbsolute(requestFile))
175
+ return {
176
+ ok: false,
177
+ message: 'Use /collab-transition <plan|apply> <absolute-request.json> (or --request <absolute-request.json>).',
178
+ };
179
+ return { ok: true, action, requestFile };
180
+ }
181
+ function notify(context, message, level = 'info') {
182
+ if (!isRecord(context) || !isRecord(context['ui']))
183
+ return;
184
+ const ui = context['ui'];
185
+ const method = ui['notify'];
186
+ if (typeof method !== 'function')
187
+ return;
188
+ try {
189
+ method.call(ui, message, level);
190
+ }
191
+ catch {
192
+ // A UI notification is diagnostic only and never changes transition state.
193
+ }
194
+ }
195
+ function summaryLine(report) {
196
+ return [
197
+ `pappra transition ${report.status}${report.code === null ? '' : ` (${report.code})`}: ${report.stage}.`,
198
+ report.next_action,
199
+ ]
200
+ .filter((part) => part !== null)
201
+ .join(' ');
202
+ }
203
+ /**
204
+ * Explicit Pi extension entry. Loading registers one command; it does not start a successor,
205
+ * mutate settings, query a model, send a prompt or claim that the host has stop-proof capability.
206
+ */
207
+ export default function piSessionTransitionExtension(pi) {
208
+ const commandHost = pi;
209
+ let runtime = null;
210
+ let rejectedSessionChange = false;
211
+ commandHost.registerCommand('collab-transition', {
212
+ description: 'Plan/apply one guarded collaboration transition. Native quiescence is blocked unless an accepted proof API exists.',
213
+ handler: async (args, context) => {
214
+ const parsed = parseExtensionCommand(args);
215
+ if (!parsed.ok) {
216
+ notify(context, parsed.message, 'warning');
217
+ return;
218
+ }
219
+ const sessionId = contextSessionId(context);
220
+ const cwd = contextCwd(context);
221
+ if (sessionId === null || cwd === null) {
222
+ notify(context, 'Pi transition requires an exact live session id and absolute cwd.', 'warning');
223
+ return;
224
+ }
225
+ if (runtime === null) {
226
+ try {
227
+ runtime = createPiSessionTransitionHost(pi, context);
228
+ }
229
+ catch {
230
+ notify(context, 'Pi transition host registration failed; reconcile the extension load before retrying.', 'warning');
231
+ return;
232
+ }
233
+ if (runtime === null) {
234
+ notify(context, 'Pi transition host could not bind the current session/cwd.', 'warning');
235
+ return;
236
+ }
237
+ }
238
+ else if (runtime.sessionId !== sessionId || runtime.cwd !== cwd) {
239
+ rejectedSessionChange = true;
240
+ notify(context, 'Pi transition host identity changed; reload in the exact source session before continuing.', 'warning');
241
+ return;
242
+ }
243
+ if (rejectedSessionChange) {
244
+ notify(context, 'Pi transition host remains blocked after a session identity change.', 'warning');
245
+ return;
246
+ }
247
+ const loaded = loadSessionTransitionRequest(parsed.requestFile);
248
+ if (!loaded.ok) {
249
+ notify(context, `${loaded.code}: ${loaded.message}`, 'warning');
250
+ return;
251
+ }
252
+ try {
253
+ const report = parsed.action === 'plan'
254
+ ? await planSessionTransition(loaded.value, { host: runtime.host })
255
+ : await applySessionTransition(loaded.value, {
256
+ host: runtime.host,
257
+ });
258
+ notify(context, summaryLine(report), report.ok ? 'info' : 'warning');
259
+ }
260
+ catch {
261
+ notify(context, 'Transition execution returned an unknown outcome; inspect the task journal and host state before resuming.', 'warning');
262
+ }
263
+ },
264
+ });
265
+ }
@@ -0,0 +1,26 @@
1
+ import { type AutomaticHandoffConfig, type AutomaticHandoffRuntime, type AutomaticHandoffResult } from './collab-auto-handoff.js';
2
+ import type { SessionTransitionDependencies } from './collab-session-transition.js';
3
+ export declare function loadAutomaticHandoffConfig(file: string): AutomaticHandoffConfig;
4
+ /** A native settled event or registered task update advances one guarded transition. */
5
+ export declare function watchAutomaticHandoff(config: AutomaticHandoffConfig, runtime: AutomaticHandoffRuntime & {
6
+ subscribe(listener: (event: unknown) => void): () => void;
7
+ }, dependencies?: SessionTransitionDependencies, onRetirement?: (result: AutomaticHandoffResult) => Promise<void>): {
8
+ refresh: () => Promise<void>;
9
+ completed: Promise<{
10
+ readonly ok: true;
11
+ } | {
12
+ readonly ok: false;
13
+ readonly code: string;
14
+ }>;
15
+ status: () => {
16
+ result: AutomaticHandoffResult | null;
17
+ error: string | null;
18
+ completion: ({
19
+ readonly ok: true;
20
+ } | {
21
+ readonly ok: false;
22
+ readonly code: string;
23
+ }) | null;
24
+ };
25
+ close(): void;
26
+ };