@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,167 @@
1
+ import { runCollaborationPreflight, } from '../../app/collab-preflight.js';
2
+ export const collaborationPreflightUsage = 'pappra collab preflight --assignment <abs assignment.json> --capabilities <abs card.json> [--max-age-minutes <n>] [--json]\n\n' +
3
+ 'Read-only readiness check over the existing collaboration preflight. It reads the\n' +
4
+ 'two files and verifies pinned inputs/evidence; it never launches, claims, mutates\n' +
5
+ 'a task record or refreshes evidence. Exit 0 ready, 1 needs_input, 2 invalid.\n' +
6
+ 'Needs-input output groups recovery guidance for known blockers; JSON output is unchanged.';
7
+ function usageFailure(output, options, code, message) {
8
+ if (options.json) {
9
+ output.stdout(`${JSON.stringify({
10
+ schema: 'pappra/collaboration-preflight/1',
11
+ ok: false,
12
+ status: 'invalid',
13
+ errors: [message],
14
+ blockers: [],
15
+ warnings: [],
16
+ limits: [],
17
+ code,
18
+ })}\n`);
19
+ }
20
+ else {
21
+ output.stderr(`pappra collab preflight: ${message}\n`);
22
+ }
23
+ return 2;
24
+ }
25
+ function describeChecks(checks) {
26
+ return checks.map((check) => ` - ${check.code}${check.capability === undefined ? '' : ` (${check.capability})`}`);
27
+ }
28
+ const FRESHNESS_RECOVERY = 'Obtain fresh runtime evidence from the current receiving session and rerun preflight. Never retimestamp older evidence, and never revert a user-selected model or provider to recreate an earlier observation.';
29
+ const IDENTITY_RECOVERY = 'Supply evidence for the exact assignee identity, session, cwd and configuration. A model or provider difference alone is not an identity difference, and identity fields are not relabeled to match.';
30
+ const CAPABILITY_RECOVERY = 'Required capability readiness is not confirmed by this card: inspect the current runtime exposure and obtain actual current evidence for the required tool or skill, restoring or enabling it when it is in fact absent. Changing the requirement is an explicit scope decision for the coordinator, not a worker recovery step. Earlier successful tool use does not prove the current runtime still exposes it.';
31
+ /** Exact identity blockers emitted by the preflight core; unknown future codes get no remedy. */
32
+ const IDENTITY_BLOCKERS = new Set([
33
+ 'assignee_agent_id_mismatch',
34
+ 'assignee_session_id_mismatch',
35
+ 'assignee_harness_mismatch',
36
+ 'assignee_surface_mismatch',
37
+ 'assignee_configuration_id_mismatch',
38
+ 'assignee_cwd_mismatch',
39
+ ]);
40
+ /** Recovery guidance for concrete, known blockers. Unknown codes keep their code only. */
41
+ function recoveryFor(code) {
42
+ if (code === 'capabilities_stale')
43
+ return { group: 'freshness', action: FRESHNESS_RECOVERY };
44
+ if (code === 'capabilities_from_future')
45
+ return {
46
+ group: 'clock',
47
+ action: 'The evidence clock is ahead of this host clock: compare host and native timestamps and correct the clock or the evidence source. Do not edit timestamps to make evidence pass.',
48
+ };
49
+ if (code === 'runtime_capabilities_unconfirmed')
50
+ return {
51
+ group: 'evidence-level',
52
+ action: 'Derive a runtime card from actual native evidence for this session (pappra collab capabilities derive); a declared template is not runtime proof.',
53
+ };
54
+ if (code === 'required_capability_omitted_by_runner')
55
+ return { group: 'capabilities', action: CAPABILITY_RECOVERY };
56
+ if (code === 'native_evidence_changed' ||
57
+ code === 'native_evidence_unavailable')
58
+ return {
59
+ group: 'evidence-files',
60
+ action: 'The referenced native evidence changed or is unavailable: re-derive from the current native file instead of editing digests.',
61
+ };
62
+ if (code === 'input_changed' || code === 'input_unavailable')
63
+ return {
64
+ group: 'pinned-input',
65
+ action: 'A pinned input changed or is missing: obtain the current pinned input and update the assignment revision deliberately rather than rewriting a digest.',
66
+ };
67
+ if (code === 'tools_unavailable' || code === 'skills_unavailable')
68
+ return { group: 'capabilities', action: CAPABILITY_RECOVERY };
69
+ if (code === 'tools_evidence_unavailable' ||
70
+ code === 'skills_evidence_unavailable')
71
+ return {
72
+ group: 'capability-evidence',
73
+ action: 'A claimed capability has no usable evidence: re-derive the card so each capability references existing evidence.',
74
+ };
75
+ if (code === 'skill_version_mismatch' ||
76
+ code === 'skill_files_changed' ||
77
+ code === 'skill_files_unavailable')
78
+ return {
79
+ group: 'skill-bundle',
80
+ action: 'The required skill bundle differs from the pinned fingerprint or is unreadable: restore the pinned bundle or update the requirement deliberately.',
81
+ };
82
+ if (code === 'assignee_cwd_unavailable')
83
+ return {
84
+ group: 'identity',
85
+ action: 'The assigned cwd is unreadable from here: run readiness from a process that can read it. cwd is part of the identity.',
86
+ };
87
+ if (IDENTITY_BLOCKERS.has(code))
88
+ return { group: 'identity', action: IDENTITY_RECOVERY };
89
+ return null;
90
+ }
91
+ function recoveryLines(checks) {
92
+ const groups = new Map();
93
+ for (const check of checks) {
94
+ const guidance = recoveryFor(check.code);
95
+ if (guidance === null)
96
+ continue;
97
+ const existing = groups.get(guidance.group);
98
+ if (existing === undefined) {
99
+ groups.set(guidance.group, {
100
+ action: guidance.action,
101
+ codes: new Set([check.code]),
102
+ });
103
+ continue;
104
+ }
105
+ existing.codes.add(check.code);
106
+ }
107
+ return [...groups.entries()].map(([group, entry]) => ` ${group}: ${entry.action} (${[...entry.codes].join(', ')})`);
108
+ }
109
+ function emitHuman(report, output) {
110
+ if (report.status === 'ready') {
111
+ output.stdout(`Preflight ready${report.checked_at === undefined ? '' : ` at ${report.checked_at}`}.\n`);
112
+ }
113
+ else if (report.status === 'needs_input') {
114
+ output.stdout(`Preflight needs input: ${report.blockers.length} blocker(s).\n`);
115
+ for (const line of describeChecks(report.blockers))
116
+ output.stdout(`${line}\n`);
117
+ const recovery = recoveryLines(report.blockers);
118
+ if (recovery.length > 0) {
119
+ output.stdout('Recovery:\n');
120
+ for (const line of recovery)
121
+ output.stdout(`${line}\n`);
122
+ }
123
+ }
124
+ else {
125
+ output.stdout(`Preflight invalid: ${report.errors[0] ?? 'invalid input'}.\n`);
126
+ for (const error of report.errors.slice(1))
127
+ output.stdout(` - ${error}\n`);
128
+ }
129
+ if (report.warnings.length > 0) {
130
+ output.stdout(`Warnings: ${report.warnings.length}.\n`);
131
+ for (const line of describeChecks(report.warnings))
132
+ output.stdout(`${line}\n`);
133
+ }
134
+ if (report.limits.length > 0) {
135
+ output.stdout(`Limits: ${report.limits.join(', ')}.\n`);
136
+ }
137
+ }
138
+ export function runCollaborationPreflightCommand(options, output) {
139
+ if (options.assignmentFile === null) {
140
+ return usageFailure(output, options, 'assignment_required', 'preflight requires --assignment <abs assignment.json>.');
141
+ }
142
+ if (options.capabilitiesFile === null) {
143
+ return usageFailure(output, options, 'capabilities_required', 'preflight requires --capabilities <abs card.json>.');
144
+ }
145
+ let maxAgeMinutes;
146
+ if (options.maxAgeMinutes !== null) {
147
+ const parsed = Number(options.maxAgeMinutes.trim());
148
+ if (!Number.isFinite(parsed) || parsed <= 0) {
149
+ return usageFailure(output, options, 'max_age_invalid', '--max-age-minutes must be a positive finite number.');
150
+ }
151
+ maxAgeMinutes = parsed;
152
+ }
153
+ const report = runCollaborationPreflight({
154
+ assignmentFile: options.assignmentFile,
155
+ capabilitiesFile: options.capabilitiesFile,
156
+ ...(maxAgeMinutes === undefined ? {} : { maxAgeMinutes }),
157
+ });
158
+ if (options.json) {
159
+ output.stdout(`${JSON.stringify(report)}\n`);
160
+ }
161
+ else {
162
+ emitHuman(report, output);
163
+ }
164
+ if (report.status === 'ready')
165
+ return 0;
166
+ return report.status === 'needs_input' ? 1 : 2;
167
+ }
@@ -0,0 +1,46 @@
1
+ import { type RecoveryController } from '../../app/collab-recovery-executor.js';
2
+ import type { RecoveryPolicy } from '../../app/collab-recovery-projection.js';
3
+ import type { Identity } from '../../collab/types.js';
4
+ import type { CliOutput } from '../output.js';
5
+ export declare const COLLAB_RECOVERY_RUN_SCHEMA: 'pappra/collab-recovery-run/1';
6
+ export declare const collaborationRecoveryRunUsage: string;
7
+ /** Typed options for the handler; a parser rejects duplicate and unknown flags at the boundary. */
8
+ export interface CollaborationRecoveryRunOptions {
9
+ readonly requestFile: string | null;
10
+ readonly apply: boolean;
11
+ readonly json: boolean;
12
+ }
13
+ export interface CollaborationRecoveryRunParse {
14
+ readonly options: CollaborationRecoveryRunOptions;
15
+ readonly errors: readonly string[];
16
+ }
17
+ /** The request file supplied to the handler; mode is derived from the --apply flag, not the file. */
18
+ export interface RecoveryRunRequestFile {
19
+ readonly schema: 'pappra/collab-recovery-run-request/1';
20
+ readonly taskRoot: string;
21
+ readonly planFile: string;
22
+ readonly self: Identity;
23
+ readonly policy: RecoveryPolicy;
24
+ readonly expected?: {
25
+ readonly session_id: string;
26
+ readonly cwd?: string | null;
27
+ readonly binding_ref?: string | null;
28
+ readonly binding_digest?: string | null;
29
+ readonly pane_id?: string | null;
30
+ readonly harness?: string | null;
31
+ } | null;
32
+ readonly requestId: string;
33
+ readonly target?: {
34
+ readonly agent: string;
35
+ } | null;
36
+ }
37
+ /** Parse argv for the recovery-run command, rejecting duplicate and unknown options. */
38
+ export declare function parseCollaborationRecoveryRunArgs(argv: readonly string[]): CollaborationRecoveryRunParse;
39
+ /**
40
+ * Durable recovery execution handler, exported for the integration router. It builds a Herdr-backed
41
+ * controller only for an `--apply` request that names a target agent; a dry plan needs no controller
42
+ * and issues no effect.
43
+ */
44
+ export declare function runCollaborationRecoveryRunCommand(options: CollaborationRecoveryRunOptions, output: CliOutput, deps?: {
45
+ readonly controller?: RecoveryController;
46
+ }): Promise<number>;
@@ -0,0 +1,224 @@
1
+ import path from 'node:path';
2
+ import { readBoundedFile } from '../../app/bounded-file.js';
3
+ import { createHerdrRecoveryController, executeRecovery, } from '../../app/collab-recovery-executor.js';
4
+ export const COLLAB_RECOVERY_RUN_SCHEMA = 'pappra/collab-recovery-run/1';
5
+ const MAX_REQUEST_BYTES = 64 * 1024;
6
+ export const collaborationRecoveryRunUsage = 'pappra collab recovery-run --request <abs recovery-run.json> [--apply] [--json]\n\n' +
7
+ 'Durable recovery execution for a single task. Without --apply this is a strict dry\n' +
8
+ 'plan: it reads the current task and recommendation and writes nothing. With --apply,\n' +
9
+ 'the request must pin the exact session, cwd, harness, pane and bounded task-local\n' +
10
+ 'binding path/digest for the admitted current task participant; no identity or\n' +
11
+ 'participant fallback is accepted. The live target and current authority are rechecked\n' +
12
+ 'before prompting. It never spawns a session, overrides a model, installs anything or\n' +
13
+ 'auto-approves.';
14
+ /** Parse argv for the recovery-run command, rejecting duplicate and unknown options. */
15
+ export function parseCollaborationRecoveryRunArgs(argv) {
16
+ const errors = [];
17
+ let requestFile = null;
18
+ let apply = false;
19
+ let json = false;
20
+ let sawApply = false;
21
+ let sawJson = false;
22
+ for (let i = 0; i < argv.length; i += 1) {
23
+ const arg = argv[i];
24
+ if (arg === '--request') {
25
+ if (requestFile !== null)
26
+ errors.push('--request may be given only once.');
27
+ const value = argv[i + 1];
28
+ if (value === undefined || value.startsWith('--'))
29
+ errors.push('--request requires a value.');
30
+ else {
31
+ requestFile = value;
32
+ i += 1;
33
+ }
34
+ }
35
+ else if (arg === '--apply') {
36
+ if (sawApply)
37
+ errors.push('--apply may be given only once.');
38
+ sawApply = true;
39
+ apply = true;
40
+ }
41
+ else if (arg === '--json') {
42
+ if (sawJson)
43
+ errors.push('--json may be given only once.');
44
+ sawJson = true;
45
+ json = true;
46
+ }
47
+ else {
48
+ errors.push(`unknown option: ${String(arg)}`);
49
+ }
50
+ }
51
+ return { options: { requestFile, apply, json }, errors };
52
+ }
53
+ function isIdentity(value) {
54
+ return (typeof value === 'object' &&
55
+ value !== null &&
56
+ typeof value.agent_id === 'string' &&
57
+ typeof value.session_id === 'string' &&
58
+ (typeof value.harness === 'string' ||
59
+ value.harness === null));
60
+ }
61
+ function isPinnedExpected(value) {
62
+ if (typeof value !== 'object' || value === null || Array.isArray(value))
63
+ return false;
64
+ const expected = value;
65
+ const keys = Object.keys(expected).sort();
66
+ return (keys.join('|') ===
67
+ 'binding_digest|binding_ref|cwd|harness|pane_id|session_id' &&
68
+ typeof expected.session_id === 'string' &&
69
+ expected.session_id.length > 0 &&
70
+ typeof expected.cwd === 'string' &&
71
+ path.isAbsolute(expected.cwd) &&
72
+ typeof expected.binding_ref === 'string' &&
73
+ path.isAbsolute(expected.binding_ref) &&
74
+ typeof expected.binding_digest === 'string' &&
75
+ /^sha256:[0-9a-f]{64}$/.test(expected.binding_digest) &&
76
+ typeof expected.pane_id === 'string' &&
77
+ /^[A-Za-z0-9]+:p[A-Za-z0-9]+$/.test(expected.pane_id) &&
78
+ typeof expected.harness === 'string' &&
79
+ expected.harness.length > 0);
80
+ }
81
+ function loadRequestFile(file) {
82
+ const read = readBoundedFile(file, MAX_REQUEST_BYTES);
83
+ if (!read.ok)
84
+ return { ok: false, error: `request file unreadable (${read.code}).` };
85
+ let parsed;
86
+ try {
87
+ parsed = JSON.parse(read.text);
88
+ }
89
+ catch {
90
+ return { ok: false, error: 'request file is not valid JSON.' };
91
+ }
92
+ if (typeof parsed !== 'object' || parsed === null)
93
+ return { ok: false, error: 'request must be an object.' };
94
+ const raw = parsed;
95
+ if (raw.schema !== 'pappra/collab-recovery-run-request/1')
96
+ return { ok: false, error: 'unsupported request schema.' };
97
+ if (typeof raw.taskRoot !== 'string' || !path.isAbsolute(raw.taskRoot))
98
+ return { ok: false, error: 'taskRoot must be an absolute path.' };
99
+ if (typeof raw.planFile !== 'string' || !path.isAbsolute(raw.planFile))
100
+ return { ok: false, error: 'planFile must be an absolute path.' };
101
+ if (!isIdentity(raw.self))
102
+ return { ok: false, error: 'self must be a valid identity.' };
103
+ const policy = raw.policy;
104
+ if (typeof policy !== 'object' ||
105
+ policy === null ||
106
+ (policy.role !== 'writer' &&
107
+ policy.role !== 'coordinator' &&
108
+ policy.role !== 'reviewer'))
109
+ return {
110
+ ok: false,
111
+ error: 'policy.role must be writer, coordinator or reviewer.',
112
+ };
113
+ if (typeof raw.requestId !== 'string' || raw.requestId.length === 0)
114
+ return { ok: false, error: 'requestId must be a non-empty string.' };
115
+ if (raw.expected !== undefined &&
116
+ raw.expected !== null &&
117
+ !isPinnedExpected(raw.expected))
118
+ return {
119
+ ok: false,
120
+ error: 'expected must pin session, cwd, harness, pane, binding_ref and binding_digest exactly.',
121
+ };
122
+ if (raw.target !== undefined &&
123
+ raw.target !== null &&
124
+ (typeof raw.target !== 'object' ||
125
+ Array.isArray(raw.target) ||
126
+ typeof raw.target.agent !== 'string' ||
127
+ !raw.target.agent))
128
+ return {
129
+ ok: false,
130
+ error: 'target.agent must be a non-empty Herdr agent name.',
131
+ };
132
+ return { ok: true, value: raw };
133
+ }
134
+ function invalid(output, options, errors) {
135
+ if (options.json)
136
+ output.stdout(`${JSON.stringify({ schema: COLLAB_RECOVERY_RUN_SCHEMA, ok: false, status: 'invalid', errors })}\n`);
137
+ else {
138
+ output.stdout('Recovery run request invalid.\n');
139
+ for (const error of errors)
140
+ output.stdout(` - ${error}\n`);
141
+ }
142
+ return 2;
143
+ }
144
+ /**
145
+ * Durable recovery execution handler, exported for the integration router. It builds a Herdr-backed
146
+ * controller only for an `--apply` request that names a target agent; a dry plan needs no controller
147
+ * and issues no effect.
148
+ */
149
+ export async function runCollaborationRecoveryRunCommand(options, output, deps = {}) {
150
+ if (options.requestFile === null)
151
+ return invalid(output, options, ['--request is required.']);
152
+ if (!path.isAbsolute(options.requestFile))
153
+ return invalid(output, options, ['--request must be absolute.']);
154
+ const loaded = loadRequestFile(options.requestFile);
155
+ if (!loaded.ok)
156
+ return invalid(output, options, [loaded.error]);
157
+ const request = loaded.value;
158
+ const mode = options.apply ? 'apply' : 'plan';
159
+ if (mode === 'apply' &&
160
+ (!isPinnedExpected(request.expected) ||
161
+ typeof request.target?.agent !== 'string' ||
162
+ request.target.agent.length === 0))
163
+ return invalid(output, options, [
164
+ 'apply requires a complete expected session/cwd/harness/pane plus a task-local binding_ref and binding_digest, and request.target.agent.',
165
+ ]);
166
+ let controller;
167
+ if (deps.controller)
168
+ controller = deps.controller;
169
+ else if (mode === 'apply') {
170
+ if (!request.target || typeof request.target.agent !== 'string')
171
+ return invalid(output, options, [
172
+ 'apply requires request.target.agent for the continuation wake.',
173
+ ]);
174
+ controller = createHerdrRecoveryController({ env: process.env }, { agent: request.target.agent });
175
+ }
176
+ else {
177
+ controller = {
178
+ id: 'recovery-plan-noop',
179
+ perform: async () => ({
180
+ disposition: 'unknown',
181
+ detail: 'plan mode issues no effect',
182
+ observation: 'none',
183
+ }),
184
+ };
185
+ }
186
+ const executorRequest = {
187
+ taskRoot: request.taskRoot,
188
+ planFile: request.planFile,
189
+ self: request.self,
190
+ policy: request.policy,
191
+ requestId: request.requestId,
192
+ mode,
193
+ ...(isPinnedExpected(request.expected)
194
+ ? {
195
+ expectedSession: {
196
+ session_id: request.expected.session_id,
197
+ cwd: request.expected.cwd,
198
+ binding_digest: request.expected.binding_digest,
199
+ binding_ref: request.expected.binding_ref,
200
+ target_agent: request.target?.agent ?? null,
201
+ pane_id: request.expected.pane_id,
202
+ harness: request.expected.harness,
203
+ },
204
+ }
205
+ : {}),
206
+ };
207
+ const result = await executeRecovery(executorRequest, { controller });
208
+ if (options.json) {
209
+ output.stdout(`${JSON.stringify({ schema: COLLAB_RECOVERY_RUN_SCHEMA, ok: result.ok, executor: result })}\n`);
210
+ }
211
+ else {
212
+ output.stdout(`Recovery ${mode}: ${result.status}${result.action ? ` (${result.action.kind} ${result.action.subtask_id ?? '-'})` : ''}.\n`);
213
+ for (const note of result.notes)
214
+ output.stdout(` - ${note}\n`);
215
+ if (result.reservation)
216
+ output.stdout(` reservation: ${result.reservation.created ? 'created' : 'existing'} ${result.reservation.key.slice(0, 12)} outcome=${result.reservation.outcome ?? 'none'}\n`);
217
+ }
218
+ // Exit success for a clean plan or a positively issued/deferred apply; block otherwise.
219
+ const good = result.status === 'planned' ||
220
+ result.status === 'applied' ||
221
+ result.status === 'deferred' ||
222
+ result.status === 'noop';
223
+ return good ? 0 : 1;
224
+ }
@@ -0,0 +1,11 @@
1
+ import { type RecoveryAction } from '../../app/collab-recovery.js';
2
+ import type { CliOutput } from '../output.js';
3
+ export declare const collaborationRecoveryUsage: string;
4
+ export interface CollaborationRecoveryOptions {
5
+ readonly action: RecoveryAction | null;
6
+ readonly taskRoot: string | null;
7
+ readonly requestFile: string | null;
8
+ readonly apply: boolean;
9
+ readonly json: boolean;
10
+ }
11
+ export declare function runCollaborationRecoveryCommand(options: CollaborationRecoveryOptions, output: CliOutput): Promise<number>;
@@ -0,0 +1,104 @@
1
+ import path from 'node:path';
2
+ import { COLLAB_RECOVERY_SCHEMA, applyRecovery, inspectRecovery, loadRecoveryRequest, planRecovery, } from '../../app/collab-recovery.js';
3
+ export const collaborationRecoveryUsage = 'pappra collab recovery inspect --task-root <abs> [--json]\n' +
4
+ 'pappra collab recovery <reconcile|lock-break> --task-root <abs> --request <abs request.json> [--apply] [--json]\n\n' +
5
+ 'Read-only recovery inspection or explicit recorded recovery. Reconcile resolves\n' +
6
+ 'one uncertainty (and optionally applies an existing state transition) atomically.\n' +
7
+ 'Lock-break archives one task write lock only after an operator stop assertion and\n' +
8
+ 'an exact inspected fingerprint. No native execution is queried or controlled.';
9
+ function invalid(output, options, errors) {
10
+ if (options.json) {
11
+ output.stdout(`${JSON.stringify({
12
+ schema: COLLAB_RECOVERY_SCHEMA,
13
+ ok: false,
14
+ status: 'invalid',
15
+ action: options.action,
16
+ errors,
17
+ })}\n`);
18
+ }
19
+ else {
20
+ output.stdout(`Recovery request invalid.\n`);
21
+ for (const error of errors)
22
+ output.stdout(` - ${error}\n`);
23
+ }
24
+ return 2;
25
+ }
26
+ function failure(output, options, value, exitCode) {
27
+ if (options.json) {
28
+ output.stdout(`${JSON.stringify({
29
+ schema: COLLAB_RECOVERY_SCHEMA,
30
+ ok: false,
31
+ status: exitCode === 2 ? 'invalid' : 'needs_input',
32
+ action: options.action,
33
+ code: value.code,
34
+ message: value.message,
35
+ nextAction: value.nextAction,
36
+ })}\n`);
37
+ }
38
+ else {
39
+ output.stdout(`Recovery needs input: ${value.message}\n`);
40
+ if (value.nextAction)
41
+ output.stdout(` ${value.nextAction}\n`);
42
+ }
43
+ return exitCode;
44
+ }
45
+ function emitInspect(value, output) {
46
+ const uncertainty = value.uncertainty;
47
+ const lock = value.lock;
48
+ output.stdout(`Recovery ${value.ok === true ? 'ready' : 'needs input'}: ${String(uncertainty.counts.open)} open uncertainty, ${String(uncertainty.counts.resolved)} resolved.\n`);
49
+ output.stdout(` lock: ${lock.held ? (lock.holder_process_alive ? 'held (holder alive)' : 'held (holder liveness unconfirmed)') : 'not held'}; transactions: ${String(lock.transaction_count)}; fingerprint: ${lock.fingerprint_status}\n`);
50
+ }
51
+ function emitHuman(value, action, output) {
52
+ if (value.status === 'planned' && value.applied === false) {
53
+ output.stdout(action === 'reconcile'
54
+ ? 'Reconcile plan validates the request and task namespace; nothing was written.\n'
55
+ : 'Lock-break plan validates the request and task namespace; nothing was archived.\n');
56
+ return;
57
+ }
58
+ if (action === 'reconcile') {
59
+ output.stdout(value.ok === true
60
+ ? `Reconcile applied: resolution recorded; state transition ${String(value.result?.state_transition ?? 'none')}.\n`
61
+ : `Reconcile refused: ${String(value.reason ?? 'unknown')}.\n`);
62
+ }
63
+ else if (value.ok === true) {
64
+ output.stdout(`Lock-break archived ${String(value.archived_lock ?? 'the task lock')}.\n`);
65
+ }
66
+ else {
67
+ output.stdout(`Lock-break refused: ${String(value.reason ?? 'unknown')}.\n`);
68
+ }
69
+ }
70
+ export async function runCollaborationRecoveryCommand(options, output) {
71
+ if (options.action === null)
72
+ return invalid(output, options, ['recovery requires an action.']);
73
+ if (options.taskRoot === null)
74
+ return invalid(output, options, ['--task-root is required.']);
75
+ if (!path.isAbsolute(options.taskRoot))
76
+ return invalid(output, options, ['--task-root must be absolute.']);
77
+ if (options.action === 'inspect') {
78
+ const result = await inspectRecovery(options.taskRoot);
79
+ if (!result.ok)
80
+ return failure(output, options, result, 1);
81
+ if (options.json)
82
+ output.stdout(`${JSON.stringify(result.value)}\n`);
83
+ else
84
+ emitInspect(result.value, output);
85
+ return result.value.ok === true ? 0 : 1;
86
+ }
87
+ if (options.requestFile === null)
88
+ return invalid(output, options, [`${options.action} requires --request.`]);
89
+ if (!path.isAbsolute(options.requestFile))
90
+ return invalid(output, options, ['--request must be absolute.']);
91
+ const loaded = loadRecoveryRequest(options.requestFile, options.action);
92
+ if (!loaded.ok)
93
+ return failure(output, options, loaded, 2);
94
+ const result = options.apply
95
+ ? await applyRecovery(options.taskRoot, loaded.value.request)
96
+ : await planRecovery(options.taskRoot, loaded.value.request);
97
+ if (!result.ok)
98
+ return failure(output, options, result, 1);
99
+ if (options.json)
100
+ output.stdout(`${JSON.stringify(result.value)}\n`);
101
+ else
102
+ emitHuman(result.value, options.action, output);
103
+ return result.value.ok === true ? 0 : 1;
104
+ }
@@ -0,0 +1,11 @@
1
+ import { type ResourceAction } from '../../app/collab-resources.js';
2
+ import type { CliOutput } from '../output.js';
3
+ export declare const collaborationResourcesUsage: string;
4
+ export interface CollaborationResourcesOptions {
5
+ readonly action: ResourceAction | null;
6
+ readonly taskRoot: string | null;
7
+ readonly requestFile: string | null;
8
+ readonly apply: boolean;
9
+ readonly json: boolean;
10
+ }
11
+ export declare function runCollaborationResourcesCommand(options: CollaborationResourcesOptions, output: CliOutput): Promise<number>;
@@ -0,0 +1,96 @@
1
+ import path from 'node:path';
2
+ import { COLLAB_RESOURCES_SCHEMA, applyResourceRequest, listTaskResources, loadResourceRequest, planResourceRequest, } from '../../app/collab-resources.js';
3
+ export const collaborationResourcesUsage = 'pappra collab resource <list|claim|release> --task-root <abs> [options]\n' +
4
+ ' list --task-root <abs> [--json]\n' +
5
+ ' claim --task-root <abs> --request <abs request.json> [--apply] [--json]\n' +
6
+ ' release --task-root <abs> --request <abs request.json> [--apply] [--json]\n\n' +
7
+ 'Read/plan is non-mutating. --apply invokes the existing cooperative claim or\n' +
8
+ 'release primitive and never fences OS side effects. Exit 0 success,\n' +
9
+ '1 conflict/uncertainty/core refusal, 2 invalid request/options.';
10
+ function invalid(output, options, errors) {
11
+ if (options.json) {
12
+ output.stdout(`${JSON.stringify({
13
+ schema: COLLAB_RESOURCES_SCHEMA,
14
+ ok: false,
15
+ status: 'invalid',
16
+ action: options.action,
17
+ errors,
18
+ })}\n`);
19
+ }
20
+ else {
21
+ output.stdout(`Resource request invalid.\n`);
22
+ for (const error of errors)
23
+ output.stdout(` - ${error}\n`);
24
+ }
25
+ return 2;
26
+ }
27
+ function failure(output, options, value, exitCode) {
28
+ if (options.json) {
29
+ output.stdout(`${JSON.stringify({
30
+ schema: COLLAB_RESOURCES_SCHEMA,
31
+ ok: false,
32
+ status: exitCode === 2 ? 'invalid' : 'needs_input',
33
+ action: options.action,
34
+ code: value.code,
35
+ message: value.message,
36
+ nextAction: value.nextAction,
37
+ })}\n`);
38
+ }
39
+ else {
40
+ output.stdout(`Resource operation needs input: ${value.message}\n`);
41
+ if (value.nextAction)
42
+ output.stdout(` ${value.nextAction}\n`);
43
+ }
44
+ return exitCode;
45
+ }
46
+ function emitHuman(value, action, output) {
47
+ if (action === 'list') {
48
+ const counts = value.counts;
49
+ output.stdout(`Domain resources: ${String(counts.tasks)} task(s), ${String(counts.claims)} claim(s), state ${String(value.state)}.\n`);
50
+ if (value.unreadable_tasks.length)
51
+ output.stdout(` unreadable tasks: ${String(value.unreadable_tasks.length)}\n`);
52
+ }
53
+ else if (value.applied === false) {
54
+ output.stdout(`Resource ${action} plan validated; nothing was persisted.\n`);
55
+ }
56
+ else {
57
+ output.stdout(`Resource ${action} ${value.ok === true ? 'applied' : 'refused'}: ${String(value.reason ?? 'completed')}.\n`);
58
+ }
59
+ }
60
+ export async function runCollaborationResourcesCommand(options, output) {
61
+ if (options.action === null)
62
+ return invalid(output, options, [
63
+ 'resource requires list, claim or release.',
64
+ ]);
65
+ if (options.taskRoot === null)
66
+ return invalid(output, options, ['--task-root is required.']);
67
+ if (!path.isAbsolute(options.taskRoot))
68
+ return invalid(output, options, ['--task-root must be absolute.']);
69
+ if (options.action === 'list') {
70
+ const result = await listTaskResources(options.taskRoot);
71
+ if (!result.ok)
72
+ return failure(output, options, result, 1);
73
+ if (options.json)
74
+ output.stdout(`${JSON.stringify(result.value)}\n`);
75
+ else
76
+ emitHuman(result.value, options.action, output);
77
+ return result.value.ok === true ? 0 : 1;
78
+ }
79
+ if (options.requestFile === null)
80
+ return invalid(output, options, [`${options.action} requires --request.`]);
81
+ if (!path.isAbsolute(options.requestFile))
82
+ return invalid(output, options, ['--request must be absolute.']);
83
+ const loaded = loadResourceRequest(options.requestFile, options.action);
84
+ if (!loaded.ok)
85
+ return failure(output, options, loaded, 2);
86
+ const result = options.apply
87
+ ? await applyResourceRequest(options.taskRoot, loaded.value.request)
88
+ : await planResourceRequest(options.taskRoot, loaded.value.request);
89
+ if (!result.ok)
90
+ return failure(output, options, result, 1);
91
+ if (options.json)
92
+ output.stdout(`${JSON.stringify(result.value)}\n`);
93
+ else
94
+ emitHuman(result.value, options.action, output);
95
+ return result.value.ok === true ? 0 : 1;
96
+ }
@@ -0,0 +1,9 @@
1
+ import type { CliOutput } from '../output.js';
2
+ export declare const collaborationRolePlanUsage: string;
3
+ export declare function runCollaborationRolePlanCommand(options: {
4
+ readonly action: string;
5
+ readonly requestFile: string | null;
6
+ readonly taskRoot: string | null;
7
+ readonly planFile: string | null;
8
+ readonly json: boolean;
9
+ }, output: CliOutput): Promise<number>;