@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,14 @@
1
+ import type { PiBootstrapConfig } from '../hosts/integration/bootstrap-config.js';
2
+ import type { ManagedPiSdkSessionController } from '../hosts/pi/managed-sdk-session.js';
3
+ import { type BoundManagedPiExecutionScope } from './managed-pi-transition-host.js';
4
+ import type { ManagedPiExecutionScope } from './collab-session-transition.js';
5
+ /** A receiver is controller-owned at launch, but task ownership binds only after the real transfer. */
6
+ export declare function watchManagedPiBootstrapAdmission(controller: ManagedPiSdkSessionController, config: PiBootstrapConfig, onBound: (binding: BoundManagedPiExecutionScope) => Promise<void>): Promise<{
7
+ refresh: () => Promise<void>;
8
+ status: () => {
9
+ state: "awaiting_idle" | "awaiting_transfer" | "bound" | "unavailable";
10
+ error: string | null;
11
+ scope: ManagedPiExecutionScope | null;
12
+ };
13
+ close(): Promise<void>;
14
+ }>;
@@ -0,0 +1,104 @@
1
+ import fs from 'node:fs';
2
+ import { createLocalTaskRecordReader } from '../hosts/integration/pi-bootstrap-runtime.js';
3
+ import { decideBootstrapWrite } from '../hosts/integration/pi-bootstrap-guard.js';
4
+ import { bindManagedPiExecutionScope, } from './managed-pi-transition-host.js';
5
+ /** A receiver is controller-owned at launch, but task ownership binds only after the real transfer. */
6
+ export async function watchManagedPiBootstrapAdmission(controller, config, onBound) {
7
+ const reader = createLocalTaskRecordReader(config.domainRoot, config.taskId);
8
+ const taskRoot = reader.read().task_root;
9
+ let closed = false;
10
+ let pending = false;
11
+ let active = null;
12
+ let binding = null;
13
+ let state = 'awaiting_transfer';
14
+ let error = null;
15
+ const refresh = () => {
16
+ if (closed || binding)
17
+ return active ?? Promise.resolve();
18
+ pending = true;
19
+ if (active)
20
+ return active;
21
+ active = (async () => {
22
+ try {
23
+ while (pending && !closed && !binding) {
24
+ pending = false;
25
+ const native = controller.observe();
26
+ const record = reader.read();
27
+ if (!decideBootstrapWrite(record, config.guard, native.native.sessionId)
28
+ .allow) {
29
+ state = 'awaiting_transfer';
30
+ continue;
31
+ }
32
+ const inventory = await controller.inventory();
33
+ if (inventory.completeness !== 'complete' ||
34
+ inventory.inflight.length ||
35
+ inventory.pending_approvals.length ||
36
+ inventory.pending_messages?.length !== 0) {
37
+ state = 'awaiting_idle';
38
+ continue;
39
+ }
40
+ const scope = {
41
+ schema: 'pappra/managed-pi-execution-scope/1',
42
+ task_id: config.taskId,
43
+ task_root: taskRoot,
44
+ session_id: native.native.sessionId,
45
+ cwd: native.cwd,
46
+ subtask_id: config.guard.subtaskId,
47
+ attempt: config.guard.attempt,
48
+ owner_epoch: config.guard.coordinatorEpoch,
49
+ claim_epochs: config.guard.claims.map((claim) => ({
50
+ claim_id: claim.claimId,
51
+ resource_epoch: claim.originalResourceEpoch + 1,
52
+ })),
53
+ };
54
+ const candidate = await bindManagedPiExecutionScope({
55
+ controller,
56
+ scope,
57
+ });
58
+ await onBound(candidate);
59
+ binding = candidate;
60
+ state = 'bound';
61
+ error = null;
62
+ }
63
+ }
64
+ catch (cause) {
65
+ state = 'unavailable';
66
+ error =
67
+ cause instanceof Error
68
+ ? cause.message
69
+ : 'managed_bootstrap_admission_unavailable';
70
+ }
71
+ })().finally(() => {
72
+ active = null;
73
+ });
74
+ return active;
75
+ };
76
+ const watcher = fs.watch(taskRoot, (_event, name) => {
77
+ if (name === null || name.toString() === 'task.json')
78
+ void refresh();
79
+ });
80
+ watcher.on('error', () => {
81
+ state = 'unavailable';
82
+ error = 'managed_bootstrap_watch_failed';
83
+ });
84
+ const unsubscribe = controller.subscribe((event) => {
85
+ if (typeof event === 'object' &&
86
+ event !== null &&
87
+ 'type' in event &&
88
+ (event.type === 'agent_settled' || event.type === 'resources_ready'))
89
+ setImmediate(() => {
90
+ void refresh();
91
+ }).unref();
92
+ });
93
+ await refresh();
94
+ return {
95
+ refresh,
96
+ status: () => ({ state, error, scope: binding?.scope ?? null }),
97
+ async close() {
98
+ closed = true;
99
+ watcher.close();
100
+ unsubscribe();
101
+ await active;
102
+ },
103
+ };
104
+ }
@@ -0,0 +1,10 @@
1
+ import type { ManagedPiSdkSessionController } from '../hosts/pi/managed-sdk-session.js';
2
+ import { type ManagedPiReadinessConfig } from './managed-pi-readiness.js';
3
+ /** Refresh native evidence and resolve an unspecified caller from this owned source. */
4
+ export declare function refreshManagedBootstrapAdmission(runtime: ManagedPiSdkSessionController, readiness: ManagedPiReadinessConfig, original: {
5
+ readonly ref: string;
6
+ readonly digest: string;
7
+ }): Promise<{
8
+ readonly ref: string;
9
+ readonly digest: string;
10
+ }>;
@@ -0,0 +1,78 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { canonicalJson } from '../collab/envelope.js';
5
+ import { loadVisibleBootstrapRequest } from './collab-bootstrap.js';
6
+ import { publishManagedPiReadiness, } from './managed-pi-readiness.js';
7
+ import { readBoundedFile } from './bounded-file.js';
8
+ /** Refresh native evidence and resolve an unspecified caller from this owned source. */
9
+ export async function refreshManagedBootstrapAdmission(runtime, readiness, original) {
10
+ const loaded = loadVisibleBootstrapRequest(original.ref);
11
+ if (!loaded.ok || loaded.value.digest !== original.digest)
12
+ throw new Error('bootstrap_refresh_template_changed');
13
+ const request = loaded.value.request;
14
+ if (!request.managed_runtime ||
15
+ request.admission.capability_card_ref !== readiness.cardFile)
16
+ throw new Error('bootstrap_refresh_card_not_authorized');
17
+ const observation = runtime.observe();
18
+ if (observation.cwd !== request.target.cwd ||
19
+ observation.native.modelObservation.provider !== 'openrouter' ||
20
+ typeof observation.native.modelObservation.model !== 'string')
21
+ throw new Error('bootstrap_refresh_native_identity_mismatch');
22
+ runtime.publishResourcesReady(true);
23
+ if (!runtime.metadataFile)
24
+ throw new Error('bootstrap_refresh_source_metadata_missing');
25
+ const status = publishManagedPiReadiness(readiness, {
26
+ sessionId: observation.native.sessionId,
27
+ cwd: observation.cwd,
28
+ metadataFile: runtime.metadataFile,
29
+ expectedProvider: 'openrouter',
30
+ expectedModel: observation.native.modelObservation.model,
31
+ });
32
+ if (status.preflight !== 'ready')
33
+ throw new Error('bootstrap_refresh_not_ready');
34
+ const card = readBoundedFile(readiness.cardFile, 1024 * 1024);
35
+ if (!card.ok)
36
+ throw new Error('bootstrap_refresh_card_unreadable');
37
+ const updated = {
38
+ ...request,
39
+ ...(request.caller.pane_id == null && observation.native.paneId
40
+ ? {
41
+ caller: { ...request.caller, pane_id: observation.native.paneId },
42
+ }
43
+ : {}),
44
+ admission: { ...request.admission, capability_card_digest: card.digest },
45
+ };
46
+ const bytes = `${canonicalJson(updated)}\n`;
47
+ const digest = `sha256:${createHash('sha256').update(bytes).digest('hex')}`;
48
+ const file = `${original.ref}.admitted-${digest.slice(7, 23)}.json`;
49
+ const parent = fs.lstatSync(path.dirname(file));
50
+ if (!parent.isDirectory() ||
51
+ parent.isSymbolicLink() ||
52
+ parent.mode & 0o077 ||
53
+ fs.realpathSync(path.dirname(file)) !== path.dirname(file))
54
+ throw new Error('bootstrap_refresh_parent_not_private');
55
+ if (fs.lstatSync(file, { throwIfNoEntry: false })) {
56
+ const existing = readBoundedFile(file, 64 * 1024);
57
+ if (!existing.ok || existing.digest !== digest)
58
+ throw new Error('bootstrap_refresh_pin_conflict');
59
+ }
60
+ else {
61
+ const fd = fs.openSync(file, 'wx', 0o600);
62
+ try {
63
+ fs.writeFileSync(fd, bytes);
64
+ fs.fsyncSync(fd);
65
+ }
66
+ finally {
67
+ fs.closeSync(fd);
68
+ }
69
+ const directory = fs.openSync(path.dirname(file), 'r');
70
+ try {
71
+ fs.fsyncSync(directory);
72
+ }
73
+ finally {
74
+ fs.closeSync(directory);
75
+ }
76
+ }
77
+ return { ref: file, digest };
78
+ }
@@ -0,0 +1,8 @@
1
+ import type { ManagedPiSdkSessionController } from '../hosts/pi/managed-sdk-session.js';
2
+ type Runtime = Pick<ManagedPiSdkSessionController, 'observe' | 'snapshot' | 'submitInput'>;
3
+ /** Only registered pointers in the runtime's launch-bound namespace become native input. */
4
+ export declare function deliverManagedPiMessage(runtime: Runtime, request: Readonly<Record<string, unknown>>, authorization: {
5
+ readonly taskRoot: string;
6
+ readonly agentId: string;
7
+ }): Promise<Readonly<Record<string, unknown>>>;
8
+ export {};
@@ -0,0 +1,110 @@
1
+ import { createHash } from 'node:crypto';
2
+ import { isTaskRecord } from '../collab/validation.js';
3
+ import { openMessageTask, readRegisteredMessageSafe, assertMessageTaskCurrent, } from './collab-messages.js';
4
+ import { buildNotificationText } from './collab-notify.js';
5
+ import { routeExclusionFor } from './collab-route.js';
6
+ import { readBoundedFile } from './bounded-file.js';
7
+ const same = (a, b) => a?.agent_id === b.agent_id &&
8
+ a.session_id === b.session_id &&
9
+ a.harness === b.harness;
10
+ /** Only registered pointers in the runtime's launch-bound namespace become native input. */
11
+ export async function deliverManagedPiMessage(runtime, request, authorization) {
12
+ const refuse = (reason) => ({ ok: false, reason });
13
+ if (request.task_root !== authorization.taskRoot ||
14
+ typeof request.message_id !== 'string' ||
15
+ typeof request.digest !== 'string' ||
16
+ request.expected_session_id !== runtime.observe().native.sessionId)
17
+ return refuse('delivery_scope_mismatch');
18
+ const opened = await openMessageTask(authorization.taskRoot);
19
+ if (!opened.ok)
20
+ return refuse(opened.code);
21
+ const registered = await readRegisteredMessageSafe(opened.value, request.message_id);
22
+ if (!registered.ok)
23
+ return refuse(registered.code);
24
+ if (registered.value.digest !== request.digest)
25
+ return refuse('delivery_digest_mismatch');
26
+ if (await assertMessageTaskCurrent(opened.value))
27
+ return refuse('delivery_namespace_changed');
28
+ // No async seam follows the last namespace/record read and the native admission.
29
+ const latest = readBoundedFile(opened.value.recordFile, 8 * 1024 * 1024);
30
+ if (!latest.ok)
31
+ return refuse('delivery_namespace_changed');
32
+ let record;
33
+ try {
34
+ record = JSON.parse(latest.text);
35
+ }
36
+ catch {
37
+ return refuse('delivery_record_missing');
38
+ }
39
+ if (!isTaskRecord(record) ||
40
+ record.task_id !== opened.value.record.task_id ||
41
+ record.task_root !== opened.value.taskRoot ||
42
+ record.domain_root !== opened.value.record.domain_root ||
43
+ record.domain_id !== opened.value.record.domain_id ||
44
+ record.created_at !== opened.value.record.created_at)
45
+ return refuse('delivery_record_missing');
46
+ const latestMessage = readBoundedFile(registered.value.file, 1024 * 1024);
47
+ if (!latestMessage.ok || latestMessage.digest !== registered.value.digest)
48
+ return refuse('delivery_digest_mismatch');
49
+ const message = registered.value.message;
50
+ const live = runtime.observe();
51
+ if (message.to.harness !== 'pi' ||
52
+ message.to.agent_id !== authorization.agentId ||
53
+ message.to.session_id !== live.native.sessionId ||
54
+ (message.to.cwd !== undefined && message.to.cwd !== live.cwd) ||
55
+ message.owner_epoch !== record.coordinator?.owner_epoch)
56
+ return refuse('delivery_identity_stale');
57
+ for (const side of [message.from, message.to])
58
+ if (routeExclusionFor(record, side).state !== 'active')
59
+ return refuse('delivery_route_excluded');
60
+ if (message.subtask_id !== null || message.attempt !== null) {
61
+ const attempt = record.attempts.find((row) => row.subtask_id === message.subtask_id &&
62
+ row.attempt === message.attempt);
63
+ if (!attempt ||
64
+ attempt.closed_at ||
65
+ attempt.cancel_requested_at ||
66
+ [
67
+ 'completed',
68
+ 'failed',
69
+ 'cancelled',
70
+ 'canceled',
71
+ 'awaiting_approval',
72
+ 'blocked',
73
+ ].includes(attempt.state) ||
74
+ attempt.awaiting === 'approval' ||
75
+ attempt.owner_epoch !== message.owner_epoch ||
76
+ (message.body.input_revision !== undefined &&
77
+ message.body.input_revision !== attempt.input_revision))
78
+ return refuse('delivery_attempt_inactive');
79
+ if (!same(message.from, record.coordinator) &&
80
+ !same(message.from, attempt.assignee))
81
+ return refuse('delivery_sender_inactive');
82
+ if (record.claims.some((claim) => claim.subtask_id === attempt.subtask_id &&
83
+ claim.attempt === attempt.attempt &&
84
+ !claim.released_at &&
85
+ claim.cancel_pending))
86
+ return refuse('delivery_cancellation_pending');
87
+ }
88
+ else if (!same(message.from, record.coordinator))
89
+ return refuse('delivery_sender_inactive');
90
+ const inventory = runtime.snapshot().ownedRuntime;
91
+ if (inventory.extensionDialogs.completeness !== 'complete' ||
92
+ inventory.extensionDialogs.pending.length ||
93
+ inventory.queues.internal.activeSelector)
94
+ return refuse('delivery_approval_pending');
95
+ if (message.type === 'ASSIGN' && record.dispatch_frozen)
96
+ return refuse('delivery_dispatch_frozen');
97
+ const entry = record.messages.find((row) => row.message_id === message.message_id);
98
+ if (!entry ||
99
+ entry.content_digest !== message.content_digest ||
100
+ !['applied', 'recorded'].includes(entry.state))
101
+ return refuse('delivery_registration_stale');
102
+ const text = buildNotificationText({
103
+ taskId: record.task_id,
104
+ type: message.type,
105
+ messagePath: registered.value.file,
106
+ digest: registered.value.digest,
107
+ });
108
+ const id = `message-${createHash('sha256').update(`${authorization.taskRoot}\0${message.message_id}\0${registered.value.digest}`).digest('hex')}`;
109
+ return { ok: true, admission: runtime.submitInput(id, text) };
110
+ }
@@ -0,0 +1,15 @@
1
+ import type { PiBootstrapConfig } from '../hosts/integration/bootstrap-config.js';
2
+ import type { ManagedPiSdkSessionController } from '../hosts/pi/managed-sdk-session.js';
3
+ /** Import verified continuity into the actual receiver before acknowledging receipt. */
4
+ export declare function prepareManagedPiHandoffReceiver(runtime: ManagedPiSdkSessionController, config: PiBootstrapConfig, referenceFile: string, journalPath: string): Promise<{
5
+ priorSourceRetired(): boolean;
6
+ startWork(): void;
7
+ status: () => {
8
+ context_imported: boolean;
9
+ ack_registered: boolean;
10
+ work_admitted: boolean;
11
+ first_work_observed: boolean;
12
+ error: string | null;
13
+ };
14
+ close: () => void;
15
+ }>;
@@ -0,0 +1,263 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { createHash } from 'node:crypto';
4
+ import { buildMessage, canonicalJson } from '../collab/envelope.js';
5
+ import { submitMessage } from '../collab/messages.js';
6
+ import { readRecord } from '../collab/store.js';
7
+ import { readHandoffBundle, verifyHandoffBundle } from '../continuity/index.js';
8
+ import { continuityTaskPaths, readContinuityBytes, } from '../continuity/paths.js';
9
+ import { decideBootstrapWrite } from '../hosts/integration/pi-bootstrap-guard.js';
10
+ import { readBoundedFile } from './bounded-file.js';
11
+ import { assertTaskStoreCurrent, openTaskStore } from './collab-task-store.js';
12
+ import { routeExclusionFor } from './collab-route.js';
13
+ const object = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
14
+ /** Import verified continuity into the actual receiver before acknowledging receipt. */
15
+ export async function prepareManagedPiHandoffReceiver(runtime, config, referenceFile, journalPath) {
16
+ const reference = readBoundedFile(referenceFile, 64 * 1024);
17
+ if (!reference.ok)
18
+ throw new Error('receiver_context_reference_unreadable');
19
+ const ref = JSON.parse(reference.text);
20
+ if (!object(ref) ||
21
+ ref.schema !== 'pappra/managed-handoff-context/1' ||
22
+ !object(ref.bundle) ||
23
+ typeof ref.bundle.root !== 'string' ||
24
+ typeof ref.bundle.continuity_task_id !== 'string' ||
25
+ typeof ref.bundle.bundle_id !== 'string' ||
26
+ typeof ref.bundle.digest !== 'string' ||
27
+ typeof ref.transition_id !== 'string' ||
28
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(ref.transition_id))
29
+ throw new Error('receiver_context_reference_invalid');
30
+ const taskRoot = path.join(fs.realpathSync(config.domainRoot), 'tasks', config.taskId);
31
+ if (ref.task_root !== taskRoot ||
32
+ ref.intent_id !== config.guard.intentId ||
33
+ ref.handoff_id !== config.guard.handoffId ||
34
+ ref.generation !== config.guard.generation ||
35
+ runtime.observe().native.sessionId !== config.guard.successor.sessionId)
36
+ throw new Error('receiver_context_identity_mismatch');
37
+ const opened = await openTaskStore(taskRoot);
38
+ if (!opened.ok)
39
+ throw new Error(opened.code);
40
+ const intent = opened.value.record.rollover?.find((row) => row.intent_id === config.guard.intentId);
41
+ if (!intent ||
42
+ intent.bundle.digest !== ref.bundle.digest ||
43
+ intent.bundle.ref !== `handoff-bundles/${ref.bundle.bundle_id}.json` ||
44
+ intent.to.session_id !== runtime.observe().native.sessionId ||
45
+ intent.to.agent_id !== config.guard.successor.agentId)
46
+ throw new Error('receiver_context_intent_mismatch');
47
+ const options = {
48
+ root: ref.bundle.root,
49
+ continuityTaskId: ref.bundle.continuity_task_id,
50
+ bundleId: ref.bundle.bundle_id,
51
+ };
52
+ const loaded = await readHandoffBundle(options);
53
+ const verified = await verifyHandoffBundle(options);
54
+ if (!loaded.ok ||
55
+ loaded.value.digest !== ref.bundle.digest ||
56
+ !verified.ok ||
57
+ verified.value.contextIntegrity === 'unknown' ||
58
+ verified.value.artifactChecks.some((row) => row.status !== 'unchanged'))
59
+ throw new Error('receiver_context_integrity_unverified');
60
+ const bundle = loaded.value.bundle;
61
+ if (bundle.collaboration.taskId !== config.taskId ||
62
+ bundle.collaboration.subtaskId !== config.guard.subtaskId ||
63
+ bundle.collaboration.attempt !== config.guard.attempt ||
64
+ bundle.collaboration.inputRevision !== config.guard.inputRevision ||
65
+ bundle.collaboration.ownerEpoch !== config.guard.coordinatorEpoch ||
66
+ bundle.sourceNativeSession.sessionId !== intent.from.session_id)
67
+ throw new Error('receiver_context_bundle_mismatch');
68
+ const checkpoint = await readContinuityBytes(options.root, options.continuityTaskId, path.join(continuityTaskPaths(options.root, options.continuityTaskId).taskDir, bundle.checkpoint.ref));
69
+ if (!checkpoint.ok ||
70
+ `sha256:${createHash('sha256').update(checkpoint.value).digest('hex')}` !==
71
+ bundle.checkpoint.digest)
72
+ throw new Error('receiver_checkpoint_changed');
73
+ if (await assertTaskStoreCurrent(opened.value))
74
+ throw new Error('receiver_task_namespace_changed');
75
+ const receiverAuthority = (reason) => {
76
+ const current = readRecord(taskRoot);
77
+ const currentIntent = current?.rollover?.find((row) => row.intent_id === intent.intent_id);
78
+ const attempt = current?.attempts.find((row) => row.subtask_id === config.guard.subtaskId &&
79
+ row.attempt === config.guard.attempt);
80
+ if (!current ||
81
+ !currentIntent ||
82
+ canonicalJson(currentIntent) !== canonicalJson(intent) ||
83
+ !attempt ||
84
+ attempt.cancel_requested_at ||
85
+ attempt.awaiting === 'approval' ||
86
+ current.coordinator?.owner_epoch !== config.guard.coordinatorEpoch ||
87
+ current.coordinator?.agent_id !==
88
+ opened.value.record.coordinator?.agent_id ||
89
+ current.coordinator?.session_id !==
90
+ opened.value.record.coordinator?.session_id)
91
+ throw new Error(reason);
92
+ return { current, attempt };
93
+ };
94
+ receiverAuthority('receiver_authority_changed_before_import');
95
+ const receipt = `${journalPath}.receiver-reservation.json`;
96
+ const fd = fs.openSync(receipt, 'wx', 0o600);
97
+ const receiptIdentity = fs.fstatSync(fd);
98
+ try {
99
+ fs.writeFileSync(fd, `${canonicalJson({
100
+ schema: 'pappra/managed-receiver-reservation/1',
101
+ session_id: runtime.observe().native.sessionId,
102
+ context_digest: reference.digest,
103
+ stage: 'import_reserved',
104
+ })}\n`);
105
+ fs.fsyncSync(fd);
106
+ }
107
+ finally {
108
+ fs.closeSync(fd);
109
+ }
110
+ try {
111
+ receiverAuthority('receiver_authority_changed_before_import');
112
+ }
113
+ catch (error) {
114
+ try {
115
+ const current = fs.lstatSync(receipt, { throwIfNoEntry: false });
116
+ if (current?.isFile() &&
117
+ current.dev === receiptIdentity.dev &&
118
+ current.ino === receiptIdentity.ino)
119
+ fs.unlinkSync(receipt);
120
+ }
121
+ catch {
122
+ /* Preserve the authority refusal; do not adopt a changed receipt. */
123
+ }
124
+ throw error;
125
+ }
126
+ await runtime.importHandoffContext(`Verified handoff context. This is advisory; task ownership is granted only by the authoritative transfer.\n${checkpoint.value.toString('utf8')}\nNext action: ${bundle.handoff.nextAction}\nBundle: ${loaded.value.path}\nIntegrity: ${verified.value.contextIntegrity}`);
127
+ const { current, attempt } = receiverAuthority('receiver_authority_changed_before_ack');
128
+ const prefix = `receiver-${createHash('sha256').update(`${intent.intent_id}:${intent.to.session_id}`).digest('hex').slice(0, 32)}`;
129
+ const ack = submitMessage(taskRoot, buildMessage({
130
+ message_id: `${prefix}-ack`,
131
+ type: 'ACK',
132
+ task_id: config.taskId,
133
+ from: intent.to,
134
+ to: current.coordinator,
135
+ reply_to: attempt.assignment_message_id,
136
+ subtask_id: config.guard.subtaskId,
137
+ attempt: config.guard.attempt,
138
+ owner_epoch: config.guard.coordinatorEpoch,
139
+ body: {
140
+ phase: 'handoff-context-imported',
141
+ handoff_id: intent.handoff_id,
142
+ rollover_intent_id: intent.intent_id,
143
+ rollover_generation: intent.generation,
144
+ input_revision: intent.input_revision,
145
+ context_digest: reference.digest,
146
+ },
147
+ }));
148
+ if (!ack.ok)
149
+ throw new Error('receiver_ack_not_admitted');
150
+ let started = false;
151
+ let observedEnd = null;
152
+ let proof = false;
153
+ let error = null;
154
+ const unsubscribe = runtime.subscribe((event) => {
155
+ if (!started || proof || !object(event))
156
+ return;
157
+ if (event.type === 'agent_end')
158
+ observedEnd = event;
159
+ if (event.type !== 'agent_settled' ||
160
+ event.aborted !== false ||
161
+ !observedEnd ||
162
+ !Array.isArray(observedEnd.messages))
163
+ return;
164
+ const assistant = [...observedEnd.messages]
165
+ .reverse()
166
+ .find((row) => object(row) && row.role === 'assistant');
167
+ if (!object(assistant) ||
168
+ assistant.stopReason !== 'stop' ||
169
+ !Array.isArray(assistant.content) ||
170
+ !assistant.content.some((row) => object(row) &&
171
+ row.type === 'text' &&
172
+ typeof row.text === 'string' &&
173
+ row.text.trim()))
174
+ return;
175
+ try {
176
+ const record = readRecord(taskRoot);
177
+ if (!record ||
178
+ !decideBootstrapWrite(record, config.guard, runtime.observe().native.sessionId).allow)
179
+ throw new Error('receiver_first_work_authority_changed');
180
+ const report = submitMessage(taskRoot, buildMessage({
181
+ message_id: `${prefix}-first-work`,
182
+ type: 'REPORT',
183
+ task_id: config.taskId,
184
+ from: intent.to,
185
+ to: record.coordinator,
186
+ subtask_id: intent.subtask_id,
187
+ attempt: intent.attempt,
188
+ owner_epoch: intent.coordinator_epoch,
189
+ body: {
190
+ status: 'running',
191
+ phase: 'handoff-first-work',
192
+ rollover_intent_id: intent.intent_id,
193
+ input_revision: intent.input_revision,
194
+ handoff_id: intent.handoff_id,
195
+ rollover_generation: intent.generation,
196
+ native_ref: {
197
+ schema: 'pappra/native-first-work/1',
198
+ handoff_id: intent.handoff_id,
199
+ generation: intent.generation,
200
+ session_id: intent.to.session_id,
201
+ observation: 'native_agent_settled',
202
+ evidence_ref: journalPath,
203
+ },
204
+ },
205
+ }));
206
+ if (!report.ok)
207
+ throw new Error('receiver_first_work_not_admitted');
208
+ proof = true;
209
+ }
210
+ catch {
211
+ error = 'receiver_first_work_unverified';
212
+ }
213
+ });
214
+ return {
215
+ priorSourceRetired() {
216
+ const directory = path.join(continuityTaskPaths(options.root, options.continuityTaskId).taskDir, 'retired-sessions');
217
+ const file = path.join(directory, `${ref.transition_id}.receipt.json`);
218
+ const bytes = readBoundedFile(file, 16 * 1024);
219
+ if (!bytes.ok)
220
+ return false;
221
+ try {
222
+ const receipt = JSON.parse(bytes.text);
223
+ if (!object(receipt) ||
224
+ receipt.schema !== 'pappra/managed-pi-retirement/1' ||
225
+ receipt.transition_id !== ref.transition_id ||
226
+ receipt.source_session_id !== intent.from.session_id ||
227
+ receipt.successor_session_id !== intent.to.session_id ||
228
+ receipt.status !== 'runtime_disposed_and_transcript_retained' ||
229
+ !object(receipt.stop) ||
230
+ receipt.stop.status !== 'runtime_disposed' ||
231
+ !object(receipt.transcript))
232
+ return false;
233
+ const archived = readBoundedFile(path.join(directory, `${ref.transition_id}.jsonl`), 64 * 1024 * 1024);
234
+ const record = readRecord(taskRoot);
235
+ return (archived.ok &&
236
+ archived.digest === receipt.transcript.digest &&
237
+ record !== null &&
238
+ routeExclusionFor(record, intent.from).state === 'excluded');
239
+ }
240
+ catch {
241
+ return false;
242
+ }
243
+ },
244
+ startWork() {
245
+ if (started)
246
+ return;
247
+ const record = readRecord(taskRoot);
248
+ if (!record ||
249
+ !decideBootstrapWrite(record, config.guard, runtime.observe().native.sessionId).allow)
250
+ throw new Error('receiver_work_before_transfer');
251
+ started = true;
252
+ runtime.submitInput(`${prefix}-resume`, `Continue the verified handoff after the completed task ownership transfer. ${bundle.handoff.nextAction}\nKeep protocol task completion separate from this turn. Read the imported checkpoint and use only your claimed resource scope.`);
253
+ },
254
+ status: () => ({
255
+ context_imported: true,
256
+ ack_registered: true,
257
+ work_admitted: started,
258
+ first_work_observed: proof,
259
+ error,
260
+ }),
261
+ close: unsubscribe,
262
+ };
263
+ }
@@ -0,0 +1,3 @@
1
+ import type { SessionTransitionRequest } from './collab-session-transition.js';
2
+ /** Publish captured context only at the destination explicitly approved by the launch request. */
3
+ export declare function prepareManagedHandoffContextReference(request: SessionTransitionRequest): void;