@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,191 @@
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import { readBoundedFile } from './bounded-file.js';
4
+ import { openTaskStore, assertTaskStoreCurrent } from './collab-task-store.js';
5
+ import { requestManagedPiControl } from '../hosts/pi/managed-session.js';
6
+ import { managedPiSocketPeerPid } from './managed-pi-repair-stop.js';
7
+ const object = (value) => typeof value === 'object' && value !== null && !Array.isArray(value);
8
+ /** Fresh authenticated SDK facts plus OS/pane ownership; never infer native identity from a title. */
9
+ export async function observeOwnedManagedPi(descriptorFile, expected, deps) {
10
+ try {
11
+ const stat = fs.lstatSync(descriptorFile);
12
+ const bytes = readBoundedFile(descriptorFile, 4096);
13
+ if (!bytes.ok || (stat.mode & 0o077) !== 0 || stat.isSymbolicLink())
14
+ return null;
15
+ const descriptor = JSON.parse(bytes.text);
16
+ if (!object(descriptor) ||
17
+ descriptor.sessionId !== expected.sessionId ||
18
+ typeof descriptor.socketPath !== 'string' ||
19
+ typeof descriptor.runId !== 'string' ||
20
+ (expected.runId !== undefined && descriptor.runId !== expected.runId))
21
+ return null;
22
+ const peer = (deps.peerPid ?? managedPiSocketPeerPid)(descriptor.socketPath);
23
+ if (peer === null || (expected.pid !== undefined && peer !== expected.pid))
24
+ return null;
25
+ const response = await (deps.control ?? requestManagedPiControl)(descriptorFile, 'snapshot');
26
+ if (response.ok !== true ||
27
+ !object(response.snapshot) ||
28
+ !object(response.snapshot.session) ||
29
+ !object(response.snapshot.process) ||
30
+ !object(response.automation) ||
31
+ !object(response.automation.launch))
32
+ return null;
33
+ const launch = response.automation.launch;
34
+ const scope = response.automation.execution_scope;
35
+ if (expected.taskRoot &&
36
+ !(object(scope) &&
37
+ scope.task_root === expected.taskRoot &&
38
+ scope.session_id === expected.sessionId) &&
39
+ !(launch.bootstrap_task_root === expected.taskRoot &&
40
+ expected.bootstrapDigest !== undefined &&
41
+ launch.bootstrap_config_digest === expected.bootstrapDigest) &&
42
+ !(launch.initial_task_root === expected.taskRoot &&
43
+ expected.initialAdmissionDigest !== undefined &&
44
+ launch.initial_admission_digest === expected.initialAdmissionDigest))
45
+ return null;
46
+ if (launch.ready !== true ||
47
+ launch.runtime !== 'sdk' ||
48
+ launch.session_id !== expected.sessionId ||
49
+ response.snapshot.session.sessionId !== expected.sessionId ||
50
+ response.snapshot.process.pid !== peer ||
51
+ launch.controller_run_id !== descriptor.runId ||
52
+ launch.cwd !== expected.cwd ||
53
+ launch.herdr_pane_id !== expected.paneId ||
54
+ typeof launch.herdr_agent_name !== 'string' ||
55
+ (expected.name !== undefined &&
56
+ launch.herdr_agent_name !== expected.name) ||
57
+ !object(launch.model) ||
58
+ launch.model.provider !== 'openrouter' ||
59
+ typeof launch.model.id !== 'string')
60
+ return null;
61
+ const observed = await deps.run('herdr', ['pane', 'process-info', '--pane', expected.paneId], 5000);
62
+ if (!observed.spawned || observed.code !== 0 || observed.timedOut)
63
+ return null;
64
+ const parsed = JSON.parse(observed.stdout);
65
+ const info = object(parsed) && object(parsed.result)
66
+ ? parsed.result.process_info
67
+ : null;
68
+ if (!object(info) ||
69
+ info.pane_id !== expected.paneId ||
70
+ !Array.isArray(info.foreground_processes) ||
71
+ !info.foreground_processes.some((row) => object(row) && row.pid === peer))
72
+ return null;
73
+ const current = readBoundedFile(descriptorFile, 4096);
74
+ if (!current.ok || current.digest !== bytes.digest)
75
+ return null;
76
+ return {
77
+ descriptorFile,
78
+ sessionId: expected.sessionId,
79
+ cwd: expected.cwd,
80
+ paneId: expected.paneId,
81
+ name: launch.herdr_agent_name,
82
+ pid: peer,
83
+ provider: 'openrouter',
84
+ model: launch.model.id,
85
+ provenance: 'owned-pi-sdk-control',
86
+ };
87
+ }
88
+ catch {
89
+ return null;
90
+ }
91
+ }
92
+ /** Resolve only task-registered runtimes or this task's reserved managed launch. */
93
+ export async function resolveTaskManagedPi(taskRoot, pane, deps) {
94
+ if (!pane.paneId || !pane.cwd)
95
+ return null;
96
+ const opened = await openTaskStore(taskRoot);
97
+ if (!opened.ok || (await assertTaskStoreCurrent(opened.value)))
98
+ return null;
99
+ const candidates = [];
100
+ const initialLaunches = opened.value.record.managed_pi_initial_launches;
101
+ if (Array.isArray(initialLaunches) && initialLaunches.length <= 64) {
102
+ for (const row of initialLaunches) {
103
+ if (!object(row) ||
104
+ row.schema !== 'pappra/managed-pi-initial-launch/1' ||
105
+ row.pane_id !== pane.paneId ||
106
+ typeof row.descriptor_file !== 'string' ||
107
+ typeof row.session_id !== 'string' ||
108
+ typeof row.pid !== 'number' ||
109
+ typeof row.controller_run_id !== 'string' ||
110
+ typeof row.admission_digest !== 'string')
111
+ continue;
112
+ candidates.push({
113
+ file: row.descriptor_file,
114
+ sessionId: row.session_id,
115
+ pid: row.pid,
116
+ runId: row.controller_run_id,
117
+ initialAdmissionDigest: row.admission_digest,
118
+ });
119
+ }
120
+ }
121
+ const registry = opened.value.record.managed_pi_runtime_registry;
122
+ if (Array.isArray(registry) && registry.length <= 64) {
123
+ for (const row of registry) {
124
+ if (!object(row) ||
125
+ (row.pane_id != null && row.pane_id !== pane.paneId) ||
126
+ typeof row.descriptor_file !== 'string' ||
127
+ typeof row.session_id !== 'string' ||
128
+ typeof row.pid !== 'number' ||
129
+ typeof row.controller_run_id !== 'string')
130
+ continue;
131
+ candidates.push({
132
+ file: row.descriptor_file,
133
+ sessionId: row.session_id,
134
+ pid: row.pid,
135
+ runId: row.controller_run_id,
136
+ });
137
+ }
138
+ }
139
+ for (const row of opened.value.record.launch_reservations ?? []) {
140
+ const bootstrap = row
141
+ .bootstrap;
142
+ if (!object(bootstrap) ||
143
+ typeof bootstrap.request_file !== 'string' ||
144
+ typeof bootstrap.request_digest !== 'string')
145
+ continue;
146
+ const requestBytes = readBoundedFile(bootstrap.request_file, 64 * 1024);
147
+ if (!requestBytes.ok || requestBytes.digest !== bootstrap.request_digest)
148
+ continue;
149
+ let request;
150
+ try {
151
+ request = JSON.parse(requestBytes.text);
152
+ }
153
+ catch {
154
+ continue;
155
+ }
156
+ if (!object(request) ||
157
+ request.task_root !== taskRoot ||
158
+ !object(request.managed_runtime) ||
159
+ !object(request.participant) ||
160
+ typeof request.participant.native_session_selector !== 'string' ||
161
+ typeof request.managed_runtime.journal_path !== 'string' ||
162
+ !object(request.bootstrap) ||
163
+ typeof request.bootstrap.config_digest !== 'string' ||
164
+ (pane.name !== undefined &&
165
+ pane.name !== null &&
166
+ bootstrap.herdr_agent !== pane.name))
167
+ continue;
168
+ candidates.push({
169
+ file: `${request.managed_runtime.journal_path}.control.json`,
170
+ sessionId: request.participant.native_session_selector,
171
+ bootstrapDigest: request.bootstrap.config_digest,
172
+ });
173
+ }
174
+ const found = new Map();
175
+ for (const candidate of candidates) {
176
+ if (!path.isAbsolute(candidate.file))
177
+ continue;
178
+ const observed = await observeOwnedManagedPi(candidate.file, {
179
+ ...candidate,
180
+ cwd: pane.cwd,
181
+ paneId: pane.paneId,
182
+ taskRoot,
183
+ ...(pane.name ? { name: pane.name } : {}),
184
+ }, deps);
185
+ if (observed)
186
+ found.set(observed.sessionId, observed);
187
+ }
188
+ if (found.size !== 1 || (await assertTaskStoreCurrent(opened.value)))
189
+ return null;
190
+ return [...found.values()][0] ?? null;
191
+ }
@@ -0,0 +1,29 @@
1
+ export interface ManagedPiReadinessConfig {
2
+ readonly assignmentFile: string;
3
+ readonly templateFile: string;
4
+ readonly cardFile: string;
5
+ }
6
+ export interface ManagedPiReadinessSource {
7
+ readonly sessionId: string;
8
+ readonly cwd: string;
9
+ readonly metadataFile: string;
10
+ readonly expectedProvider?: string;
11
+ readonly expectedModel?: string;
12
+ }
13
+ export interface ManagedPiReadinessDependencies {
14
+ readonly beforeRefresh?: () => Promise<void>;
15
+ }
16
+ export interface ManagedPiReadinessResult {
17
+ readonly status: 'waiting' | 'published' | 'unchanged' | 'blocked';
18
+ readonly code: string;
19
+ readonly cardFile: string;
20
+ readonly preflight: string | null;
21
+ }
22
+ /** Publish startup capabilities only from a matching native resources_ready observation. */
23
+ export declare function publishManagedPiReadiness(config: ManagedPiReadinessConfig, source: ManagedPiReadinessSource): ManagedPiReadinessResult;
24
+ /** Watch only explicit native/config inputs. No timer, model prompt or completion polling. */
25
+ export declare function watchManagedPiReadiness(config: ManagedPiReadinessConfig, source: ManagedPiReadinessSource, onResult?: (result: ManagedPiReadinessResult) => void, dependencies?: ManagedPiReadinessDependencies): {
26
+ refresh: (force?: boolean) => Promise<void>;
27
+ status: () => ManagedPiReadinessResult | null;
28
+ close: () => Promise<void>;
29
+ };
@@ -0,0 +1,288 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { derivePiStartupCard } from './capability-evidence/pi.js';
5
+ import { readBoundedFile } from './bounded-file.js';
6
+ import { runCollaborationPreflight } from './collab-preflight.js';
7
+ import { isAssignment, isCard } from '../collab/contracts.js';
8
+ import { samePath } from './capability-evidence/shared.js';
9
+ function pinDirectory(directory) {
10
+ const stat = fs.lstatSync(directory);
11
+ if (!stat.isDirectory() ||
12
+ stat.isSymbolicLink() ||
13
+ fs.realpathSync(directory) !== directory)
14
+ throw new Error('readiness_directory_redirected');
15
+ return { dev: stat.dev, ino: stat.ino };
16
+ }
17
+ /** Publish startup capabilities only from a matching native resources_ready observation. */
18
+ export function publishManagedPiReadiness(config, source) {
19
+ const result = (status, code, preflight = null) => ({
20
+ status,
21
+ code,
22
+ cardFile: config.cardFile,
23
+ preflight,
24
+ });
25
+ let temporary = null;
26
+ try {
27
+ const files = [
28
+ config.assignmentFile,
29
+ config.templateFile,
30
+ config.cardFile,
31
+ source.metadataFile,
32
+ ];
33
+ if (files.some((file) => !path.isAbsolute(file)))
34
+ return result('blocked', 'readiness_path_not_absolute');
35
+ if (!source.sessionId || !path.isAbsolute(source.cwd))
36
+ return result('waiting', 'readiness_source_identity_missing');
37
+ if ([config.assignmentFile, config.templateFile, source.metadataFile].some((file) => path.resolve(file) === path.resolve(config.cardFile)))
38
+ return result('blocked', 'readiness_input_output_conflict');
39
+ const directory = path.dirname(config.cardFile);
40
+ const parent = pinDirectory(directory);
41
+ const assignmentRead = readBoundedFile(config.assignmentFile, 1024 * 1024);
42
+ if (!assignmentRead.ok)
43
+ return result(assignmentRead.code === 'unreadable' ? 'waiting' : 'blocked', `readiness_assignment_${assignmentRead.code}`);
44
+ const templateRead = readBoundedFile(config.templateFile, 1024 * 1024);
45
+ if (!templateRead.ok)
46
+ return result(templateRead.code === 'unreadable' ? 'waiting' : 'blocked', `readiness_template_${templateRead.code}`);
47
+ let assignment;
48
+ let template;
49
+ try {
50
+ assignment = JSON.parse(assignmentRead.text);
51
+ template = JSON.parse(templateRead.text);
52
+ }
53
+ catch {
54
+ return result('waiting', 'readiness_configuration_invalid');
55
+ }
56
+ if (!isAssignment(assignment) || !isCard(template))
57
+ return result('waiting', 'readiness_configuration_invalid');
58
+ const derived = derivePiStartupCard({
59
+ assignment,
60
+ template,
61
+ metadataFile: source.metadataFile,
62
+ sessionId: source.sessionId,
63
+ cwd: source.cwd,
64
+ ...(source.expectedProvider === undefined
65
+ ? {}
66
+ : { expectedProvider: source.expectedProvider }),
67
+ ...(source.expectedModel === undefined
68
+ ? {}
69
+ : { expectedModel: source.expectedModel }),
70
+ });
71
+ if (derived.status !== 'derived')
72
+ return result('waiting', derived.blockers[0] ?? 'native_card_unavailable');
73
+ if (derived.card.session_id !== source.sessionId ||
74
+ !samePath(derived.card.cwd, source.cwd))
75
+ return result('waiting', 'readiness_source_identity_mismatch');
76
+ const bytes = Buffer.from(`${JSON.stringify(derived.card, null, 2)}\n`);
77
+ const existing = fs.lstatSync(config.cardFile, { throwIfNoEntry: false });
78
+ if (existing) {
79
+ const prior = readBoundedFile(config.cardFile, 1024 * 1024);
80
+ if (!prior.ok)
81
+ return result('blocked', 'readiness_card_target_unsafe');
82
+ const card = JSON.parse(prior.text);
83
+ if (!isCard(card) ||
84
+ card.session_id !== source.sessionId ||
85
+ !samePath(card.cwd, source.cwd))
86
+ return result('blocked', 'readiness_card_target_foreign');
87
+ if (prior.bytes.equals(bytes)) {
88
+ const preflight = runCollaborationPreflight({
89
+ assignmentFile: config.assignmentFile,
90
+ capabilitiesFile: config.cardFile,
91
+ });
92
+ return result('unchanged', 'native_card_unchanged', preflight.status);
93
+ }
94
+ }
95
+ const current = pinDirectory(directory);
96
+ if (current.dev !== parent.dev || current.ino !== parent.ino)
97
+ return result('blocked', 'readiness_directory_changed');
98
+ temporary = path.join(directory, `.pappra-readiness-${crypto.randomUUID()}.tmp`);
99
+ const fd = fs.openSync(temporary, 'wx', 0o600);
100
+ try {
101
+ fs.writeFileSync(fd, bytes);
102
+ fs.fsyncSync(fd);
103
+ }
104
+ finally {
105
+ fs.closeSync(fd);
106
+ }
107
+ const beforePublish = pinDirectory(directory);
108
+ if (beforePublish.dev !== parent.dev || beforePublish.ino !== parent.ino)
109
+ return result('blocked', 'readiness_directory_changed');
110
+ fs.renameSync(temporary, config.cardFile);
111
+ temporary = null;
112
+ const preflight = runCollaborationPreflight({
113
+ assignmentFile: config.assignmentFile,
114
+ capabilitiesFile: config.cardFile,
115
+ });
116
+ return result('published', 'native_card_published', preflight.status);
117
+ }
118
+ catch {
119
+ return result('blocked', 'readiness_publication_failed');
120
+ }
121
+ finally {
122
+ if (temporary !== null) {
123
+ try {
124
+ fs.unlinkSync(temporary);
125
+ }
126
+ catch {
127
+ /* only this call's temporary file */
128
+ }
129
+ }
130
+ }
131
+ }
132
+ /** Watch only explicit native/config inputs. No timer, model prompt or completion polling. */
133
+ export function watchManagedPiReadiness(config, source, onResult = () => { }, dependencies = {}) {
134
+ const inputs = [
135
+ source.metadataFile,
136
+ config.assignmentFile,
137
+ config.templateFile,
138
+ ];
139
+ const directories = new Map();
140
+ const pins = new Map();
141
+ for (const file of inputs) {
142
+ if (!path.isAbsolute(file))
143
+ throw new Error('readiness_path_not_absolute');
144
+ const directory = path.dirname(file);
145
+ pins.set(directory, pinDirectory(directory));
146
+ const names = directories.get(directory) ?? new Set();
147
+ names.add(path.basename(file));
148
+ directories.set(directory, names);
149
+ }
150
+ let last = null;
151
+ let lastCause = null;
152
+ let closed = false;
153
+ let pending = false;
154
+ let forcePending = false;
155
+ let active = null;
156
+ const watchers = [];
157
+ const notify = (result) => {
158
+ try {
159
+ onResult(result);
160
+ }
161
+ catch {
162
+ /* Observers do not interrupt native lifecycle handling. */
163
+ }
164
+ };
165
+ const inputCause = () => {
166
+ const hash = crypto.createHash('sha256');
167
+ for (const file of inputs) {
168
+ const read = readBoundedFile(file, file === source.metadataFile ? 16 * 1024 * 1024 : 1024 * 1024);
169
+ hash.update(read.ok ? read.digest : `error:${read.code}`);
170
+ hash.update('\0');
171
+ }
172
+ return hash.digest('hex');
173
+ };
174
+ const directoriesCurrent = () => {
175
+ for (const [directory, pin] of pins) {
176
+ try {
177
+ const current = pinDirectory(directory);
178
+ if (current.dev !== pin.dev || current.ino !== pin.ino)
179
+ return false;
180
+ }
181
+ catch {
182
+ return false;
183
+ }
184
+ }
185
+ return true;
186
+ };
187
+ const refresh = (force = false) => {
188
+ if (closed)
189
+ return active ?? Promise.resolve();
190
+ pending = true;
191
+ forcePending ||= force;
192
+ if (active)
193
+ return active;
194
+ active = (async () => {
195
+ while (pending && !closed) {
196
+ pending = false;
197
+ const forced = forcePending;
198
+ forcePending = false;
199
+ if (!directoriesCurrent()) {
200
+ last = {
201
+ status: 'blocked',
202
+ code: 'readiness_directory_changed',
203
+ cardFile: config.cardFile,
204
+ preflight: null,
205
+ };
206
+ notify(last);
207
+ continue;
208
+ }
209
+ const beforeRefreshCause = inputCause();
210
+ if (!forced && beforeRefreshCause === lastCause)
211
+ continue;
212
+ try {
213
+ await dependencies.beforeRefresh?.();
214
+ }
215
+ catch {
216
+ last = {
217
+ status: 'waiting',
218
+ code: 'readiness_refresh_dependency_failed',
219
+ cardFile: config.cardFile,
220
+ preflight: null,
221
+ };
222
+ notify(last);
223
+ continue;
224
+ }
225
+ if (closed)
226
+ break;
227
+ if (!directoriesCurrent()) {
228
+ last = {
229
+ status: 'blocked',
230
+ code: 'readiness_directory_changed',
231
+ cardFile: config.cardFile,
232
+ preflight: null,
233
+ };
234
+ notify(last);
235
+ continue;
236
+ }
237
+ const cause = inputCause();
238
+ if (!forced && cause === lastCause)
239
+ continue;
240
+ lastCause = cause;
241
+ last = publishManagedPiReadiness(config, source);
242
+ notify(last);
243
+ }
244
+ })().finally(() => {
245
+ active = null;
246
+ if (pending && !closed)
247
+ void refresh(forcePending);
248
+ });
249
+ return active;
250
+ };
251
+ try {
252
+ for (const [directory, names] of directories) {
253
+ const watcher = fs.watch(directory, (_event, filename) => {
254
+ if (closed)
255
+ return;
256
+ if (filename === null || names.has(filename.toString()))
257
+ void refresh();
258
+ });
259
+ watcher.on('error', () => {
260
+ last = {
261
+ status: 'blocked',
262
+ code: 'readiness_watch_failed',
263
+ cardFile: config.cardFile,
264
+ preflight: null,
265
+ };
266
+ });
267
+ watchers.push(watcher);
268
+ }
269
+ void refresh();
270
+ }
271
+ catch (error) {
272
+ for (const watcher of watchers)
273
+ watcher.close();
274
+ throw error;
275
+ }
276
+ return {
277
+ refresh,
278
+ status: () => last,
279
+ close: async () => {
280
+ if (closed)
281
+ return;
282
+ closed = true;
283
+ for (const watcher of watchers)
284
+ watcher.close();
285
+ await active;
286
+ },
287
+ };
288
+ }
@@ -0,0 +1,21 @@
1
+ import { requestManagedPiControl } from '../hosts/pi/managed-session.js';
2
+ import { ManagedPiSdkSessionController } from '../hosts/pi/managed-sdk-session.js';
3
+ import type { ManagedPiExecutionScope } from './collab-session-transition.js';
4
+ import type { RoleRepairDependencies } from './collab-role-repair.js';
5
+ import { type ManagedPiSdkResumeAuthorization } from './managed-pi-resume-admission.js';
6
+ /** The owned SDK process registers itself before TUI input; no PID comes from configuration. */
7
+ export declare function registerManagedPiRuntime(controller: ManagedPiSdkSessionController, scope: ManagedPiExecutionScope, descriptorFile: string, options?: {
8
+ readonly confirmNative?: boolean;
9
+ readonly resumeAuthorization?: ManagedPiSdkResumeAuthorization;
10
+ }): Promise<void>;
11
+ /** Read-only OS witness for the socket owner; it neither reads nor prints an authentication token. */
12
+ export declare function managedPiSocketPeerPid(socketPath: string): number | null;
13
+ export declare function managedPiRepairDependencies(request: {
14
+ readonly execution: {
15
+ readonly task_root: string;
16
+ };
17
+ readonly repair_policy?: unknown;
18
+ }, deps?: {
19
+ readonly control?: typeof requestManagedPiControl;
20
+ readonly peerPid?: typeof managedPiSocketPeerPid;
21
+ }): RoleRepairDependencies | undefined;