@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,371 @@
1
+ import crypto from 'node:crypto';
2
+ import { captureProcessIdentity, } from '../infra/process-identity.js';
3
+ import fs from 'node:fs';
4
+ import path from 'node:path';
5
+ import { spawnSync } from 'node:child_process';
6
+ import { bindNative, findAttempt } from '../collab/lifecycle.js';
7
+ import { canonicalJson } from '../collab/envelope.js';
8
+ import { readRecord, transact } from '../collab/store.js';
9
+ import { requestManagedPiControl } from '../hosts/pi/managed-session.js';
10
+ import { ManagedPiSdkSessionController } from '../hosts/pi/managed-sdk-session.js';
11
+ import { openTaskStore, assertTaskStoreCurrent } from './collab-task-store.js';
12
+ import { readBoundedFile } from './bounded-file.js';
13
+ import { consumeManagedPiResumeRegistration, } from './managed-pi-resume-admission.js';
14
+ const REGISTRY = 'managed_pi_runtime_registry';
15
+ const object = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
16
+ const hash = (value) => crypto.createHash('sha256').update(canonicalJson(value)).digest('hex');
17
+ function parsePrivateRecord(text, code) {
18
+ try {
19
+ const value = JSON.parse(text);
20
+ if (object(value))
21
+ return value;
22
+ }
23
+ catch {
24
+ /* Private descriptors contain authentication tokens. */
25
+ }
26
+ throw new Error(code);
27
+ }
28
+ function entries(record) {
29
+ const value = record[REGISTRY];
30
+ if (value === undefined)
31
+ return [];
32
+ if (!Array.isArray(value) ||
33
+ value.length > 64 ||
34
+ !value.every((item) => object(item) &&
35
+ item.schema === 'pappra/managed-pi-runtime/1' &&
36
+ typeof item.agent_id === 'string' &&
37
+ typeof item.session_id === 'string' &&
38
+ Number.isSafeInteger(item.pid) &&
39
+ Number(item.pid) > 0 &&
40
+ typeof item.descriptor_file === 'string' &&
41
+ path.isAbsolute(item.descriptor_file) &&
42
+ typeof item.controller_run_id === 'string' &&
43
+ typeof item.input_revision === 'string' &&
44
+ object(item.scope)))
45
+ throw new Error('managed_runtime_registry_invalid');
46
+ return value;
47
+ }
48
+ /** The owned SDK process registers itself before TUI input; no PID comes from configuration. */
49
+ export async function registerManagedPiRuntime(controller, scope, descriptorFile, options = {}) {
50
+ const live = controller.observe();
51
+ const snapshot = controller.snapshot();
52
+ if (!(controller instanceof ManagedPiSdkSessionController) ||
53
+ controller.isDisposed ||
54
+ snapshot.process.pid !== process.pid ||
55
+ snapshot.session.sessionId !== scope.session_id ||
56
+ live.native.sessionId !== scope.session_id ||
57
+ path.resolve(live.cwd) !== path.resolve(scope.cwd) ||
58
+ descriptorFile !== `${snapshot.ingress.journalPath}.control.json`)
59
+ throw new Error('managed_runtime_registration_identity_mismatch');
60
+ const descriptor = readBoundedFile(descriptorFile, 4096);
61
+ const stat = fs.lstatSync(descriptorFile);
62
+ if (!descriptor.ok || (stat.mode & 0o077) !== 0)
63
+ throw new Error('managed_runtime_descriptor_unsafe');
64
+ const decoded = parsePrivateRecord(descriptor.text, 'managed_runtime_descriptor_invalid');
65
+ if (!object(decoded) ||
66
+ decoded.schema !== 'harness-collab/pi-managed-control/1' ||
67
+ decoded.sessionId !== scope.session_id ||
68
+ typeof decoded.runId !== 'string' ||
69
+ !decoded.runId)
70
+ throw new Error('managed_runtime_descriptor_mismatch');
71
+ const opened = await openTaskStore(scope.task_root);
72
+ if (!opened.ok || (await assertTaskStoreCurrent(opened.value)))
73
+ throw new Error('managed_runtime_task_unavailable');
74
+ const attempt = findAttempt(opened.value.record, scope.subtask_id, scope.attempt);
75
+ if (!attempt ||
76
+ attempt.assignee.session_id !== scope.session_id ||
77
+ !attempt.input_revision)
78
+ throw new Error('managed_runtime_assignment_mismatch');
79
+ const entry = {
80
+ schema: 'pappra/managed-pi-runtime/1',
81
+ agent_id: attempt.assignee.agent_id,
82
+ session_id: scope.session_id,
83
+ pid: process.pid,
84
+ process_identity: captureProcessIdentity(),
85
+ descriptor_file: descriptorFile,
86
+ controller_run_id: decoded.runId,
87
+ input_revision: attempt.input_revision,
88
+ scope,
89
+ pane_id: live.native.paneId,
90
+ };
91
+ const saved = transact(scope.task_root, {
92
+ actor: 'managed-pi-runtime',
93
+ purpose: 'register-owned-runtime',
94
+ apply(record) {
95
+ const current = findAttempt(record, scope.subtask_id, scope.attempt);
96
+ if (record.task_id !== scope.task_id ||
97
+ record.coordinator?.owner_epoch !== scope.owner_epoch ||
98
+ !current ||
99
+ current.assignee.agent_id !== entry.agent_id ||
100
+ current.assignee.session_id !== entry.session_id ||
101
+ current.input_revision !== entry.input_revision ||
102
+ current.owner_epoch !== scope.owner_epoch ||
103
+ !['assigned', 'accepted', 'running'].includes(current.state) ||
104
+ !scope.claim_epochs.every((pin) => record.claims.some((claim) => claim.claim_id === pin.claim_id &&
105
+ claim.resource_epoch === pin.resource_epoch &&
106
+ !claim.released_at &&
107
+ claim.subtask_id === scope.subtask_id &&
108
+ claim.attempt === scope.attempt &&
109
+ claim.holder.agent_id === entry.agent_id &&
110
+ claim.holder.session_id === entry.session_id)))
111
+ return { ok: false, reason: 'managed_runtime_registration_stale' };
112
+ const rows = entries(record);
113
+ const old = rows.find((row) => row.session_id === entry.session_id);
114
+ if (old && canonicalJson(old) !== canonicalJson(entry)) {
115
+ if (!options.resumeAuthorization)
116
+ return {
117
+ ok: false,
118
+ reason: 'managed_runtime_identity_already_registered',
119
+ };
120
+ consumeManagedPiResumeRegistration(record, options.resumeAuthorization, old, entry);
121
+ rows[rows.indexOf(old)] = entry;
122
+ }
123
+ else if (options.resumeAuthorization) {
124
+ return { ok: false, reason: 'managed_runtime_resume_source_missing' };
125
+ }
126
+ if (!old) {
127
+ if (rows.length >= 64)
128
+ return { ok: false, reason: 'managed_runtime_registry_limit' };
129
+ rows.push(entry);
130
+ }
131
+ if (current.native.observation === 'confirmed' &&
132
+ (current.native.session_id !== entry.session_id ||
133
+ current.native.runner !== 'pi'))
134
+ return { ok: false, reason: 'managed_runtime_native_binding_conflict' };
135
+ if (options.confirmNative !== false &&
136
+ (current.native.observation !== 'confirmed' ||
137
+ options.resumeAuthorization !== undefined)) {
138
+ const observed = bindNative(record, {
139
+ subtaskId: scope.subtask_id,
140
+ attempt: scope.attempt,
141
+ runner: 'pi',
142
+ sessionId: live.native.sessionId,
143
+ runId: entry.controller_run_id,
144
+ observation: 'confirmed',
145
+ evidenceRef: snapshot.ingress.journalPath,
146
+ observedAt: new Date().toISOString(),
147
+ });
148
+ if (!observed.ok)
149
+ return observed;
150
+ }
151
+ record[REGISTRY] = rows;
152
+ return {
153
+ record,
154
+ op: 'register-managed-runtime',
155
+ summary: { session_id: entry.session_id },
156
+ result: null,
157
+ };
158
+ },
159
+ });
160
+ if (!saved.ok)
161
+ throw new Error(saved.reason);
162
+ }
163
+ const PEER_PID_PROBE = String.raw `import socket, struct, sys
164
+ s=socket.socket(socket.AF_UNIX,socket.SOCK_STREAM)
165
+ s.settimeout(2)
166
+ try:
167
+ s.connect(sys.argv[1])
168
+ if sys.platform == 'darwin':
169
+ print(struct.unpack('i',s.getsockopt(0,2,4))[0])
170
+ elif hasattr(socket,'SO_PEERCRED'):
171
+ print(struct.unpack('3i',s.getsockopt(socket.SOL_SOCKET,socket.SO_PEERCRED,12))[0])
172
+ else:
173
+ sys.exit(2)
174
+ finally:
175
+ s.close()
176
+ `;
177
+ /** Read-only OS witness for the socket owner; it neither reads nor prints an authentication token. */
178
+ export function managedPiSocketPeerPid(socketPath) {
179
+ const result = spawnSync('python3', ['-c', PEER_PID_PROBE, socketPath], {
180
+ encoding: 'utf8',
181
+ timeout: 10_000,
182
+ maxBuffer: 4096,
183
+ shell: false,
184
+ });
185
+ if (result.error || result.status !== 0 || !/^\d+\s*$/.test(result.stdout))
186
+ return null;
187
+ const pid = Number(result.stdout.trim());
188
+ return Number.isSafeInteger(pid) && pid > 0 ? pid : null;
189
+ }
190
+ function privateDirectory(directory) {
191
+ const stat = fs.lstatSync(directory);
192
+ if (!stat.isDirectory() ||
193
+ stat.isSymbolicLink() ||
194
+ fs.realpathSync(directory) !== directory ||
195
+ (stat.mode & 0o077) !== 0 ||
196
+ (typeof process.getuid === 'function' && stat.uid !== process.getuid()))
197
+ throw new Error('managed_stop_directory_unsafe');
198
+ return stat;
199
+ }
200
+ export function managedPiRepairDependencies(request, deps = {}) {
201
+ if (!request.repair_policy)
202
+ return undefined;
203
+ const control = deps.control ?? requestManagedPiControl;
204
+ const peerPid = deps.peerPid ?? managedPiSocketPeerPid;
205
+ return {
206
+ confirm_stopped: async (source) => {
207
+ const opened = await openTaskStore(request.execution.task_root);
208
+ if (!opened.ok)
209
+ return null;
210
+ const task = opened.value;
211
+ const coordinator = task.record.coordinator;
212
+ const attempt = findAttempt(task.record, source.source.assignment_id, source.source.attempt);
213
+ const registered = entries(task.record).find((item) => item.agent_id === source.assignee.agent_id &&
214
+ item.session_id === source.assignee.session_id);
215
+ if (!registered ||
216
+ task.record.task_id !== source.task_id ||
217
+ coordinator?.agent_id !== source.coordinator.agent_id ||
218
+ coordinator.session_id !== source.coordinator.session_id ||
219
+ coordinator.owner_epoch !== source.coordinator.owner_epoch ||
220
+ !attempt ||
221
+ attempt.assignee.agent_id !== source.assignee.agent_id ||
222
+ attempt.assignee.session_id !== source.assignee.session_id ||
223
+ attempt.owner_epoch !== source.coordinator.owner_epoch ||
224
+ attempt.input_revision !== source.source.input_revision ||
225
+ registered.input_revision !== source.source.input_revision ||
226
+ registered.scope.task_root !== task.taskRoot ||
227
+ registered.scope.task_id !== source.task_id ||
228
+ registered.scope.subtask_id !== source.source.assignment_id ||
229
+ registered.scope.attempt !== source.source.attempt ||
230
+ registered.scope.owner_epoch !== source.coordinator.owner_epoch)
231
+ return null;
232
+ // Pin authority rather than task.json's inode: unrelated task commits are safe.
233
+ const authority = (current) => hash({
234
+ task_id: current.task_id,
235
+ task_root: current.task_root,
236
+ domain_id: current.domain_id,
237
+ domain_root: current.domain_root,
238
+ created_at: current.created_at,
239
+ coordinator: current.coordinator,
240
+ attempts: current.attempts
241
+ .filter((row) => row.subtask_id === source.source.assignment_id &&
242
+ row.attempt === source.source.attempt)
243
+ .map(({ updated_at: _updated, transitions: _transitions, ...row }) => row),
244
+ runtimes: entries(current).filter((row) => row.agent_id === source.assignee.agent_id &&
245
+ row.session_id === source.assignee.session_id),
246
+ claims: current.claims.filter((row) => registered.scope.claim_epochs.some((pin) => pin.claim_id === row.claim_id)),
247
+ });
248
+ const expectedAuthority = authority(task.record);
249
+ const key = hash({ source, registered });
250
+ const directory = path.join(task.taskRoot, '.managed-native-stops');
251
+ const file = path.join(directory, `${key}.json`);
252
+ if (fs.lstatSync(directory, { throwIfNoEntry: false }))
253
+ privateDirectory(directory);
254
+ if (fs.lstatSync(file, { throwIfNoEntry: false })) {
255
+ const prior = readBoundedFile(file, 64 * 1024);
256
+ if (!prior.ok)
257
+ throw new Error('managed_stop_receipt_unsafe');
258
+ const value = parsePrivateRecord(prior.text, 'managed_stop_receipt_invalid');
259
+ if (!object(value) ||
260
+ value.key !== key ||
261
+ value.state !== 'confirmed' ||
262
+ !object(value.receipt))
263
+ throw new Error('managed_stop_outcome_unknown');
264
+ const receipt = value.receipt;
265
+ if (receipt.schema !== 'pappra/collab-native-stop-receipt/1' ||
266
+ receipt.task_id !== source.task_id ||
267
+ receipt.subtask_id !== source.source.assignment_id ||
268
+ receipt.attempt !== source.source.attempt ||
269
+ receipt.owner_epoch !== source.coordinator.owner_epoch ||
270
+ receipt.assignee?.session_id !== source.assignee.session_id ||
271
+ receipt.assignee.agent_id !== source.assignee.agent_id ||
272
+ receipt.observation !== 'confirmed' ||
273
+ receipt.evidence_ref !== file)
274
+ throw new Error('managed_stop_receipt_conflict');
275
+ return receipt;
276
+ }
277
+ const descriptor = readBoundedFile(registered.descriptor_file, 4096);
278
+ if (!descriptor.ok)
279
+ return null;
280
+ const decoded = parsePrivateRecord(descriptor.text, 'managed_runtime_descriptor_invalid');
281
+ if (!object(decoded) ||
282
+ decoded.sessionId !== registered.session_id ||
283
+ decoded.runId !== registered.controller_run_id ||
284
+ typeof decoded.socketPath !== 'string')
285
+ return null;
286
+ if (peerPid(decoded.socketPath) !== registered.pid)
287
+ return null;
288
+ const status = await control(registered.descriptor_file, 'snapshot');
289
+ const snapshot = object(status.snapshot) ? status.snapshot : null;
290
+ const automation = object(status.automation) ? status.automation : null;
291
+ const scope = automation && object(automation.execution_scope)
292
+ ? automation.execution_scope
293
+ : null;
294
+ const session = snapshot && object(snapshot.session) ? snapshot.session : null;
295
+ const owner = snapshot && object(snapshot.process) ? snapshot.process : null;
296
+ if (status.ok !== true ||
297
+ snapshot?.schema !== 'harness-collab/pi-managed-sdk-session/1' ||
298
+ session?.sessionId !== registered.session_id ||
299
+ owner?.pid !== registered.pid ||
300
+ !scope ||
301
+ canonicalJson(scope) !== canonicalJson(registered.scope))
302
+ return null;
303
+ if (await assertTaskStoreCurrent(task))
304
+ return null;
305
+ // The live snapshot awaited above is not authority over a later task revision.
306
+ // No async seam follows this fresh semantic check and the stop reservation.
307
+ const latest = readRecord(task.taskRoot);
308
+ if (!latest || authority(latest) !== expectedAuthority)
309
+ return null;
310
+ fs.mkdirSync(directory, { mode: 0o700, recursive: true });
311
+ const pin = privateDirectory(directory);
312
+ const reservation = Buffer.from(`${JSON.stringify({ schema: 'pappra/managed-native-stop-journal/1', key, state: 'reserved' })}\n`);
313
+ const fd = fs.openSync(file, 'wx', 0o600);
314
+ try {
315
+ fs.writeFileSync(fd, reservation);
316
+ fs.fsyncSync(fd);
317
+ }
318
+ finally {
319
+ fs.closeSync(fd);
320
+ }
321
+ const response = await control(registered.descriptor_file, 'stop');
322
+ const exit = object(response.exit) ? response.exit : null;
323
+ const final = exit && object(exit.finalSnapshot) ? exit.finalSnapshot : null;
324
+ const finalSession = final && object(final.session) ? final.session : null;
325
+ const processInfo = exit && object(exit.process) ? exit.process : null;
326
+ if (response.ok !== true ||
327
+ exit?.status !== 'runtime_disposed' ||
328
+ exit.sessionId !== registered.session_id ||
329
+ final?.scopedQuiescent !== true ||
330
+ finalSession?.sessionId !== registered.session_id ||
331
+ processInfo?.exit !== 'not_owned')
332
+ throw new Error('managed_stop_outcome_unknown');
333
+ const receipt = {
334
+ schema: 'pappra/collab-native-stop-receipt/1',
335
+ observation: 'confirmed',
336
+ task_id: source.task_id,
337
+ subtask_id: source.source.assignment_id,
338
+ attempt: source.source.attempt,
339
+ owner_epoch: source.coordinator.owner_epoch,
340
+ assignee: source.assignee,
341
+ evidence_ref: file,
342
+ observed_at: new Date().toISOString(),
343
+ scope: 'pinned_pi_1_4_owned_runtime',
344
+ };
345
+ const current = privateDirectory(directory);
346
+ const reserved = readBoundedFile(file, 64 * 1024);
347
+ if (current.ino !== pin.ino ||
348
+ current.dev !== pin.dev ||
349
+ !reserved.ok ||
350
+ !reserved.bytes.equals(reservation))
351
+ throw new Error('managed_stop_receipt_changed');
352
+ const temporary = path.join(directory, `.stop-${crypto.randomUUID()}.tmp`);
353
+ try {
354
+ const output = fs.openSync(temporary, 'wx', 0o600);
355
+ try {
356
+ fs.writeFileSync(output, `${JSON.stringify({ schema: 'pappra/managed-native-stop-journal/1', key, state: 'confirmed', receipt, native: exit })}\n`);
357
+ fs.fsyncSync(output);
358
+ }
359
+ finally {
360
+ fs.closeSync(output);
361
+ }
362
+ fs.renameSync(temporary, file);
363
+ }
364
+ finally {
365
+ if (fs.existsSync(temporary))
366
+ fs.unlinkSync(temporary);
367
+ }
368
+ return receipt;
369
+ },
370
+ };
371
+ }
@@ -0,0 +1,32 @@
1
+ import type { TaskRecord } from '../collab/types.js';
2
+ import { assertManagedPiSdkResumeAuthorization, type ManagedPiSdkResumeAuthorization } from '../hosts/pi/resume-capability.js';
3
+ import type { ManagedPiExecutionScope } from '../schemas/managed-pi-execution.js';
4
+ import type { ManagedPiRequest } from './managed-pi.js';
5
+ export interface ManagedPiResumeConfig {
6
+ readonly sourceJournalPath: string;
7
+ readonly sourceSessionFile: string;
8
+ readonly sourceRunId: string;
9
+ }
10
+ export { assertManagedPiSdkResumeAuthorization };
11
+ export type { ManagedPiSdkResumeAuthorization };
12
+ export interface ManagedPiResumeRuntimeRegistration {
13
+ readonly schema: 'pappra/managed-pi-runtime/1';
14
+ readonly agent_id: string;
15
+ readonly session_id: string;
16
+ readonly pid: number;
17
+ readonly descriptor_file: string;
18
+ readonly controller_run_id: string;
19
+ readonly input_revision: string;
20
+ readonly scope: ManagedPiExecutionScope;
21
+ readonly pane_id?: string | null;
22
+ }
23
+ export declare function prepareManagedPiResume(request: ManagedPiRequest): Promise<ManagedPiSdkResumeAuthorization>;
24
+ /** Release this process's exact reservation after startup failure or runtime shutdown. */
25
+ export declare function releaseManagedPiResume(value: ManagedPiSdkResumeAuthorization): boolean;
26
+ /** Called only inside the task-store transaction that replaces the exact old registry entry. */
27
+ export declare function consumeManagedPiResumeRegistration(record: TaskRecord, value: ManagedPiSdkResumeAuthorization, old: ManagedPiResumeRuntimeRegistration, next: ManagedPiResumeRuntimeRegistration): void;
28
+ /** Enable ongoing authority checks only after the durable new registry entry exists. */
29
+ export declare function canExecuteManagedPiResume(value: ManagedPiSdkResumeAuthorization, native: {
30
+ readonly sessionId: string;
31
+ readonly cwd: string;
32
+ }): boolean;