@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,384 @@
1
+ import crypto from 'node:crypto';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import { canonicalJson } from '../collab/envelope.js';
5
+ import { findAttempt } from '../collab/lifecycle.js';
6
+ import { transact } from '../collab/store.js';
7
+ import { CheckpointService, saveHandoffBundle, } from '../continuity/index.js';
8
+ import { continuityTaskPaths, writeContinuityBytes, } from '../continuity/paths.js';
9
+ import { readBoundedFile } from './bounded-file.js';
10
+ import { prepareManagedHandoffContextReference } from './managed-pi-handoff-reference.js';
11
+ import { openTaskStore, assertTaskStoreCurrent, } from './collab-task-store.js';
12
+ import { openMessageTask, readRegisteredMessageSafe, } from './collab-messages.js';
13
+ import { applySessionTransition, } from './collab-session-transition.js';
14
+ export const AUTO_HANDOFF_SCHEMA = 'pappra/automatic-handoff/1';
15
+ const JOURNAL = 'automatic_handoff_journal';
16
+ const MAX_ENTRIES = 32;
17
+ function object(value) {
18
+ return typeof value === 'object' && value !== null && !Array.isArray(value);
19
+ }
20
+ function entries(record) {
21
+ const value = record[JOURNAL];
22
+ if (value === undefined)
23
+ return [];
24
+ if (!Array.isArray(value) ||
25
+ value.length > MAX_ENTRIES ||
26
+ !value.every((row) => object(row) &&
27
+ typeof row.id === 'string' &&
28
+ typeof row.config_digest === 'string' &&
29
+ [
30
+ 'capture_reserved',
31
+ 'prepared',
32
+ 'active',
33
+ 'complete',
34
+ 'reconcile_required',
35
+ ].includes(String(row.stage)) &&
36
+ (row.request === null || object(row.request)) &&
37
+ (row.code === null || typeof row.code === 'string')))
38
+ throw new Error('automatic_handoff_journal_invalid');
39
+ return value;
40
+ }
41
+ async function storeEntry(task, next, create, authorize) {
42
+ const unsafe = await assertTaskStoreCurrent(task);
43
+ if (unsafe)
44
+ throw new Error(unsafe.code);
45
+ const result = transact(task.taskRoot, {
46
+ actor: 'automatic-handoff',
47
+ purpose: next.stage,
48
+ apply(record) {
49
+ if (create && (!authorize || !authorize(record)))
50
+ return { ok: false, reason: 'automatic_handoff_authority_changed' };
51
+ const rows = entries(record);
52
+ const index = rows.findIndex((row) => row.id === next.id);
53
+ if (create && index >= 0)
54
+ return { ok: false, reason: 'automatic_handoff_already_reserved' };
55
+ if (!create &&
56
+ (index < 0 || rows[index]?.config_digest !== next.config_digest))
57
+ return { ok: false, reason: 'automatic_handoff_reservation_changed' };
58
+ if (index < 0) {
59
+ if (rows.length >= MAX_ENTRIES)
60
+ return { ok: false, reason: 'automatic_handoff_limit' };
61
+ rows.push(next);
62
+ }
63
+ else
64
+ rows[index] = next;
65
+ record[JOURNAL] = rows;
66
+ return {
67
+ record,
68
+ op: 'automatic-handoff',
69
+ summary: { id: next.id, stage: next.stage },
70
+ result: null,
71
+ };
72
+ },
73
+ });
74
+ if (!result.ok)
75
+ throw new Error(result.reason);
76
+ return reopenTask(task);
77
+ }
78
+ async function reopenTask(previous) {
79
+ const current = await openTaskStore(previous.taskRoot);
80
+ if (!current.ok)
81
+ throw new Error(current.code);
82
+ for (const key of ['taskRoot', 'messagesDirectory']) {
83
+ const before = previous.identity[key];
84
+ const after = current.value.identity[key];
85
+ if (before.dev !== after.dev ||
86
+ before.ino !== after.ino ||
87
+ before.path !== after.path)
88
+ throw new Error('automatic_handoff_namespace_changed');
89
+ }
90
+ return current.value;
91
+ }
92
+ function pending(items, completeness) {
93
+ const values = items.map((item) => typeof item === 'string' ? item : JSON.stringify(item));
94
+ if (values.length > 64 || values.some((item) => !item || item.length > 2048))
95
+ throw new Error('handoff_pending_inventory_exceeds_bound');
96
+ return { items: values, completeness };
97
+ }
98
+ function captureIdentityMatches(record, config, runtime) {
99
+ const intent = config.transition.intent;
100
+ const observed = runtime.observe();
101
+ const attempt = findAttempt(record, intent.subtask_id, intent.attempt);
102
+ return (observed.native.sessionId === intent.from.session_id &&
103
+ observed.cwd === intent.from.cwd &&
104
+ record.task_root === config.transition.task_root &&
105
+ record.coordinator?.owner_epoch === intent.coordinator_epoch &&
106
+ attempt?.assignee.agent_id === intent.from.agent_id &&
107
+ attempt.assignee.session_id === intent.from.session_id &&
108
+ attempt.input_revision === intent.input_revision &&
109
+ ['assigned', 'accepted', 'running'].includes(attempt.state) &&
110
+ intent.claims.every((expected) => record.claims.some((claim) => claim.claim_id === expected.claim_id &&
111
+ claim.released_at === null &&
112
+ claim.resource_epoch === expected.resource_epoch &&
113
+ claim.holder.agent_id === intent.from.agent_id &&
114
+ claim.holder.session_id === intent.from.session_id)));
115
+ }
116
+ /** Resolve only digest-verified, applied evidence for this exact handoff; the core rechecks it. */
117
+ async function transitionEvidence(request) {
118
+ const task = await openMessageTask(request.task_root);
119
+ if (!task.ok)
120
+ throw new Error(task.code);
121
+ let ack = null;
122
+ let report = null;
123
+ for (const row of task.value.record.messages) {
124
+ if (row.state !== 'applied' ||
125
+ (row.type !== 'ACK' && row.type !== 'REPORT') ||
126
+ row.from.agent_id !== request.intent.to.agent_id ||
127
+ row.from.session_id !== request.intent.to.session_id ||
128
+ row.subtask_id !== request.intent.subtask_id ||
129
+ row.attempt !== request.intent.attempt)
130
+ continue;
131
+ const loaded = await readRegisteredMessageSafe(task.value, row.message_id);
132
+ if (!loaded.ok)
133
+ continue;
134
+ const message = loaded.value.message;
135
+ if (message.body?.['handoff_id'] !== request.intent.handoff_id ||
136
+ message.body?.['rollover_intent_id'] !== request.intent.intent_id ||
137
+ message.body?.['rollover_generation'] !== request.intent.generation ||
138
+ message.body?.['input_revision'] !== request.intent.input_revision)
139
+ continue;
140
+ if (row.type === 'ACK')
141
+ ack = row.message_id;
142
+ else
143
+ report = row.message_id;
144
+ }
145
+ return {
146
+ ...request,
147
+ evidence: { ack_message_id: ack, first_work_report_id: report },
148
+ };
149
+ }
150
+ /** One supported event advances one bounded transition. Existing transition effects remain authoritative. */
151
+ export async function tickAutomaticHandoff(config, runtime, dependencies = {}) {
152
+ const result = (status, code, transition = null, request) => ({
153
+ schema: AUTO_HANDOFF_SCHEMA,
154
+ status,
155
+ code,
156
+ transition,
157
+ ...(request ? { request } : {}),
158
+ });
159
+ let task = null;
160
+ let entry = null;
161
+ try {
162
+ if (config.schema !== AUTO_HANDOFF_SCHEMA ||
163
+ !/^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$/.test(config.id) ||
164
+ !Number.isFinite(config.thresholdPercent) ||
165
+ config.thresholdPercent <= 0 ||
166
+ config.thresholdPercent >= 100 ||
167
+ !path.isAbsolute(config.workspaceRoot) ||
168
+ !config.nextAction ||
169
+ !config.checkpoint.objective ||
170
+ !Array.isArray(config.checkpoint.acceptance) ||
171
+ config.checkpoint.acceptance.length === 0 ||
172
+ config.checkpoint.acceptance.some((item) => typeof item !== 'string' || !item.trim()))
173
+ return result('blocked', 'automatic_handoff_config_invalid');
174
+ const loaded = await openTaskStore(config.transition.task_root);
175
+ if (!loaded.ok)
176
+ return result('blocked', loaded.code);
177
+ task = loaded.value;
178
+ const digest = `sha256:${crypto.createHash('sha256').update(canonicalJson(config)).digest('hex')}`;
179
+ entry = entries(task.record).find((row) => row.id === config.id) ?? null;
180
+ if (entry && entry.config_digest !== digest)
181
+ return result('blocked', 'automatic_handoff_config_conflict');
182
+ if (entry?.stage === 'capture_reserved' ||
183
+ entry?.stage === 'reconcile_required')
184
+ return result('reconcile_required', entry.code ?? 'summary_capture_outcome_unknown');
185
+ if (!entry) {
186
+ const observed = runtime.observe();
187
+ if (observed.contextPercent === null)
188
+ return result('waiting', 'native_context_usage_unavailable');
189
+ if (!Number.isFinite(observed.contextPercent) ||
190
+ observed.contextPercent < 0 ||
191
+ observed.contextPercent > 100)
192
+ return result('blocked', 'native_context_usage_invalid');
193
+ if (observed.contextPercent < config.thresholdPercent)
194
+ return result('below-threshold', null);
195
+ if (!captureIdentityMatches(task.record, config, runtime))
196
+ return result('blocked', 'automatic_handoff_source_mismatch');
197
+ if (runtime.canCaptureSummary && !runtime.canCaptureSummary())
198
+ return result('waiting', 'native_compaction_not_ready');
199
+ entry = {
200
+ id: config.id,
201
+ config_digest: digest,
202
+ stage: 'capture_reserved',
203
+ request: null,
204
+ code: null,
205
+ };
206
+ task = await storeEntry(task, entry, true, (record) => captureIdentityMatches(record, config, runtime));
207
+ const captured = await runtime.captureSummary(config.id);
208
+ if (!captured.summary.trim() || captured.summary.length > 128 * 1024)
209
+ throw new Error('native_handoff_summary_missing_or_oversized');
210
+ let transcriptArtifact = null;
211
+ if (captured.sessionFile) {
212
+ const before = fs.lstatSync(captured.sessionFile);
213
+ const source = readBoundedFile(captured.sessionFile, 8 * 1024 * 1024);
214
+ const after = fs.lstatSync(captured.sessionFile);
215
+ if (!source.ok ||
216
+ before.dev !== after.dev ||
217
+ before.ino !== after.ino ||
218
+ before.size !== after.size ||
219
+ before.mtimeMs !== after.mtimeMs)
220
+ throw new Error('native_transcript_capture_unstable');
221
+ const header = JSON.parse(source.text.split('\n', 1)[0]);
222
+ if (header.type !== 'session' ||
223
+ header.id !== observed.native.sessionId ||
224
+ header.cwd !== observed.cwd)
225
+ throw new Error('native_transcript_identity_mismatch');
226
+ const destination = path.join(continuityTaskPaths(config.workspaceRoot, config.checkpoint.taskId)
227
+ .taskDir, 'native-context', `${config.id}.jsonl`);
228
+ const written = await writeContinuityBytes(config.workspaceRoot, config.checkpoint.taskId, destination, Buffer.from(source.text), true);
229
+ if (!written.ok)
230
+ throw new Error(written.code);
231
+ transcriptArtifact = path
232
+ .relative(config.workspaceRoot, destination)
233
+ .split(path.sep)
234
+ .join('/');
235
+ }
236
+ const summaryParts = captured.summary.match(/[\s\S]{1,4000}/g) ?? [];
237
+ const checkpoint = await new CheckpointService(config.workspaceRoot).save({
238
+ ...config.checkpoint,
239
+ authorSession: observed.native.sessionId,
240
+ attempted: [
241
+ ...(config.checkpoint.attempted ?? []),
242
+ ...summaryParts.map((part, i) => `Native handoff context summary (${i + 1}/${summaryParts.length}): ${part}`),
243
+ ],
244
+ // Native compaction is lossy. Retain its complete source as a private,
245
+ // digest-verified checkpoint artifact instead of relabeling the summary.
246
+ artifacts: [
247
+ ...(config.checkpoint.artifacts ?? []),
248
+ ...(transcriptArtifact ? [transcriptArtifact] : []),
249
+ ],
250
+ contextCompleteness: captured.complete || transcriptArtifact ? 'complete' : 'partial',
251
+ nativeRefs: [
252
+ {
253
+ harness: 'pi',
254
+ sessionId: observed.native.sessionId,
255
+ runId: config.id,
256
+ },
257
+ ],
258
+ });
259
+ if (!checkpoint.ok ||
260
+ !checkpoint.checkpoint ||
261
+ !checkpoint.checkpointPath)
262
+ throw new Error('automatic_checkpoint_capture_incomplete');
263
+ const inventory = await runtime.inventory();
264
+ const checkpointBytes = readBoundedFile(checkpoint.checkpointPath, 16 * 1024 * 1024);
265
+ if (!checkpointBytes.ok)
266
+ throw new Error('automatic_checkpoint_unreadable');
267
+ const current = await openTaskStore(config.transition.task_root);
268
+ if (!current.ok ||
269
+ !captureIdentityMatches(current.value.record, config, runtime))
270
+ throw new Error('automatic_handoff_authority_changed');
271
+ task = current.value;
272
+ const intent = config.transition.intent;
273
+ const bundle = await saveHandoffBundle({
274
+ root: config.workspaceRoot,
275
+ continuityTaskId: config.checkpoint.taskId,
276
+ bundleId: config.bundleId,
277
+ checkpoint: {
278
+ checkpointId: checkpoint.checkpoint.checkpointId,
279
+ taskId: checkpoint.checkpoint.taskId,
280
+ workspaceId: checkpoint.checkpoint.workspaceId,
281
+ ref: path
282
+ .relative(continuityTaskPaths(config.workspaceRoot, config.checkpoint.taskId).taskDir, checkpoint.checkpointPath)
283
+ .split(path.sep)
284
+ .join('/'),
285
+ digest: checkpointBytes.digest,
286
+ authorSession: observed.native.sessionId,
287
+ contextCompleteness: checkpoint.checkpoint.contextCompleteness,
288
+ },
289
+ collaboration: {
290
+ taskId: task.record.task_id,
291
+ attempt: intent.attempt,
292
+ ownerEpoch: intent.coordinator_epoch,
293
+ subtaskId: intent.subtask_id,
294
+ inputRevision: intent.input_revision,
295
+ association: task.record.task_id === config.checkpoint.taskId
296
+ ? null
297
+ : `Explicit automatic-handoff configuration ${config.id}`,
298
+ },
299
+ sourceNativeSession: observed.native,
300
+ handoff: {
301
+ claims: intent.claims.map((expected) => {
302
+ const claim = task.record.claims.find((candidate) => candidate.claim_id === expected.claim_id);
303
+ return {
304
+ claimId: claim.claim_id,
305
+ resource: claim.key,
306
+ resourceEpoch: expected.resource_epoch,
307
+ holder: claim.holder.agent_id,
308
+ };
309
+ }),
310
+ claimsCompleteness: 'complete',
311
+ pendingTools: pending(inventory.inflight, inventory.completeness),
312
+ pendingMessages: pending(inventory.pending_messages ?? [], inventory.pending_messages ? inventory.completeness : 'unknown'),
313
+ pendingApprovals: pending(inventory.pending_approvals, inventory.completeness),
314
+ nextAction: config.nextAction,
315
+ recovery: [
316
+ 'Resume only through the registered transition and verified task authority.',
317
+ ],
318
+ executionAuthority: 'none',
319
+ advisory: true,
320
+ },
321
+ limitations: [
322
+ 'Native model summaries are lossy; saved context does not grant execution.',
323
+ ],
324
+ });
325
+ if (!bundle.ok)
326
+ throw new Error(bundle.code);
327
+ entry = {
328
+ ...entry,
329
+ stage: 'prepared',
330
+ request: {
331
+ ...config.transition,
332
+ ...(runtime.prepareBootstrapAdmission
333
+ ? {
334
+ bootstrap_request: await runtime.prepareBootstrapAdmission(config.transition.bootstrap_request),
335
+ }
336
+ : {}),
337
+ bundle: {
338
+ root: config.workspaceRoot,
339
+ continuity_task_id: config.checkpoint.taskId,
340
+ bundle_id: bundle.value.bundleId,
341
+ digest: bundle.value.digest,
342
+ },
343
+ },
344
+ };
345
+ task = await storeEntry(task, entry, false);
346
+ }
347
+ if (!entry.request)
348
+ return result('reconcile_required', 'automatic_handoff_request_missing');
349
+ const request = await transitionEvidence(entry.request);
350
+ prepareManagedHandoffContextReference(request);
351
+ const transition = await applySessionTransition(request, dependencies);
352
+ task = await reopenTask(task);
353
+ entry = {
354
+ ...entry,
355
+ stage: transition.ok && transition.stage === 'task_retired'
356
+ ? 'complete'
357
+ : 'active',
358
+ code: transition.code,
359
+ };
360
+ task = await storeEntry(task, entry, false);
361
+ return result(entry.stage === 'complete'
362
+ ? 'complete'
363
+ : transition.ok
364
+ ? 'progressed'
365
+ : 'waiting', transition.code, transition, request);
366
+ }
367
+ catch (error) {
368
+ if (task && entry?.stage === 'capture_reserved') {
369
+ try {
370
+ await storeEntry(task, {
371
+ ...entry,
372
+ stage: 'reconcile_required',
373
+ code: 'summary_or_checkpoint_outcome_unknown',
374
+ }, false);
375
+ }
376
+ catch {
377
+ /* retained reservation still prevents recapture */
378
+ }
379
+ }
380
+ return result('reconcile_required', error instanceof Error && /^[A-Za-z0-9_-]+$/.test(error.message)
381
+ ? error.message
382
+ : 'automatic_handoff_failed');
383
+ }
384
+ }
@@ -0,0 +1,57 @@
1
+ export declare const COLLAB_BINDINGS_SCHEMA = "pappra/collaboration-bindings/1";
2
+ export declare const COLLAB_BINDING_RESULT_SCHEMA = "pappra/collaboration-binding-result/1";
3
+ export interface BindingEntry {
4
+ readonly alias: string;
5
+ readonly record: string;
6
+ readonly record_realpath: string;
7
+ readonly task_root: string;
8
+ readonly domain_root: string;
9
+ readonly protocol_task_id: string;
10
+ readonly domain_id: string;
11
+ readonly record_created_at: string;
12
+ readonly bound_at: string;
13
+ }
14
+ export interface BindingTombstone {
15
+ readonly alias: string;
16
+ readonly at: string;
17
+ readonly previous: BindingEntry | null;
18
+ }
19
+ export interface BindingServiceFailure {
20
+ readonly ok: false;
21
+ readonly code: string;
22
+ readonly message: string;
23
+ readonly nextAction: string | null;
24
+ readonly details?: readonly string[];
25
+ }
26
+ export type BindingServiceResult<T> = {
27
+ readonly ok: true;
28
+ readonly value: T;
29
+ } | BindingServiceFailure;
30
+ export interface TargetIdentity {
31
+ readonly record: string;
32
+ readonly record_realpath: string;
33
+ readonly task_root: string;
34
+ readonly domain_root: string;
35
+ readonly protocol_task_id: string;
36
+ readonly domain_id: string;
37
+ readonly record_created_at: string;
38
+ }
39
+ export interface TargetSnapshot extends TargetIdentity {
40
+ readonly state_revision: number;
41
+ readonly coordinator_epoch: number | null;
42
+ readonly dispatch_frozen: boolean;
43
+ readonly attempts: readonly Record<string, unknown>[];
44
+ readonly attempt_count: number;
45
+ readonly truncated: boolean;
46
+ }
47
+ export interface BindingCommandOptions {
48
+ readonly root: string | null;
49
+ readonly taskId: string | null;
50
+ readonly record: string | null;
51
+ readonly roots: string | null;
52
+ readonly apply: boolean;
53
+ }
54
+ export declare function listBindings(options: BindingCommandOptions): Promise<BindingServiceResult<Record<string, unknown>>>;
55
+ export declare function resolveBinding(options: BindingCommandOptions): Promise<BindingServiceResult<Record<string, unknown>>>;
56
+ export declare function bindAlias(options: BindingCommandOptions): Promise<BindingServiceResult<Record<string, unknown>>>;
57
+ export declare function unbindAlias(options: BindingCommandOptions): Promise<BindingServiceResult<Record<string, unknown>>>;