@caupulican/pi-adaptative 0.81.41 → 0.81.42

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 (237) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/dist/bundled-resources/runtimes/pi-shell-engine/commands/text.py +5 -1
  3. package/dist/bundled-resources/runtimes/pi-shell-engine/context.py +3 -3
  4. package/dist/bundled-resources/runtimes/pi-shell-engine/errors.py +8 -0
  5. package/dist/bundled-resources/runtimes/pi-shell-engine/exec.py +26 -3
  6. package/dist/bundled-resources/runtimes/pi-shell-engine/expand.py +3 -0
  7. package/dist/bundled-resources/runtimes/pi-shell-engine/main.py +4 -1
  8. package/dist/bundled-resources/runtimes/pi-shell-engine/state.py +2 -1
  9. package/dist/bundled-resources/runtimes/pi-shell-engine/tokens.py +2 -0
  10. package/dist/core/agent-paths.d.ts +32 -0
  11. package/dist/core/agent-paths.d.ts.map +1 -1
  12. package/dist/core/agent-paths.js +65 -0
  13. package/dist/core/agent-paths.js.map +1 -1
  14. package/dist/core/agent-session-contracts.d.ts +19 -1
  15. package/dist/core/agent-session-contracts.d.ts.map +1 -1
  16. package/dist/core/agent-session-contracts.js.map +1 -1
  17. package/dist/core/agent-session.d.ts.map +1 -1
  18. package/dist/core/agent-session.js +4 -9
  19. package/dist/core/agent-session.js.map +1 -1
  20. package/dist/core/autonomy/contracts.d.ts +2 -0
  21. package/dist/core/autonomy/contracts.d.ts.map +1 -1
  22. package/dist/core/autonomy/contracts.js.map +1 -1
  23. package/dist/core/autonomy/envelope-enforcement.d.ts.map +1 -1
  24. package/dist/core/autonomy/envelope-enforcement.js +4 -9
  25. package/dist/core/autonomy/envelope-enforcement.js.map +1 -1
  26. package/dist/core/autonomy/lane-tool-surface.d.ts +3 -1
  27. package/dist/core/autonomy/lane-tool-surface.d.ts.map +1 -1
  28. package/dist/core/autonomy/lane-tool-surface.js +17 -4
  29. package/dist/core/autonomy/lane-tool-surface.js.map +1 -1
  30. package/dist/core/autonomy/path-scope.d.ts +14 -0
  31. package/dist/core/autonomy/path-scope.d.ts.map +1 -1
  32. package/dist/core/autonomy/path-scope.js +37 -6
  33. package/dist/core/autonomy/path-scope.js.map +1 -1
  34. package/dist/core/background-lane-controller.d.ts +27 -1
  35. package/dist/core/background-lane-controller.d.ts.map +1 -1
  36. package/dist/core/background-lane-controller.js +32 -1
  37. package/dist/core/background-lane-controller.js.map +1 -1
  38. package/dist/core/delegation/managed-lane-controller.d.ts +11 -1
  39. package/dist/core/delegation/managed-lane-controller.d.ts.map +1 -1
  40. package/dist/core/delegation/managed-lane-controller.js +84 -41
  41. package/dist/core/delegation/managed-lane-controller.js.map +1 -1
  42. package/dist/core/delegation/session-worker-claim.d.ts.map +1 -1
  43. package/dist/core/delegation/session-worker-claim.js +4 -3
  44. package/dist/core/delegation/session-worker-claim.js.map +1 -1
  45. package/dist/core/delegation/worker-action-journal.d.ts +73 -0
  46. package/dist/core/delegation/worker-action-journal.d.ts.map +1 -0
  47. package/dist/core/delegation/worker-action-journal.js +297 -0
  48. package/dist/core/delegation/worker-action-journal.js.map +1 -0
  49. package/dist/core/delegation/worker-actions.d.ts +36 -1
  50. package/dist/core/delegation/worker-actions.d.ts.map +1 -1
  51. package/dist/core/delegation/worker-actions.js +171 -46
  52. package/dist/core/delegation/worker-actions.js.map +1 -1
  53. package/dist/core/delegation/worker-agent-control-coordinator.d.ts +75 -0
  54. package/dist/core/delegation/worker-agent-control-coordinator.d.ts.map +1 -0
  55. package/dist/core/delegation/worker-agent-control-coordinator.js +218 -0
  56. package/dist/core/delegation/worker-agent-control-coordinator.js.map +1 -0
  57. package/dist/core/delegation/worker-agent-control.d.ts +66 -0
  58. package/dist/core/delegation/worker-agent-control.d.ts.map +1 -0
  59. package/dist/core/delegation/worker-agent-control.js +163 -0
  60. package/dist/core/delegation/worker-agent-control.js.map +1 -0
  61. package/dist/core/delegation/worker-attempt-executor.d.ts +80 -0
  62. package/dist/core/delegation/worker-attempt-executor.d.ts.map +1 -0
  63. package/dist/core/delegation/worker-attempt-executor.js +343 -0
  64. package/dist/core/delegation/worker-attempt-executor.js.map +1 -0
  65. package/dist/core/delegation/worker-claim.d.ts +30 -0
  66. package/dist/core/delegation/worker-claim.d.ts.map +1 -1
  67. package/dist/core/delegation/worker-claim.js +205 -53
  68. package/dist/core/delegation/worker-claim.js.map +1 -1
  69. package/dist/core/delegation/worker-conversation-store.d.ts +116 -0
  70. package/dist/core/delegation/worker-conversation-store.d.ts.map +1 -0
  71. package/dist/core/delegation/worker-conversation-store.js +442 -0
  72. package/dist/core/delegation/worker-conversation-store.js.map +1 -0
  73. package/dist/core/delegation/worker-delegation-controller.d.ts +21 -5
  74. package/dist/core/delegation/worker-delegation-controller.d.ts.map +1 -1
  75. package/dist/core/delegation/worker-delegation-controller.js +386 -251
  76. package/dist/core/delegation/worker-delegation-controller.js.map +1 -1
  77. package/dist/core/delegation/worker-delegation-request.d.ts +14 -0
  78. package/dist/core/delegation/worker-delegation-request.d.ts.map +1 -1
  79. package/dist/core/delegation/worker-delegation-request.js.map +1 -1
  80. package/dist/core/delegation/worker-dispatch-scheduler.d.ts +4 -2
  81. package/dist/core/delegation/worker-dispatch-scheduler.d.ts.map +1 -1
  82. package/dist/core/delegation/worker-dispatch-scheduler.js +16 -6
  83. package/dist/core/delegation/worker-dispatch-scheduler.js.map +1 -1
  84. package/dist/core/delegation/worker-execution-policy.d.ts +2 -1
  85. package/dist/core/delegation/worker-execution-policy.d.ts.map +1 -1
  86. package/dist/core/delegation/worker-execution-policy.js +5 -7
  87. package/dist/core/delegation/worker-execution-policy.js.map +1 -1
  88. package/dist/core/delegation/worker-lifecycle.d.ts +44 -1
  89. package/dist/core/delegation/worker-lifecycle.d.ts.map +1 -1
  90. package/dist/core/delegation/worker-lifecycle.js +120 -0
  91. package/dist/core/delegation/worker-lifecycle.js.map +1 -1
  92. package/dist/core/delegation/worker-process-owner.d.ts +18 -0
  93. package/dist/core/delegation/worker-process-owner.d.ts.map +1 -0
  94. package/dist/core/delegation/worker-process-owner.js +54 -0
  95. package/dist/core/delegation/worker-process-owner.js.map +1 -0
  96. package/dist/core/delegation/worker-profile-resolver.d.ts +5 -1
  97. package/dist/core/delegation/worker-profile-resolver.d.ts.map +1 -1
  98. package/dist/core/delegation/worker-profile-resolver.js +8 -0
  99. package/dist/core/delegation/worker-profile-resolver.js.map +1 -1
  100. package/dist/core/delegation/worker-recovery-coordinator.d.ts +54 -0
  101. package/dist/core/delegation/worker-recovery-coordinator.d.ts.map +1 -0
  102. package/dist/core/delegation/worker-recovery-coordinator.js +181 -0
  103. package/dist/core/delegation/worker-recovery-coordinator.js.map +1 -0
  104. package/dist/core/delegation/worker-resource-catalog.d.ts +32 -0
  105. package/dist/core/delegation/worker-resource-catalog.d.ts.map +1 -0
  106. package/dist/core/delegation/worker-resource-catalog.js +116 -0
  107. package/dist/core/delegation/worker-resource-catalog.js.map +1 -0
  108. package/dist/core/delegation/worker-resource-materializer.d.ts +47 -0
  109. package/dist/core/delegation/worker-resource-materializer.d.ts.map +1 -0
  110. package/dist/core/delegation/worker-resource-materializer.js +137 -0
  111. package/dist/core/delegation/worker-resource-materializer.js.map +1 -0
  112. package/dist/core/delegation/worker-runner.d.ts +3 -1
  113. package/dist/core/delegation/worker-runner.d.ts.map +1 -1
  114. package/dist/core/delegation/worker-runner.js +189 -54
  115. package/dist/core/delegation/worker-runner.js.map +1 -1
  116. package/dist/core/delegation/worker-terminal-finalizer.d.ts +23 -0
  117. package/dist/core/delegation/worker-terminal-finalizer.d.ts.map +1 -0
  118. package/dist/core/delegation/worker-terminal-finalizer.js +12 -0
  119. package/dist/core/delegation/worker-terminal-finalizer.js.map +1 -0
  120. package/dist/core/delegation/worker-write-reservation-coordinator.d.ts +38 -0
  121. package/dist/core/delegation/worker-write-reservation-coordinator.d.ts.map +1 -0
  122. package/dist/core/delegation/worker-write-reservation-coordinator.js +107 -0
  123. package/dist/core/delegation/worker-write-reservation-coordinator.js.map +1 -0
  124. package/dist/core/delegation/worker-write-reservation.d.ts +90 -0
  125. package/dist/core/delegation/worker-write-reservation.d.ts.map +1 -0
  126. package/dist/core/delegation/worker-write-reservation.js +348 -0
  127. package/dist/core/delegation/worker-write-reservation.js.map +1 -0
  128. package/dist/core/models/model-endpoint.d.ts +3 -0
  129. package/dist/core/models/model-endpoint.d.ts.map +1 -0
  130. package/dist/core/models/model-endpoint.js +11 -0
  131. package/dist/core/models/model-endpoint.js.map +1 -0
  132. package/dist/core/orchestration/agent-resume.d.ts +2 -0
  133. package/dist/core/orchestration/agent-resume.d.ts.map +1 -1
  134. package/dist/core/orchestration/agent-resume.js +7 -0
  135. package/dist/core/orchestration/agent-resume.js.map +1 -1
  136. package/dist/core/orchestration/attempt-usage.d.ts +28 -0
  137. package/dist/core/orchestration/attempt-usage.d.ts.map +1 -0
  138. package/dist/core/orchestration/attempt-usage.js +168 -0
  139. package/dist/core/orchestration/attempt-usage.js.map +1 -0
  140. package/dist/core/orchestration/capability-gateway.d.ts +19 -1
  141. package/dist/core/orchestration/capability-gateway.d.ts.map +1 -1
  142. package/dist/core/orchestration/capability-gateway.js +128 -28
  143. package/dist/core/orchestration/capability-gateway.js.map +1 -1
  144. package/dist/core/orchestration/contracts.d.ts +35 -0
  145. package/dist/core/orchestration/contracts.d.ts.map +1 -1
  146. package/dist/core/orchestration/contracts.js +17 -0
  147. package/dist/core/orchestration/contracts.js.map +1 -1
  148. package/dist/core/orchestration/delegation-ledger.d.ts +17 -2
  149. package/dist/core/orchestration/delegation-ledger.d.ts.map +1 -1
  150. package/dist/core/orchestration/delegation-ledger.js +78 -3
  151. package/dist/core/orchestration/delegation-ledger.js.map +1 -1
  152. package/dist/core/orchestration/event-store.d.ts +1 -0
  153. package/dist/core/orchestration/event-store.d.ts.map +1 -1
  154. package/dist/core/orchestration/event-store.js +78 -38
  155. package/dist/core/orchestration/event-store.js.map +1 -1
  156. package/dist/core/orchestration/profile-registry.d.ts.map +1 -1
  157. package/dist/core/orchestration/profile-registry.js +81 -41
  158. package/dist/core/orchestration/profile-registry.js.map +1 -1
  159. package/dist/core/orchestration/profile-store.d.ts.map +1 -1
  160. package/dist/core/orchestration/profile-store.js +18 -4
  161. package/dist/core/orchestration/profile-store.js.map +1 -1
  162. package/dist/core/orchestration/risk-budget.d.ts +2 -0
  163. package/dist/core/orchestration/risk-budget.d.ts.map +1 -1
  164. package/dist/core/orchestration/risk-budget.js +26 -0
  165. package/dist/core/orchestration/risk-budget.js.map +1 -1
  166. package/dist/core/orchestration/task-runtime.d.ts +13 -1
  167. package/dist/core/orchestration/task-runtime.d.ts.map +1 -1
  168. package/dist/core/orchestration/task-runtime.js +127 -16
  169. package/dist/core/orchestration/task-runtime.js.map +1 -1
  170. package/dist/core/orchestration/worker-execution-contract.d.ts +3 -1
  171. package/dist/core/orchestration/worker-execution-contract.d.ts.map +1 -1
  172. package/dist/core/orchestration/worker-execution-contract.js +75 -23
  173. package/dist/core/orchestration/worker-execution-contract.js.map +1 -1
  174. package/dist/core/orchestration/worker-result-adapter.d.ts +9 -3
  175. package/dist/core/orchestration/worker-result-adapter.d.ts.map +1 -1
  176. package/dist/core/orchestration/worker-result-adapter.js +167 -14
  177. package/dist/core/orchestration/worker-result-adapter.js.map +1 -1
  178. package/dist/core/reflection-controller.d.ts +1 -1
  179. package/dist/core/reflection-controller.d.ts.map +1 -1
  180. package/dist/core/reflection-controller.js +90 -54
  181. package/dist/core/reflection-controller.js.map +1 -1
  182. package/dist/core/research/evidence-bundle.d.ts +20 -0
  183. package/dist/core/research/evidence-bundle.d.ts.map +1 -1
  184. package/dist/core/research/evidence-bundle.js +173 -69
  185. package/dist/core/research/evidence-bundle.js.map +1 -1
  186. package/dist/core/runtime-builder.d.ts +7 -0
  187. package/dist/core/runtime-builder.d.ts.map +1 -1
  188. package/dist/core/runtime-builder.js +15 -1
  189. package/dist/core/runtime-builder.js.map +1 -1
  190. package/dist/core/session-artifact-bundle.d.ts +35 -0
  191. package/dist/core/session-artifact-bundle.d.ts.map +1 -0
  192. package/dist/core/session-artifact-bundle.js +61 -0
  193. package/dist/core/session-artifact-bundle.js.map +1 -0
  194. package/dist/core/tools/delegate-status.d.ts +6 -1
  195. package/dist/core/tools/delegate-status.d.ts.map +1 -1
  196. package/dist/core/tools/delegate-status.js +100 -18
  197. package/dist/core/tools/delegate-status.js.map +1 -1
  198. package/dist/core/tools/delegate.d.ts +9 -1
  199. package/dist/core/tools/delegate.d.ts.map +1 -1
  200. package/dist/core/tools/delegate.js +323 -61
  201. package/dist/core/tools/delegate.js.map +1 -1
  202. package/dist/core/tools/run-process.d.ts +1 -1
  203. package/dist/core/tools/run-process.d.ts.map +1 -1
  204. package/dist/core/tools/run-process.js +69 -9
  205. package/dist/core/tools/run-process.js.map +1 -1
  206. package/dist/core/tools/shell-contract-router.d.ts.map +1 -1
  207. package/dist/core/tools/shell-contract-router.js +12 -5
  208. package/dist/core/tools/shell-contract-router.js.map +1 -1
  209. package/dist/core/util/bounded-file.d.ts +15 -0
  210. package/dist/core/util/bounded-file.d.ts.map +1 -0
  211. package/dist/core/util/bounded-file.js +120 -0
  212. package/dist/core/util/bounded-file.js.map +1 -0
  213. package/dist/core/util/bounded-jsonl.d.ts.map +1 -1
  214. package/dist/core/util/bounded-jsonl.js +119 -9
  215. package/dist/core/util/bounded-jsonl.js.map +1 -1
  216. package/dist/core/util/bounded-value.d.ts +3 -0
  217. package/dist/core/util/bounded-value.d.ts.map +1 -0
  218. package/dist/core/util/bounded-value.js +12 -0
  219. package/dist/core/util/bounded-value.js.map +1 -0
  220. package/dist/core/util/value-guards.d.ts +2 -0
  221. package/dist/core/util/value-guards.d.ts.map +1 -1
  222. package/dist/core/util/value-guards.js +5 -0
  223. package/dist/core/util/value-guards.js.map +1 -1
  224. package/dist/modes/interactive/components/session-selector.d.ts.map +1 -1
  225. package/dist/modes/interactive/components/session-selector.js +27 -44
  226. package/dist/modes/interactive/components/session-selector.js.map +1 -1
  227. package/docs/tool-repair.md +3 -0
  228. package/docs/windows.md +4 -2
  229. package/examples/extensions/custom-provider-anthropic/package-lock.json +2 -2
  230. package/examples/extensions/custom-provider-anthropic/package.json +1 -1
  231. package/examples/extensions/custom-provider-gitlab-duo/package.json +1 -1
  232. package/examples/extensions/sandbox/package-lock.json +2 -2
  233. package/examples/extensions/sandbox/package.json +1 -1
  234. package/examples/extensions/with-deps/package-lock.json +2 -2
  235. package/examples/extensions/with-deps/package.json +1 -1
  236. package/npm-shrinkwrap.json +12 -12
  237. package/package.json +4 -4
@@ -1 +1 @@
1
- {"version":3,"file":"managed-lane-controller.js","sourceRoot":"","sources":["../../../src/core/delegation/managed-lane-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { CapabilityEnvelope, WorkerClaim, WorkerClaimStatus, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport { getPrivateLaneDeniedPaths } from \"../autonomy/lane-private-paths.ts\";\nimport { isLaneTerminalStatus, type LaneRecord, type LaneTerminalStatus } from \"../autonomy/lane-tracker.ts\";\nimport { appendLaneRecordSnapshot, getLatestLaneRecordSnapshots } from \"../autonomy/session-lane-record.ts\";\nimport type { ManagedLaneDispatch, ManagedLaneEvent } from \"../extensions/types.ts\";\nimport type { GoalState } from \"../goals/goal-state.ts\";\nimport type { ExecutionGrant } from \"../orchestration/contracts.ts\";\nimport { createWorkerResultContract } from \"../orchestration/worker-result-adapter.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport { getActiveSessionBranchEntries } from \"../session-snapshot.ts\";\nimport { reviewManagedLaneChangedFiles } from \"./worker-claim.ts\";\nimport { compileManagedProcessExecutionGrant } from \"./worker-execution-policy.ts\";\nimport type { WorkerLifecycle } from \"./worker-lifecycle.ts\";\n\nconst LEGACY_MANAGED_LEASE_TTL_MS = 24 * 60 * 60 * 1_000;\nconst LEGACY_MANAGED_READ_TOOLS = [\"read\", \"grep\", \"find\", \"ls\"] as const;\n\nexport function resolveManagedLaneTerminalStatus(status: string | undefined): LaneTerminalStatus {\n\tif (isLaneTerminalStatus(status)) return status;\n\tswitch (status) {\n\t\tcase \"done\":\n\t\tcase \"completed\":\n\t\t\treturn \"succeeded\";\n\t\tcase \"blocked\":\n\t\t\treturn \"failed\";\n\t\tcase \"dismissed\":\n\t\tcase \"cancelled\":\n\t\t\treturn \"canceled\";\n\t\tdefault:\n\t\t\treturn \"failed\";\n\t}\n}\n\nexport function mapManagedLaneTerminalStatus(status: LaneTerminalStatus): WorkerClaimStatus {\n\tswitch (status) {\n\t\tcase \"succeeded\":\n\t\t\treturn \"completed\";\n\t\tcase \"canceled\":\n\t\t\treturn \"cancelled\";\n\t\tcase \"failed\":\n\t\tcase \"timeout\":\n\t\tcase \"budget_exhausted\":\n\t\t\treturn \"failed\";\n\t}\n}\n\nexport interface ManagedLaneControllerDeps {\n\tisDisposed(): boolean;\n\tgetAgentDir(): string;\n\tgetCwd(): string;\n\tgetSessionManager(): SessionManager;\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tgetCapabilityEnvelope(): CapabilityEnvelope | undefined;\n\tsaveWorkerClaimSnapshot(claim: WorkerClaim, request?: WorkerRequest): string;\n}\n\n/** Out-of-process adapter over the same durable worker lifecycle used by in-process delegation. */\nexport class ManagedLaneController {\n\tprivate readonly deps: ManagedLaneControllerDeps;\n\tprivate readonly lifecycle: WorkerLifecycle;\n\tprivate readonly recordTerminal: (record: LaneRecord, durableNotificationId: string) => void;\n\tprivate readonly deregisterByLane = new Map<string, () => void>();\n\tprivate hydrated = false;\n\n\tconstructor(\n\t\tdeps: ManagedLaneControllerDeps,\n\t\tlifecycle: WorkerLifecycle,\n\t\trecordTerminal: (record: LaneRecord, durableNotificationId: string) => void,\n\t) {\n\t\tthis.deps = deps;\n\t\tthis.lifecycle = lifecycle;\n\t\tthis.recordTerminal = recordTerminal;\n\t}\n\n\tensureHydrated(): void {\n\t\tif (this.hydrated) return;\n\t\tthis.hydrated = true;\n\t\tconst durableIds = new Set(this.lifecycle.getManagedRecords().map((record) => record.laneId));\n\t\tfor (const legacy of getLatestLaneRecordSnapshots(getActiveSessionBranchEntries(this.deps.getSessionManager()))) {\n\t\t\tif (\n\t\t\t\tlegacy.type !== \"tmux-worker\" ||\n\t\t\t\t(legacy.status !== \"queued\" && legacy.status !== \"running\") ||\n\t\t\t\tdurableIds.has(legacy.laneId)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.lifecycle.prepareManaged({\n\t\t\t\tlaneId: legacy.laneId,\n\t\t\t\tdispatchSequence: 1,\n\t\t\t\tinstructions: legacy.label ?? `Resume externally managed lane ${legacy.laneId}`,\n\t\t\t\tprofileId: legacy.profileId ?? \"legacy-managed-process\",\n\t\t\t\tprovider: \"legacy\",\n\t\t\t\tauthorizationId: `legacy-session-lane:${legacy.laneId}`,\n\t\t\t\trole: \"implementer\",\n\t\t\t\triskBudget: { maxAttempts: 1, maxWallClockMs: LEGACY_MANAGED_LEASE_TTL_MS },\n\t\t\t\tleaseTtlMs: LEGACY_MANAGED_LEASE_TTL_MS,\n\t\t\t\tcompileGrant: (target) =>\n\t\t\t\t\tthis.compileGrant(target, legacy.laneId, {\n\t\t\t\t\t\tsequence: 1,\n\t\t\t\t\t\tinstructions: legacy.label ?? `Resume externally managed lane ${legacy.laneId}`,\n\t\t\t\t\t\tprofileId: legacy.profileId ?? \"legacy-managed-process\",\n\t\t\t\t\t\tprovider: \"legacy\",\n\t\t\t\t\t\tauthorizationId: `legacy-session-lane:${legacy.laneId}`,\n\t\t\t\t\t\tauthorizationKind: \"legacy-recovery\",\n\t\t\t\t\t\tallowedTools: LEGACY_MANAGED_READ_TOOLS,\n\t\t\t\t\t\twritePaths: [],\n\t\t\t\t\t\tleaseTtlMs: LEGACY_MANAGED_LEASE_TTL_MS,\n\t\t\t\t\t}),\n\t\t\t\t...(legacy.worktreeLaneKey ? { worktreeLaneKey: legacy.worktreeLaneKey } : {}),\n\t\t\t});\n\t\t}\n\t\tfor (const record of this.lifecycle.getManagedRecords()) {\n\t\t\tif (record.status === \"queued\" || record.status === \"running\") this.ensureRegistration(record.laneId);\n\t\t}\n\t}\n\n\tresolve(callerLaneId: string): string | undefined {\n\t\tthis.ensureHydrated();\n\t\tconst record = this.lifecycle.getManagedRecord(callerLaneId);\n\t\treturn record && (record.status === \"queued\" || record.status === \"running\") ? callerLaneId : undefined;\n\t}\n\n\trecord(event: ManagedLaneEvent): LaneRecord | undefined {\n\t\tif (this.deps.isDisposed()) return undefined;\n\t\tthis.ensureHydrated();\n\t\tif (event.phase === \"dispatch\") {\n\t\t\tconst goal = this.deps.getGoalStateSnapshot();\n\t\t\tconst prepared = this.lifecycle.prepareManaged({\n\t\t\t\tlaneId: event.laneId,\n\t\t\t\tdispatchSequence: event.dispatch.sequence,\n\t\t\t\tinstructions: event.dispatch.instructions,\n\t\t\t\tprofileId: event.dispatch.profileId,\n\t\t\t\tprovider: event.dispatch.provider,\n\t\t\t\tauthorizationId: event.dispatch.authorizationId,\n\t\t\t\tleaseTtlMs: event.dispatch.leaseTtlMs,\n\t\t\t\tcompileGrant: (target) => this.compileGrant(target, event.laneId, event.dispatch),\n\t\t\t\trole: \"implementer\",\n\t\t\t\triskBudget: { maxAttempts: 1, maxWallClockMs: event.dispatch.leaseTtlMs },\n\t\t\t\t...(goal && Array.isArray(goal.requirements) && (!event.goalId || goal.goalId === event.goalId)\n\t\t\t\t\t? { goal }\n\t\t\t\t\t: {}),\n\t\t\t\t...(event.goalId ? { goalId: event.goalId } : {}),\n\t\t\t\t...(event.worktreeLaneKey ? { worktreeLaneKey: event.worktreeLaneKey } : {}),\n\t\t\t});\n\t\t\tif (!prepared.created) return undefined;\n\t\t\tthis.ensureRegistration(event.laneId);\n\t\t\tappendLaneRecordSnapshot(this.deps.getSessionManager(), prepared.record);\n\t\t\treturn prepared.record;\n\t\t}\n\n\t\tconst attempt = this.lifecycle.getManagedAttempt(event.laneId);\n\t\tconst handle = this.lifecycle.getManagedHandle(event.laneId);\n\t\tif (!attempt || !handle || (attempt.status !== \"leased\" && attempt.status !== \"running\")) return undefined;\n\t\tconst resolvedStatus = resolveManagedLaneTerminalStatus(event.status);\n\t\tconst changedFiles = event.changedFiles ? [...event.changedFiles] : [];\n\t\tconst review = reviewManagedLaneChangedFiles({\n\t\t\tchangedFiles,\n\t\t\tenvelope: this.deps.getCapabilityEnvelope() ?? {},\n\t\t\tcwd: this.deps.getCwd(),\n\t\t});\n\t\tconst claim: WorkerClaim = {\n\t\t\trequestId: event.laneId,\n\t\t\tstatus: mapManagedLaneTerminalStatus(resolvedStatus),\n\t\t\tsummary: `Managed worker lane ${event.laneId} reported terminal status \"${event.status ?? \"unknown\"}\"${\n\t\t\t\tevent.reasonCode ? ` (${event.reasonCode})` : \"\"\n\t\t\t}.${review.reviewRequired ? ` Changed files require parent review (${review.reasonCode}).` : \"\"}`,\n\t\t\tchangedFiles,\n\t\t\tparentReviewRequired: review.reviewRequired,\n\t\t\tcreatedAt: new Date().toISOString(),\n\t\t};\n\t\tlet record: LaneRecord | undefined;\n\t\ttry {\n\t\t\tthis.deps.saveWorkerClaimSnapshot(claim);\n\t\t} finally {\n\t\t\ttry {\n\t\t\t\tconst usage = event.usage;\n\t\t\t\trecord = this.lifecycle.finish(\n\t\t\t\t\tcreateWorkerResultContract({\n\t\t\t\t\t\thandle,\n\t\t\t\t\t\tclaim,\n\t\t\t\t\t\taccepted: resolvedStatus === \"succeeded\" && !review.reviewRequired,\n\t\t\t\t\t\tcostUsd: usage?.cost.total,\n\t\t\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\t\t\t...(usage\n\t\t\t\t\t\t\t? {\n\t\t\t\t\t\t\t\t\tinputTokens: usage.input,\n\t\t\t\t\t\t\t\t\toutputTokens: usage.output,\n\t\t\t\t\t\t\t\t\ttotalTokens: usage.totalTokens,\n\t\t\t\t\t\t\t\t}\n\t\t\t\t\t\t\t: {}),\n\t\t\t\t\t\twallClockMs: Math.max(0, Date.now() - Date.parse(attempt.createdAt)),\n\t\t\t\t\t\ttoolCalls: 0,\n\t\t\t\t\t\treasonCode: review.reviewRequired\n\t\t\t\t\t\t\t? `parent_review_required:${review.reasonCode}`\n\t\t\t\t\t\t\t: (event.reasonCode ?? `managed_worker_${resolvedStatus}`),\n\t\t\t\t\t}),\n\t\t\t\t);\n\t\t\t\tconst notification = this.lifecycle.getTerminalNotification(event.laneId);\n\t\t\t\tif (notification) this.recordTerminal(record, notification.notificationId);\n\t\t\t\tappendLaneRecordSnapshot(this.deps.getSessionManager(), record);\n\t\t\t} finally {\n\t\t\t\tthis.releaseRegistration(event.laneId);\n\t\t\t}\n\t\t}\n\t\treturn record;\n\t}\n\n\trelease(): void {\n\t\tfor (const deregister of this.deregisterByLane.values()) deregister();\n\t\tthis.deregisterByLane.clear();\n\t}\n\n\tprivate ensureRegistration(laneId: string): void {\n\t\tif (this.deregisterByLane.has(laneId)) return;\n\t\tthis.deregisterByLane.set(laneId, registerInFlightWork(this.deps.getAgentDir(), \"lane\", `tmux:${laneId}`));\n\t}\n\n\tprivate releaseRegistration(laneId: string): void {\n\t\tthis.deregisterByLane.get(laneId)?.();\n\t\tthis.deregisterByLane.delete(laneId);\n\t}\n\n\tprivate compileGrant(\n\t\ttarget: { objectiveId: string; taskId: string; attemptId: string },\n\t\tlaneId: string,\n\t\tdispatch: ManagedLaneDispatch,\n\t): ExecutionGrant {\n\t\tconst compiled = compileManagedProcessExecutionGrant({\n\t\t\ttarget,\n\t\t\tlaneId,\n\t\t\tauthorizationId: dispatch.authorizationId,\n\t\t\trole: \"implementer\",\n\t\t\tallowedTools: dispatch.allowedTools,\n\t\t\twritePaths: dispatch.writePaths,\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tdeniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),\n\t\t\tbudget: {\n\t\t\t\tmaxAttempts: 1,\n\t\t\t\tmaxWallClockMs: dispatch.leaseTtlMs,\n\t\t\t\t...(dispatch.maxCostUsd !== undefined ? { maxCostUsd: dispatch.maxCostUsd } : {}),\n\t\t\t},\n\t\t});\n\t\tif (!compiled.ok) {\n\t\t\tthrow new Error(`Managed worker '${laneId}' execution grant was denied: ${compiled.reasonCodes.join(\", \")}`);\n\t\t}\n\t\treturn compiled.grant;\n\t}\n}\n"]}
1
+ {"version":3,"file":"managed-lane-controller.js","sourceRoot":"","sources":["../../../src/core/delegation/managed-lane-controller.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { Usage } from \"@caupulican/pi-ai\";\nimport type { CapabilityEnvelope, WorkerClaim, WorkerClaimStatus, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport { getPrivateLaneDeniedPaths } from \"../autonomy/lane-private-paths.ts\";\nimport { isLaneTerminalStatus, type LaneRecord, type LaneTerminalStatus } from \"../autonomy/lane-tracker.ts\";\nimport { appendLaneRecordSnapshot, getLatestLaneRecordSnapshots } from \"../autonomy/session-lane-record.ts\";\nimport type { ManagedLaneDispatch, ManagedLaneEvent } from \"../extensions/types.ts\";\nimport type { GoalState } from \"../goals/goal-state.ts\";\nimport { validateProviderUsage } from \"../orchestration/attempt-usage.ts\";\nimport type { ExecutionGrant } from \"../orchestration/contracts.ts\";\nimport { registerInFlightWork } from \"../reload-blockers.ts\";\nimport { getActiveSessionBranchEntries } from \"../session-snapshot.ts\";\nimport { getLatestWorkerClaimSnapshot } from \"./session-worker-claim.ts\";\nimport {\n\tnormalizeWorkerClaimForHost,\n\tnormalizeWorkerClaimReasonCode,\n\treviewManagedLaneChangedFiles,\n} from \"./worker-claim.ts\";\nimport { compileManagedProcessExecutionGrant } from \"./worker-execution-policy.ts\";\nimport type { WorkerLifecycle } from \"./worker-lifecycle.ts\";\nimport { finalizeWorkerClaim } from \"./worker-terminal-finalizer.ts\";\n\nconst LEGACY_MANAGED_LEASE_TTL_MS = 24 * 60 * 60 * 1_000;\nconst LEGACY_MANAGED_READ_TOOLS = [\"read\", \"grep\", \"find\", \"ls\"] as const;\n\nexport function resolveManagedLaneTerminalStatus(status: string | undefined): LaneTerminalStatus {\n\tif (isLaneTerminalStatus(status)) return status;\n\tswitch (status) {\n\t\tcase \"done\":\n\t\tcase \"completed\":\n\t\t\treturn \"succeeded\";\n\t\tcase \"blocked\":\n\t\t\treturn \"failed\";\n\t\tcase \"dismissed\":\n\t\tcase \"cancelled\":\n\t\t\treturn \"canceled\";\n\t\tdefault:\n\t\t\treturn \"failed\";\n\t}\n}\n\nexport function mapManagedLaneTerminalStatus(status: LaneTerminalStatus): WorkerClaimStatus {\n\tswitch (status) {\n\t\tcase \"succeeded\":\n\t\t\treturn \"completed\";\n\t\tcase \"canceled\":\n\t\t\treturn \"cancelled\";\n\t\tcase \"failed\":\n\t\tcase \"timeout\":\n\t\tcase \"budget_exhausted\":\n\t\t\treturn \"failed\";\n\t}\n}\n\nexport interface ManagedLaneControllerDeps {\n\tisDisposed(): boolean;\n\tgetAgentDir(): string;\n\tgetCwd(): string;\n\tgetSessionManager(): SessionManager;\n\tgetGoalStateSnapshot(): GoalState | undefined;\n\tgetCapabilityEnvelope(): CapabilityEnvelope | undefined;\n\tsaveWorkerClaimSnapshot(claim: WorkerClaim, request?: WorkerRequest): string;\n\t/** Optional only for minimal host embeddings; normal AgentSession integration always supplies this. */\n\taddSpawnedUsage?(\n\t\tusage: Usage,\n\t\topts: { label?: string; sourceSessionId?: string; reportId: string },\n\t): string | undefined;\n}\n\n/** Out-of-process adapter over the same durable worker lifecycle used by in-process delegation. */\nexport class ManagedLaneController {\n\tprivate readonly deps: ManagedLaneControllerDeps;\n\tprivate readonly lifecycle: WorkerLifecycle;\n\tprivate readonly recordTerminal: (record: LaneRecord, durableNotificationId: string) => void;\n\tprivate readonly warn: (message: string) => void;\n\tprivate readonly deregisterByLane = new Map<string, () => void>();\n\tprivate hydrated = false;\n\n\tconstructor(\n\t\tdeps: ManagedLaneControllerDeps,\n\t\tlifecycle: WorkerLifecycle,\n\t\trecordTerminal: (record: LaneRecord, durableNotificationId: string) => void,\n\t\twarn: (message: string) => void = () => {},\n\t) {\n\t\tthis.deps = deps;\n\t\tthis.lifecycle = lifecycle;\n\t\tthis.recordTerminal = recordTerminal;\n\t\tthis.warn = warn;\n\t}\n\n\tensureHydrated(): void {\n\t\tif (this.hydrated) return;\n\t\tthis.hydrated = true;\n\t\tconst durableIds = new Set(this.lifecycle.getManagedRecords().map((record) => record.laneId));\n\t\tfor (const legacy of getLatestLaneRecordSnapshots(getActiveSessionBranchEntries(this.deps.getSessionManager()))) {\n\t\t\tif (\n\t\t\t\tlegacy.type !== \"tmux-worker\" ||\n\t\t\t\t(legacy.status !== \"queued\" && legacy.status !== \"running\") ||\n\t\t\t\tdurableIds.has(legacy.laneId)\n\t\t\t) {\n\t\t\t\tcontinue;\n\t\t\t}\n\t\t\tthis.lifecycle.prepareManaged({\n\t\t\t\tlaneId: legacy.laneId,\n\t\t\t\tdispatchSequence: 1,\n\t\t\t\tinstructions: legacy.label ?? `Resume externally managed lane ${legacy.laneId}`,\n\t\t\t\tprofileId: legacy.profileId ?? \"legacy-managed-process\",\n\t\t\t\tprovider: \"legacy\",\n\t\t\t\tauthorizationId: `legacy-session-lane:${legacy.laneId}`,\n\t\t\t\trole: \"implementer\",\n\t\t\t\triskBudget: { maxAttempts: 1, maxWallClockMs: LEGACY_MANAGED_LEASE_TTL_MS },\n\t\t\t\tleaseTtlMs: LEGACY_MANAGED_LEASE_TTL_MS,\n\t\t\t\tcompileGrant: (target) =>\n\t\t\t\t\tthis.compileGrant(target, legacy.laneId, {\n\t\t\t\t\t\tsequence: 1,\n\t\t\t\t\t\tinstructions: legacy.label ?? `Resume externally managed lane ${legacy.laneId}`,\n\t\t\t\t\t\tprofileId: legacy.profileId ?? \"legacy-managed-process\",\n\t\t\t\t\t\tprovider: \"legacy\",\n\t\t\t\t\t\tauthorizationId: `legacy-session-lane:${legacy.laneId}`,\n\t\t\t\t\t\tauthorizationKind: \"legacy-recovery\",\n\t\t\t\t\t\tallowedTools: LEGACY_MANAGED_READ_TOOLS,\n\t\t\t\t\t\twritePaths: [],\n\t\t\t\t\t\tleaseTtlMs: LEGACY_MANAGED_LEASE_TTL_MS,\n\t\t\t\t\t}),\n\t\t\t\t...(legacy.worktreeLaneKey ? { worktreeLaneKey: legacy.worktreeLaneKey } : {}),\n\t\t\t});\n\t\t}\n\t\tfor (const record of this.lifecycle.getManagedRecords()) {\n\t\t\tif (record.status === \"queued\" || record.status === \"running\") this.ensureRegistration(record.laneId);\n\t\t}\n\t}\n\n\tresolve(callerLaneId: string): string | undefined {\n\t\tthis.ensureHydrated();\n\t\tconst record = this.lifecycle.getManagedRecord(callerLaneId);\n\t\treturn record && (record.status === \"queued\" || record.status === \"running\") ? callerLaneId : undefined;\n\t}\n\n\trecord(event: ManagedLaneEvent): LaneRecord | undefined {\n\t\tif (this.deps.isDisposed()) return undefined;\n\t\tthis.ensureHydrated();\n\t\tif (event.phase === \"dispatch\") {\n\t\t\tconst goal = this.deps.getGoalStateSnapshot();\n\t\t\tconst prepared = this.lifecycle.prepareManaged({\n\t\t\t\tlaneId: event.laneId,\n\t\t\t\tdispatchSequence: event.dispatch.sequence,\n\t\t\t\tinstructions: event.dispatch.instructions,\n\t\t\t\tprofileId: event.dispatch.profileId,\n\t\t\t\tprovider: event.dispatch.provider,\n\t\t\t\tauthorizationId: event.dispatch.authorizationId,\n\t\t\t\tleaseTtlMs: event.dispatch.leaseTtlMs,\n\t\t\t\tcompileGrant: (target) => this.compileGrant(target, event.laneId, event.dispatch),\n\t\t\t\trole: \"implementer\",\n\t\t\t\triskBudget: { maxAttempts: 1, maxWallClockMs: event.dispatch.leaseTtlMs },\n\t\t\t\t...(goal && Array.isArray(goal.requirements) && (!event.goalId || goal.goalId === event.goalId)\n\t\t\t\t\t? { goal }\n\t\t\t\t\t: {}),\n\t\t\t\t...(event.goalId ? { goalId: event.goalId } : {}),\n\t\t\t\t...(event.worktreeLaneKey ? { worktreeLaneKey: event.worktreeLaneKey } : {}),\n\t\t\t});\n\t\t\tif (!prepared.created) return undefined;\n\t\t\tthis.ensureRegistration(event.laneId);\n\t\t\tappendLaneRecordSnapshot(this.deps.getSessionManager(), prepared.record);\n\t\t\treturn prepared.record;\n\t\t}\n\n\t\tconst attempt = this.lifecycle.getManagedAttempt(event.laneId);\n\t\tconst handle = this.lifecycle.getManagedHandle(event.laneId);\n\t\tif (!attempt || !handle || (attempt.status !== \"leased\" && attempt.status !== \"running\")) return undefined;\n\t\tlet usage: Usage | undefined;\n\t\ttry {\n\t\t\tusage = event.usage ? validateProviderUsage(event.usage, \"managed lane usage\") : undefined;\n\t\t} catch (error) {\n\t\t\tthis.warn(\n\t\t\t\t`Rejected terminal report for managed worker ${event.laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\tconst resolvedStatus = resolveManagedLaneTerminalStatus(event.status);\n\t\tconst usageReportId = usage && this.deps.addSpawnedUsage ? `managed-worker:${handle.attemptId}` : undefined;\n\t\tlet claim: WorkerClaim;\n\t\ttry {\n\t\t\tclaim = normalizeWorkerClaimForHost({\n\t\t\t\trequestId: event.laneId,\n\t\t\t\tterminalAttemptId: handle.attemptId,\n\t\t\t\tstatus: mapManagedLaneTerminalStatus(resolvedStatus),\n\t\t\t\tsummary: `Managed worker lane ${event.laneId} reported terminal status \"${resolvedStatus}\".`,\n\t\t\t\tchangedFiles: event.changedFiles ?? [],\n\t\t\t\t...(usageReportId ? { usageReportId } : {}),\n\t\t\t\tcreatedAt: new Date().toISOString(),\n\t\t\t});\n\t\t} catch (error) {\n\t\t\tthis.warn(\n\t\t\t\t`Rejected terminal report for managed worker ${event.laneId}: ${error instanceof Error ? error.message : String(error)}`,\n\t\t\t);\n\t\t\treturn undefined;\n\t\t}\n\t\tconst review = reviewManagedLaneChangedFiles({\n\t\t\tchangedFiles: claim.changedFiles,\n\t\t\tenvelope: this.deps.getCapabilityEnvelope() ?? {},\n\t\t\tcwd: this.deps.getCwd(),\n\t\t});\n\t\tclaim = normalizeWorkerClaimForHost({\n\t\t\t...claim,\n\t\t\tsummary: `${claim.summary}${\n\t\t\t\treview.reviewRequired ? ` Changed files require parent review (${review.reasonCode}).` : \"\"\n\t\t\t}`,\n\t\t\tparentReviewRequired: review.reviewRequired,\n\t\t});\n\t\tlet record: LaneRecord | undefined;\n\t\tlet finalized = false;\n\t\ttry {\n\t\t\t// Accounting must commit before the lifecycle terminal transition. A failed append leaves the\n\t\t\t// fenced attempt active so the same terminal event can retry with this stable report id.\n\t\t\tif (usage && usageReportId) {\n\t\t\t\tthis.deps.addSpawnedUsage?.(usage, { label: \"managed-worker\", reportId: usageReportId });\n\t\t\t}\n\t\t\tif (!this.hasPersistedClaimForAttempt(claim)) this.deps.saveWorkerClaimSnapshot(claim);\n\t\t\tconst terminal = finalizeWorkerClaim(this.lifecycle, {\n\t\t\t\thandle,\n\t\t\t\tclaim,\n\t\t\t\taccepted: resolvedStatus === \"succeeded\" && !review.reviewRequired,\n\t\t\t\tcostUsd: usage?.cost.total,\n\t\t\t\tcwd: this.deps.getCwd(),\n\t\t\t\t...(usage\n\t\t\t\t\t? {\n\t\t\t\t\t\t\tinputTokens: usage.input,\n\t\t\t\t\t\t\toutputTokens: usage.output,\n\t\t\t\t\t\t\ttotalTokens: usage.totalTokens,\n\t\t\t\t\t\t}\n\t\t\t\t\t: {}),\n\t\t\t\twallClockMs: Math.max(0, Date.now() - Date.parse(attempt.createdAt)),\n\t\t\t\ttoolCalls: 0,\n\t\t\t\treasonCode: normalizeWorkerClaimReasonCode(\n\t\t\t\t\treview.reviewRequired ? `parent_review_required:${review.reasonCode}` : event.reasonCode,\n\t\t\t\t\t`managed_worker_${resolvedStatus}`,\n\t\t\t\t),\n\t\t\t});\n\t\t\trecord = terminal.record;\n\t\t\tfinalized = true;\n\t\t\tif (terminal.notification) this.recordTerminal(record, terminal.notification.notificationId);\n\t\t\tappendLaneRecordSnapshot(this.deps.getSessionManager(), record);\n\t\t} catch (error) {\n\t\t\tconst message = error instanceof Error ? error.message : String(error);\n\t\t\tif (finalized) {\n\t\t\t\tthis.warn(\n\t\t\t\t\t`Managed worker ${event.laneId} finalized, but terminal projection or handoff failed: ${message}`,\n\t\t\t\t);\n\t\t\t\treturn record;\n\t\t\t}\n\t\t\tthis.warn(`Managed worker ${event.laneId} terminal processing failed and remains retryable: ${message}`);\n\t\t\treturn undefined;\n\t\t} finally {\n\t\t\tif (finalized) this.releaseRegistration(event.laneId);\n\t\t}\n\t\treturn record;\n\t}\n\n\trelease(): void {\n\t\tfor (const deregister of this.deregisterByLane.values()) deregister();\n\t\tthis.deregisterByLane.clear();\n\t}\n\n\tprivate ensureRegistration(laneId: string): void {\n\t\tif (this.deregisterByLane.has(laneId)) return;\n\t\tthis.deregisterByLane.set(laneId, registerInFlightWork(this.deps.getAgentDir(), \"lane\", `tmux:${laneId}`));\n\t}\n\n\tprivate releaseRegistration(laneId: string): void {\n\t\tthis.deregisterByLane.get(laneId)?.();\n\t\tthis.deregisterByLane.delete(laneId);\n\t}\n\n\t/** A replay after a crash between claim append and lifecycle finalization must not duplicate the claim. */\n\tprivate hasPersistedClaimForAttempt(claim: WorkerClaim): boolean {\n\t\tif (!claim.terminalAttemptId) return false;\n\t\tconst latest = getLatestWorkerClaimSnapshot(\n\t\t\tgetActiveSessionBranchEntries(this.deps.getSessionManager()),\n\t\t\tclaim.requestId,\n\t\t);\n\t\treturn latest?.claim.terminalAttemptId === claim.terminalAttemptId;\n\t}\n\n\tprivate compileGrant(\n\t\ttarget: { objectiveId: string; taskId: string; attemptId: string },\n\t\tlaneId: string,\n\t\tdispatch: ManagedLaneDispatch,\n\t): ExecutionGrant {\n\t\tconst compiled = compileManagedProcessExecutionGrant({\n\t\t\ttarget,\n\t\t\tlaneId,\n\t\t\tauthorizationId: dispatch.authorizationId,\n\t\t\trole: \"implementer\",\n\t\t\tallowedTools: dispatch.allowedTools,\n\t\t\twritePaths: dispatch.writePaths,\n\t\t\tcwd: this.deps.getCwd(),\n\t\t\tdeniedPaths: getPrivateLaneDeniedPaths(this.deps.getCwd(), this.deps.getAgentDir()),\n\t\t\tbudget: {\n\t\t\t\tmaxAttempts: 1,\n\t\t\t\tmaxWallClockMs: dispatch.leaseTtlMs,\n\t\t\t\t...(dispatch.maxCostUsd !== undefined ? { maxCostUsd: dispatch.maxCostUsd } : {}),\n\t\t\t},\n\t\t});\n\t\tif (!compiled.ok) {\n\t\t\tthrow new Error(`Managed worker '${laneId}' execution grant was denied: ${compiled.reasonCodes.join(\", \")}`);\n\t\t}\n\t\treturn compiled.grant;\n\t}\n}\n"]}
@@ -1 +1 @@
1
- {"version":3,"file":"session-worker-claim.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/session-worker-claim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAKN,KAAK,wBAAwB,EAE7B,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC;AAIhC,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAEvD,MAAM,MAAM,0BAA0B,GAAG,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG;IACvF;uEACmE;IACnE,OAAO,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AASF,wBAAgB,yBAAyB,CACxC,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,EACzD,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,aAAa;AACvB;;4EAE4E;AAC5E,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACxB,MAAM,CAgBR;AAED,kDAAkD;AAClD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,aAAa,EAAE,CAY3F;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,WAAW,EAAE,CAEvF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,SAAS,EAAE,MAAM,GACf,0BAA0B,GAAG,SAAS,CAkBxC;AAED,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAExG,MAAM,MAAM,6BAA6B,GACtC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,6BAA6B,CAAA;CAAE,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,GAAG,wBAAwB,EACpF,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,MAAuC,GAChD,6BAA6B,CAQ/B","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport {\n\tdecodeSessionSnapshotPayload,\n\tgetActiveSessionBranchEntries,\n\tgetSessionSnapshots,\n\tisVersionOneSessionSnapshotPayload,\n\ttype SessionBranchEntrySource,\n\ttype SessionSnapshotCodec,\n\ttype SessionSnapshotPayload,\n} from \"../session-snapshot.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\nimport { cloneWorkerClaimForStorage, isParentReviewRequired, isWorkerClaim } from \"./worker-claim.ts\";\n\nexport const WORKER_CLAIM_CUSTOM_TYPE = \"worker_claim\";\n\nexport type WorkerClaimSnapshotPayload = SessionSnapshotPayload<\"claim\", WorkerClaim> & {\n\t/** The originating request, when the host has one, makes a claim auditable against the\n\t * instructions, route, and capability envelope that bounded it. */\n\trequest?: WorkerRequest;\n};\n\nconst WORKER_CLAIM_SNAPSHOT_CODEC: SessionSnapshotCodec<WorkerClaim, \"claim\"> = {\n\tcustomType: WORKER_CLAIM_CUSTOM_TYPE,\n\tvalueKey: \"claim\",\n\tisValue: isWorkerClaim,\n\tclone: cloneWorkerClaimForStorage,\n};\n\nexport function appendWorkerClaimSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tclaim: WorkerClaim,\n\trequest?: WorkerRequest,\n\t/** Baseline for relative changedFiles when re-deriving the review marker; forwarded to\n\t * `isParentReviewRequired`/`validateWorkerClaim`. Defaults to `process.cwd()`, matching the\n\t * validator's own documented default for single-cwd-per-process callers. */\n\toptions?: { cwd?: string },\n): string {\n\tconst stored = cloneWorkerClaimForStorage(claim);\n\t// Stamp the parent-review marker here by re-running the SAME gate\n\t// (validateWorkerClaim, via isParentReviewRequired) that originally decided\n\t// ask-user/parent_review_required, so the marker can never drift from the gate's own verdict.\n\t// Only computable when `request` is available; externally managed lanes leave the field unset —\n\t// \"unknown\", never falsely \"false\".\n\tif (request) {\n\t\tstored.parentReviewRequired = isParentReviewRequired({ request, claim, cwd: options?.cwd });\n\t}\n\tconst payload: WorkerClaimSnapshotPayload = {\n\t\tversion: 1,\n\t\tclaim: stored,\n\t\t...(request ? { request: structuredClone(request) } : {}),\n\t};\n\treturn sessionManager.appendCustomEntry(WORKER_CLAIM_CUSTOM_TYPE, payload);\n}\n\n/** Requests persisted alongside worker claims. */\nexport function getWorkerRequestSnapshots(entries: readonly SessionEntry[]): WorkerRequest[] {\n\tconst requests: WorkerRequest[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst request = payload.request;\n\t\tif (isPlainRecord(request) && typeof request.id === \"string\") {\n\t\t\trequests.push(structuredClone(request) as unknown as WorkerRequest);\n\t\t}\n\t}\n\treturn requests;\n}\n\nexport function getWorkerClaimSnapshots(entries: readonly SessionEntry[]): WorkerClaim[] {\n\treturn getSessionSnapshots(entries, WORKER_CLAIM_SNAPSHOT_CODEC);\n}\n\n/**\n * Latest persisted snapshot (claim + originating request, when available) for one worker\n * requestId — \"latest wins\" over the append-only entries, the same collapse `delegate_status`\n * already performs when it maps results by requestId. Used to read, and durably update, the\n * parent-review marker.\n */\nexport function getLatestWorkerClaimSnapshot(\n\tentries: readonly SessionEntry[],\n\trequestId: string,\n): WorkerClaimSnapshotPayload | undefined {\n\tlet latest: WorkerClaimSnapshotPayload | undefined;\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst claim = decodeSessionSnapshotPayload(payload, WORKER_CLAIM_SNAPSHOT_CODEC);\n\t\tif (!claim || claim.requestId !== requestId) continue;\n\t\tconst request = payload.request;\n\t\tlatest = {\n\t\t\tversion: 1,\n\t\t\tclaim,\n\t\t\t...(isPlainRecord(request) && typeof request.id === \"string\"\n\t\t\t\t? { request: structuredClone(request) as unknown as WorkerRequest }\n\t\t\t\t: {}),\n\t\t};\n\t}\n\treturn latest;\n}\n\nexport type AcknowledgeWorkerReviewReason = \"unknown_worker_claim\" | \"not_flagged\" | \"already_reviewed\";\n\nexport type AcknowledgeWorkerReviewResult =\n\t| { ok: true; requestId: string; reviewedAt: string }\n\t| { ok: false; reason: AcknowledgeWorkerReviewReason };\n\n/**\n * Durably acknowledge an unreviewed worker mutation. Re-appends the latest snapshot for\n * `requestId` with `parentReviewedAt` set, so the ack is a first-class entry in the same\n * append-only audit trail as the original claim — it survives reload and any future re-read of\n * `getWorkerClaimSnapshots`/`getLatestWorkerClaimSnapshot` (both are \"latest wins\"). Never\n * write-blocking: this only marks the mutation reviewed, it does not touch the worker's files.\n */\nexport function acknowledgeWorkerClaimReview(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\"> & SessionBranchEntrySource,\n\trequestId: string,\n\tnow: () => string = () => new Date().toISOString(),\n): AcknowledgeWorkerReviewResult {\n\tconst latest = getLatestWorkerClaimSnapshot(getActiveSessionBranchEntries(sessionManager), requestId);\n\tif (!latest) return { ok: false, reason: \"unknown_worker_claim\" };\n\tif (!latest.claim.parentReviewRequired) return { ok: false, reason: \"not_flagged\" };\n\tif (latest.claim.parentReviewedAt) return { ok: false, reason: \"already_reviewed\" };\n\tconst reviewedAt = now();\n\tappendWorkerClaimSnapshot(sessionManager, { ...latest.claim, parentReviewedAt: reviewedAt }, latest.request);\n\treturn { ok: true, requestId, reviewedAt };\n}\n"]}
1
+ {"version":3,"file":"session-worker-claim.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/session-worker-claim.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAC;AACnF,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAC3E,OAAO,EAKN,KAAK,wBAAwB,EAE7B,KAAK,sBAAsB,EAC3B,MAAM,wBAAwB,CAAC;AAShC,eAAO,MAAM,wBAAwB,iBAAiB,CAAC;AAEvD,MAAM,MAAM,0BAA0B,GAAG,sBAAsB,CAAC,OAAO,EAAE,WAAW,CAAC,GAAG;IACvF;uEACmE;IACnE,OAAO,CAAC,EAAE,aAAa,CAAC;CACxB,CAAC;AASF,wBAAgB,yBAAyB,CACxC,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,EACzD,KAAK,EAAE,WAAW,EAClB,OAAO,CAAC,EAAE,aAAa;AACvB;;4EAE4E;AAC5E,OAAO,CAAC,EAAE;IAAE,GAAG,CAAC,EAAE,MAAM,CAAA;CAAE,GACxB,MAAM,CAiBR;AAED,kDAAkD;AAClD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,aAAa,EAAE,CAY3F;AAED,wBAAgB,uBAAuB,CAAC,OAAO,EAAE,SAAS,YAAY,EAAE,GAAG,WAAW,EAAE,CAEvF;AAED;;;;;GAKG;AACH,wBAAgB,4BAA4B,CAC3C,OAAO,EAAE,SAAS,YAAY,EAAE,EAChC,SAAS,EAAE,MAAM,GACf,0BAA0B,GAAG,SAAS,CAkBxC;AAED,MAAM,MAAM,6BAA6B,GAAG,sBAAsB,GAAG,aAAa,GAAG,kBAAkB,CAAC;AAExG,MAAM,MAAM,6BAA6B,GACtC;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,SAAS,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,GACnD;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,6BAA6B,CAAA;CAAE,CAAC;AAExD;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAC3C,cAAc,EAAE,IAAI,CAAC,cAAc,EAAE,mBAAmB,CAAC,GAAG,wBAAwB,EACpF,SAAS,EAAE,MAAM,EACjB,GAAG,GAAE,MAAM,MAAuC,GAChD,6BAA6B,CAQ/B","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport {\n\tdecodeSessionSnapshotPayload,\n\tgetActiveSessionBranchEntries,\n\tgetSessionSnapshots,\n\tisVersionOneSessionSnapshotPayload,\n\ttype SessionBranchEntrySource,\n\ttype SessionSnapshotCodec,\n\ttype SessionSnapshotPayload,\n} from \"../session-snapshot.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\nimport {\n\tcloneWorkerClaimForStorage,\n\tisParentReviewRequired,\n\tisWorkerClaim,\n\tnormalizeWorkerClaimForHost,\n} from \"./worker-claim.ts\";\n\nexport const WORKER_CLAIM_CUSTOM_TYPE = \"worker_claim\";\n\nexport type WorkerClaimSnapshotPayload = SessionSnapshotPayload<\"claim\", WorkerClaim> & {\n\t/** The originating request, when the host has one, makes a claim auditable against the\n\t * instructions, route, and capability envelope that bounded it. */\n\trequest?: WorkerRequest;\n};\n\nconst WORKER_CLAIM_SNAPSHOT_CODEC: SessionSnapshotCodec<WorkerClaim, \"claim\"> = {\n\tcustomType: WORKER_CLAIM_CUSTOM_TYPE,\n\tvalueKey: \"claim\",\n\tisValue: isWorkerClaim,\n\tclone: cloneWorkerClaimForStorage,\n};\n\nexport function appendWorkerClaimSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tclaim: WorkerClaim,\n\trequest?: WorkerRequest,\n\t/** Baseline for relative changedFiles when re-deriving the review marker; forwarded to\n\t * `isParentReviewRequired`/`validateWorkerClaim`. Defaults to `process.cwd()`, matching the\n\t * validator's own documented default for single-cwd-per-process callers. */\n\toptions?: { cwd?: string },\n): string {\n\tconst normalizedClaim = normalizeWorkerClaimForHost(claim);\n\tconst stored = cloneWorkerClaimForStorage(normalizedClaim);\n\t// Stamp the parent-review marker here by re-running the SAME gate\n\t// (validateWorkerClaim, via isParentReviewRequired) that originally decided\n\t// ask-user/parent_review_required, so the marker can never drift from the gate's own verdict.\n\t// Only computable when `request` is available; externally managed lanes leave the field unset —\n\t// \"unknown\", never falsely \"false\".\n\tif (request) {\n\t\tstored.parentReviewRequired = isParentReviewRequired({ request, claim: normalizedClaim, cwd: options?.cwd });\n\t}\n\tconst payload: WorkerClaimSnapshotPayload = {\n\t\tversion: 1,\n\t\tclaim: stored,\n\t\t...(request ? { request: structuredClone(request) } : {}),\n\t};\n\treturn sessionManager.appendCustomEntry(WORKER_CLAIM_CUSTOM_TYPE, payload);\n}\n\n/** Requests persisted alongside worker claims. */\nexport function getWorkerRequestSnapshots(entries: readonly SessionEntry[]): WorkerRequest[] {\n\tconst requests: WorkerRequest[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst request = payload.request;\n\t\tif (isPlainRecord(request) && typeof request.id === \"string\") {\n\t\t\trequests.push(structuredClone(request) as unknown as WorkerRequest);\n\t\t}\n\t}\n\treturn requests;\n}\n\nexport function getWorkerClaimSnapshots(entries: readonly SessionEntry[]): WorkerClaim[] {\n\treturn getSessionSnapshots(entries, WORKER_CLAIM_SNAPSHOT_CODEC);\n}\n\n/**\n * Latest persisted snapshot (claim + originating request, when available) for one worker\n * requestId — \"latest wins\" over the append-only entries, the same collapse `delegate_status`\n * already performs when it maps results by requestId. Used to read, and durably update, the\n * parent-review marker.\n */\nexport function getLatestWorkerClaimSnapshot(\n\tentries: readonly SessionEntry[],\n\trequestId: string,\n): WorkerClaimSnapshotPayload | undefined {\n\tlet latest: WorkerClaimSnapshotPayload | undefined;\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst claim = decodeSessionSnapshotPayload(payload, WORKER_CLAIM_SNAPSHOT_CODEC);\n\t\tif (!claim || claim.requestId !== requestId) continue;\n\t\tconst request = payload.request;\n\t\tlatest = {\n\t\t\tversion: 1,\n\t\t\tclaim,\n\t\t\t...(isPlainRecord(request) && typeof request.id === \"string\"\n\t\t\t\t? { request: structuredClone(request) as unknown as WorkerRequest }\n\t\t\t\t: {}),\n\t\t};\n\t}\n\treturn latest;\n}\n\nexport type AcknowledgeWorkerReviewReason = \"unknown_worker_claim\" | \"not_flagged\" | \"already_reviewed\";\n\nexport type AcknowledgeWorkerReviewResult =\n\t| { ok: true; requestId: string; reviewedAt: string }\n\t| { ok: false; reason: AcknowledgeWorkerReviewReason };\n\n/**\n * Durably acknowledge an unreviewed worker mutation. Re-appends the latest snapshot for\n * `requestId` with `parentReviewedAt` set, so the ack is a first-class entry in the same\n * append-only audit trail as the original claim — it survives reload and any future re-read of\n * `getWorkerClaimSnapshots`/`getLatestWorkerClaimSnapshot` (both are \"latest wins\"). Never\n * write-blocking: this only marks the mutation reviewed, it does not touch the worker's files.\n */\nexport function acknowledgeWorkerClaimReview(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\"> & SessionBranchEntrySource,\n\trequestId: string,\n\tnow: () => string = () => new Date().toISOString(),\n): AcknowledgeWorkerReviewResult {\n\tconst latest = getLatestWorkerClaimSnapshot(getActiveSessionBranchEntries(sessionManager), requestId);\n\tif (!latest) return { ok: false, reason: \"unknown_worker_claim\" };\n\tif (!latest.claim.parentReviewRequired) return { ok: false, reason: \"not_flagged\" };\n\tif (latest.claim.parentReviewedAt) return { ok: false, reason: \"already_reviewed\" };\n\tconst reviewedAt = now();\n\tappendWorkerClaimSnapshot(sessionManager, { ...latest.claim, parentReviewedAt: reviewedAt }, latest.request);\n\treturn { ok: true, requestId, reviewedAt };\n}\n"]}
@@ -1,6 +1,6 @@
1
1
  import { decodeSessionSnapshotPayload, getActiveSessionBranchEntries, getSessionSnapshots, isVersionOneSessionSnapshotPayload, } from "../session-snapshot.js";
2
2
  import { isPlainRecord } from "../util/value-guards.js";
3
- import { cloneWorkerClaimForStorage, isParentReviewRequired, isWorkerClaim } from "./worker-claim.js";
3
+ import { cloneWorkerClaimForStorage, isParentReviewRequired, isWorkerClaim, normalizeWorkerClaimForHost, } from "./worker-claim.js";
4
4
  export const WORKER_CLAIM_CUSTOM_TYPE = "worker_claim";
5
5
  const WORKER_CLAIM_SNAPSHOT_CODEC = {
6
6
  customType: WORKER_CLAIM_CUSTOM_TYPE,
@@ -13,14 +13,15 @@ export function appendWorkerClaimSnapshot(sessionManager, claim, request,
13
13
  * `isParentReviewRequired`/`validateWorkerClaim`. Defaults to `process.cwd()`, matching the
14
14
  * validator's own documented default for single-cwd-per-process callers. */
15
15
  options) {
16
- const stored = cloneWorkerClaimForStorage(claim);
16
+ const normalizedClaim = normalizeWorkerClaimForHost(claim);
17
+ const stored = cloneWorkerClaimForStorage(normalizedClaim);
17
18
  // Stamp the parent-review marker here by re-running the SAME gate
18
19
  // (validateWorkerClaim, via isParentReviewRequired) that originally decided
19
20
  // ask-user/parent_review_required, so the marker can never drift from the gate's own verdict.
20
21
  // Only computable when `request` is available; externally managed lanes leave the field unset —
21
22
  // "unknown", never falsely "false".
22
23
  if (request) {
23
- stored.parentReviewRequired = isParentReviewRequired({ request, claim, cwd: options?.cwd });
24
+ stored.parentReviewRequired = isParentReviewRequired({ request, claim: normalizedClaim, cwd: options?.cwd });
24
25
  }
25
26
  const payload = {
26
27
  version: 1,
@@ -1 +1 @@
1
- {"version":3,"file":"session-worker-claim.js","sourceRoot":"","sources":["../../../src/core/delegation/session-worker-claim.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport {\n\tdecodeSessionSnapshotPayload,\n\tgetActiveSessionBranchEntries,\n\tgetSessionSnapshots,\n\tisVersionOneSessionSnapshotPayload,\n\ttype SessionBranchEntrySource,\n\ttype SessionSnapshotCodec,\n\ttype SessionSnapshotPayload,\n} from \"../session-snapshot.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\nimport { cloneWorkerClaimForStorage, isParentReviewRequired, isWorkerClaim } from \"./worker-claim.ts\";\n\nexport const WORKER_CLAIM_CUSTOM_TYPE = \"worker_claim\";\n\nexport type WorkerClaimSnapshotPayload = SessionSnapshotPayload<\"claim\", WorkerClaim> & {\n\t/** The originating request, when the host has one, makes a claim auditable against the\n\t * instructions, route, and capability envelope that bounded it. */\n\trequest?: WorkerRequest;\n};\n\nconst WORKER_CLAIM_SNAPSHOT_CODEC: SessionSnapshotCodec<WorkerClaim, \"claim\"> = {\n\tcustomType: WORKER_CLAIM_CUSTOM_TYPE,\n\tvalueKey: \"claim\",\n\tisValue: isWorkerClaim,\n\tclone: cloneWorkerClaimForStorage,\n};\n\nexport function appendWorkerClaimSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tclaim: WorkerClaim,\n\trequest?: WorkerRequest,\n\t/** Baseline for relative changedFiles when re-deriving the review marker; forwarded to\n\t * `isParentReviewRequired`/`validateWorkerClaim`. Defaults to `process.cwd()`, matching the\n\t * validator's own documented default for single-cwd-per-process callers. */\n\toptions?: { cwd?: string },\n): string {\n\tconst stored = cloneWorkerClaimForStorage(claim);\n\t// Stamp the parent-review marker here by re-running the SAME gate\n\t// (validateWorkerClaim, via isParentReviewRequired) that originally decided\n\t// ask-user/parent_review_required, so the marker can never drift from the gate's own verdict.\n\t// Only computable when `request` is available; externally managed lanes leave the field unset —\n\t// \"unknown\", never falsely \"false\".\n\tif (request) {\n\t\tstored.parentReviewRequired = isParentReviewRequired({ request, claim, cwd: options?.cwd });\n\t}\n\tconst payload: WorkerClaimSnapshotPayload = {\n\t\tversion: 1,\n\t\tclaim: stored,\n\t\t...(request ? { request: structuredClone(request) } : {}),\n\t};\n\treturn sessionManager.appendCustomEntry(WORKER_CLAIM_CUSTOM_TYPE, payload);\n}\n\n/** Requests persisted alongside worker claims. */\nexport function getWorkerRequestSnapshots(entries: readonly SessionEntry[]): WorkerRequest[] {\n\tconst requests: WorkerRequest[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst request = payload.request;\n\t\tif (isPlainRecord(request) && typeof request.id === \"string\") {\n\t\t\trequests.push(structuredClone(request) as unknown as WorkerRequest);\n\t\t}\n\t}\n\treturn requests;\n}\n\nexport function getWorkerClaimSnapshots(entries: readonly SessionEntry[]): WorkerClaim[] {\n\treturn getSessionSnapshots(entries, WORKER_CLAIM_SNAPSHOT_CODEC);\n}\n\n/**\n * Latest persisted snapshot (claim + originating request, when available) for one worker\n * requestId — \"latest wins\" over the append-only entries, the same collapse `delegate_status`\n * already performs when it maps results by requestId. Used to read, and durably update, the\n * parent-review marker.\n */\nexport function getLatestWorkerClaimSnapshot(\n\tentries: readonly SessionEntry[],\n\trequestId: string,\n): WorkerClaimSnapshotPayload | undefined {\n\tlet latest: WorkerClaimSnapshotPayload | undefined;\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst claim = decodeSessionSnapshotPayload(payload, WORKER_CLAIM_SNAPSHOT_CODEC);\n\t\tif (!claim || claim.requestId !== requestId) continue;\n\t\tconst request = payload.request;\n\t\tlatest = {\n\t\t\tversion: 1,\n\t\t\tclaim,\n\t\t\t...(isPlainRecord(request) && typeof request.id === \"string\"\n\t\t\t\t? { request: structuredClone(request) as unknown as WorkerRequest }\n\t\t\t\t: {}),\n\t\t};\n\t}\n\treturn latest;\n}\n\nexport type AcknowledgeWorkerReviewReason = \"unknown_worker_claim\" | \"not_flagged\" | \"already_reviewed\";\n\nexport type AcknowledgeWorkerReviewResult =\n\t| { ok: true; requestId: string; reviewedAt: string }\n\t| { ok: false; reason: AcknowledgeWorkerReviewReason };\n\n/**\n * Durably acknowledge an unreviewed worker mutation. Re-appends the latest snapshot for\n * `requestId` with `parentReviewedAt` set, so the ack is a first-class entry in the same\n * append-only audit trail as the original claim — it survives reload and any future re-read of\n * `getWorkerClaimSnapshots`/`getLatestWorkerClaimSnapshot` (both are \"latest wins\"). Never\n * write-blocking: this only marks the mutation reviewed, it does not touch the worker's files.\n */\nexport function acknowledgeWorkerClaimReview(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\"> & SessionBranchEntrySource,\n\trequestId: string,\n\tnow: () => string = () => new Date().toISOString(),\n): AcknowledgeWorkerReviewResult {\n\tconst latest = getLatestWorkerClaimSnapshot(getActiveSessionBranchEntries(sessionManager), requestId);\n\tif (!latest) return { ok: false, reason: \"unknown_worker_claim\" };\n\tif (!latest.claim.parentReviewRequired) return { ok: false, reason: \"not_flagged\" };\n\tif (latest.claim.parentReviewedAt) return { ok: false, reason: \"already_reviewed\" };\n\tconst reviewedAt = now();\n\tappendWorkerClaimSnapshot(sessionManager, { ...latest.claim, parentReviewedAt: reviewedAt }, latest.request);\n\treturn { ok: true, requestId, reviewedAt };\n}\n"]}
1
+ {"version":3,"file":"session-worker-claim.js","sourceRoot":"","sources":["../../../src/core/delegation/session-worker-claim.ts"],"names":[],"mappings":"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","sourcesContent":["import type { SessionEntry, SessionManager } from \"@caupulican/pi-agent-core/node\";\nimport type { WorkerClaim, WorkerRequest } from \"../autonomy/contracts.ts\";\nimport {\n\tdecodeSessionSnapshotPayload,\n\tgetActiveSessionBranchEntries,\n\tgetSessionSnapshots,\n\tisVersionOneSessionSnapshotPayload,\n\ttype SessionBranchEntrySource,\n\ttype SessionSnapshotCodec,\n\ttype SessionSnapshotPayload,\n} from \"../session-snapshot.ts\";\nimport { isPlainRecord } from \"../util/value-guards.ts\";\nimport {\n\tcloneWorkerClaimForStorage,\n\tisParentReviewRequired,\n\tisWorkerClaim,\n\tnormalizeWorkerClaimForHost,\n} from \"./worker-claim.ts\";\n\nexport const WORKER_CLAIM_CUSTOM_TYPE = \"worker_claim\";\n\nexport type WorkerClaimSnapshotPayload = SessionSnapshotPayload<\"claim\", WorkerClaim> & {\n\t/** The originating request, when the host has one, makes a claim auditable against the\n\t * instructions, route, and capability envelope that bounded it. */\n\trequest?: WorkerRequest;\n};\n\nconst WORKER_CLAIM_SNAPSHOT_CODEC: SessionSnapshotCodec<WorkerClaim, \"claim\"> = {\n\tcustomType: WORKER_CLAIM_CUSTOM_TYPE,\n\tvalueKey: \"claim\",\n\tisValue: isWorkerClaim,\n\tclone: cloneWorkerClaimForStorage,\n};\n\nexport function appendWorkerClaimSnapshot(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\">,\n\tclaim: WorkerClaim,\n\trequest?: WorkerRequest,\n\t/** Baseline for relative changedFiles when re-deriving the review marker; forwarded to\n\t * `isParentReviewRequired`/`validateWorkerClaim`. Defaults to `process.cwd()`, matching the\n\t * validator's own documented default for single-cwd-per-process callers. */\n\toptions?: { cwd?: string },\n): string {\n\tconst normalizedClaim = normalizeWorkerClaimForHost(claim);\n\tconst stored = cloneWorkerClaimForStorage(normalizedClaim);\n\t// Stamp the parent-review marker here by re-running the SAME gate\n\t// (validateWorkerClaim, via isParentReviewRequired) that originally decided\n\t// ask-user/parent_review_required, so the marker can never drift from the gate's own verdict.\n\t// Only computable when `request` is available; externally managed lanes leave the field unset —\n\t// \"unknown\", never falsely \"false\".\n\tif (request) {\n\t\tstored.parentReviewRequired = isParentReviewRequired({ request, claim: normalizedClaim, cwd: options?.cwd });\n\t}\n\tconst payload: WorkerClaimSnapshotPayload = {\n\t\tversion: 1,\n\t\tclaim: stored,\n\t\t...(request ? { request: structuredClone(request) } : {}),\n\t};\n\treturn sessionManager.appendCustomEntry(WORKER_CLAIM_CUSTOM_TYPE, payload);\n}\n\n/** Requests persisted alongside worker claims. */\nexport function getWorkerRequestSnapshots(entries: readonly SessionEntry[]): WorkerRequest[] {\n\tconst requests: WorkerRequest[] = [];\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst request = payload.request;\n\t\tif (isPlainRecord(request) && typeof request.id === \"string\") {\n\t\t\trequests.push(structuredClone(request) as unknown as WorkerRequest);\n\t\t}\n\t}\n\treturn requests;\n}\n\nexport function getWorkerClaimSnapshots(entries: readonly SessionEntry[]): WorkerClaim[] {\n\treturn getSessionSnapshots(entries, WORKER_CLAIM_SNAPSHOT_CODEC);\n}\n\n/**\n * Latest persisted snapshot (claim + originating request, when available) for one worker\n * requestId — \"latest wins\" over the append-only entries, the same collapse `delegate_status`\n * already performs when it maps results by requestId. Used to read, and durably update, the\n * parent-review marker.\n */\nexport function getLatestWorkerClaimSnapshot(\n\tentries: readonly SessionEntry[],\n\trequestId: string,\n): WorkerClaimSnapshotPayload | undefined {\n\tlet latest: WorkerClaimSnapshotPayload | undefined;\n\tfor (const entry of entries) {\n\t\tif (entry.type !== \"custom\" || entry.customType !== WORKER_CLAIM_CUSTOM_TYPE) continue;\n\t\tconst payload = entry.data;\n\t\tif (!isVersionOneSessionSnapshotPayload(payload)) continue;\n\t\tconst claim = decodeSessionSnapshotPayload(payload, WORKER_CLAIM_SNAPSHOT_CODEC);\n\t\tif (!claim || claim.requestId !== requestId) continue;\n\t\tconst request = payload.request;\n\t\tlatest = {\n\t\t\tversion: 1,\n\t\t\tclaim,\n\t\t\t...(isPlainRecord(request) && typeof request.id === \"string\"\n\t\t\t\t? { request: structuredClone(request) as unknown as WorkerRequest }\n\t\t\t\t: {}),\n\t\t};\n\t}\n\treturn latest;\n}\n\nexport type AcknowledgeWorkerReviewReason = \"unknown_worker_claim\" | \"not_flagged\" | \"already_reviewed\";\n\nexport type AcknowledgeWorkerReviewResult =\n\t| { ok: true; requestId: string; reviewedAt: string }\n\t| { ok: false; reason: AcknowledgeWorkerReviewReason };\n\n/**\n * Durably acknowledge an unreviewed worker mutation. Re-appends the latest snapshot for\n * `requestId` with `parentReviewedAt` set, so the ack is a first-class entry in the same\n * append-only audit trail as the original claim — it survives reload and any future re-read of\n * `getWorkerClaimSnapshots`/`getLatestWorkerClaimSnapshot` (both are \"latest wins\"). Never\n * write-blocking: this only marks the mutation reviewed, it does not touch the worker's files.\n */\nexport function acknowledgeWorkerClaimReview(\n\tsessionManager: Pick<SessionManager, \"appendCustomEntry\"> & SessionBranchEntrySource,\n\trequestId: string,\n\tnow: () => string = () => new Date().toISOString(),\n): AcknowledgeWorkerReviewResult {\n\tconst latest = getLatestWorkerClaimSnapshot(getActiveSessionBranchEntries(sessionManager), requestId);\n\tif (!latest) return { ok: false, reason: \"unknown_worker_claim\" };\n\tif (!latest.claim.parentReviewRequired) return { ok: false, reason: \"not_flagged\" };\n\tif (latest.claim.parentReviewedAt) return { ok: false, reason: \"already_reviewed\" };\n\tconst reviewedAt = now();\n\tappendWorkerClaimSnapshot(sessionManager, { ...latest.claim, parentReviewedAt: reviewedAt }, latest.request);\n\treturn { ok: true, requestId, reviewedAt };\n}\n"]}
@@ -0,0 +1,73 @@
1
+ export type WorkerActionJournalState = "not_started" | "unknown" | "succeeded" | "failed";
2
+ export interface WorkerActionJournalScope {
3
+ agentDir: string;
4
+ parentSessionId: string;
5
+ taskId: string;
6
+ attemptId: string;
7
+ fencingToken: number;
8
+ }
9
+ export interface WorkerActionJournalAction {
10
+ op: "write" | "edit";
11
+ path: string;
12
+ content?: string;
13
+ old?: string;
14
+ new?: string;
15
+ }
16
+ export interface BeginWorkerActionInput {
17
+ index: number;
18
+ action: WorkerActionJournalAction;
19
+ /** Realpath-resolved target used by the executor, never model-provided text alone. */
20
+ targetPath: string;
21
+ }
22
+ export interface WorkerActionExecutionPermit {
23
+ kind: "execute";
24
+ state: "not_started";
25
+ actionId: string;
26
+ actionDigest: string;
27
+ normalizedTarget: string;
28
+ }
29
+ export interface WorkerActionInspectionRequired {
30
+ kind: "inspection_required";
31
+ state: Exclude<WorkerActionJournalState, "not_started">;
32
+ actionId: string;
33
+ actionDigest: string;
34
+ normalizedTarget: string;
35
+ reasonCode: string;
36
+ evidencePointer?: string;
37
+ }
38
+ export type BeginWorkerActionResult = WorkerActionExecutionPermit | WorkerActionInspectionRequired;
39
+ export interface WorkerActionJournalInspection {
40
+ state: WorkerActionJournalState;
41
+ actionId: string;
42
+ actionDigest?: string;
43
+ normalizedTarget?: string;
44
+ reasonCode?: string;
45
+ evidencePointer?: string;
46
+ }
47
+ /** Canonical lexical identity for an already-authorized real target, including native Windows paths. */
48
+ export declare function normalizeWorkerActionTarget(cwd: string, targetPath: string): string;
49
+ /**
50
+ * Durable intent/receipt journal for model-emitted structured mutations. It deliberately records
51
+ * only action digests and normalized targets; operation payloads can contain source text or secrets
52
+ * and must never leave the model result in persisted orchestration state.
53
+ */
54
+ export declare class WorkerActionJournal {
55
+ readonly agentDir: string;
56
+ readonly filePath: string;
57
+ private readonly scope;
58
+ private readonly identity;
59
+ constructor(scope: WorkerActionJournalScope);
60
+ inspect(actionIdentity: string): WorkerActionJournalInspection;
61
+ begin(input: BeginWorkerActionInput): BeginWorkerActionResult;
62
+ recordSucceeded(permit: WorkerActionExecutionPermit, options?: {
63
+ evidencePointer?: string;
64
+ }): void;
65
+ recordFailed(permit: WorkerActionExecutionPermit, reasonCode: string, options?: {
66
+ evidencePointer?: string;
67
+ }): void;
68
+ private recordTerminal;
69
+ private readLocked;
70
+ private writeLocked;
71
+ private inspectionFor;
72
+ }
73
+ //# sourceMappingURL=worker-action-journal.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"worker-action-journal.d.ts","sourceRoot":"","sources":["../../../src/core/delegation/worker-action-journal.ts"],"names":[],"mappings":"AAgBA,MAAM,MAAM,wBAAwB,GAAG,aAAa,GAAG,SAAS,GAAG,WAAW,GAAG,QAAQ,CAAC;AAE1F,MAAM,WAAW,wBAAwB;IACxC,QAAQ,EAAE,MAAM,CAAC;IACjB,eAAe,EAAE,MAAM,CAAC;IACxB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,EAAE,MAAM,CAAC;IAClB,YAAY,EAAE,MAAM,CAAC;CACrB;AAED,MAAM,WAAW,yBAAyB;IACzC,EAAE,EAAE,OAAO,GAAG,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,GAAG,CAAC,EAAE,MAAM,CAAC;CACb;AAED,MAAM,WAAW,sBAAsB;IACtC,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,yBAAyB,CAAC;IAClC,sFAAsF;IACtF,UAAU,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,2BAA2B;IAC3C,IAAI,EAAE,SAAS,CAAC;IAChB,KAAK,EAAE,aAAa,CAAC;IACrB,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,8BAA8B;IAC9C,IAAI,EAAE,qBAAqB,CAAC;IAC5B,KAAK,EAAE,OAAO,CAAC,wBAAwB,EAAE,aAAa,CAAC,CAAC;IACxD,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,EAAE,MAAM,CAAC;IACrB,gBAAgB,EAAE,MAAM,CAAC;IACzB,UAAU,EAAE,MAAM,CAAC;IACnB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,MAAM,uBAAuB,GAAG,2BAA2B,GAAG,8BAA8B,CAAC;AAEnG,MAAM,WAAW,6BAA6B;IAC7C,KAAK,EAAE,wBAAwB,CAAC;IAChC,QAAQ,EAAE,MAAM,CAAC;IACjB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,eAAe,CAAC,EAAE,MAAM,CAAC;CACzB;AA8DD,wGAAwG;AACxG,wBAAgB,2BAA2B,CAAC,GAAG,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,MAAM,CAInF;AAmHD;;;;GAIG;AACH,qBAAa,mBAAmB;IAC/B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;IAC1B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA6C;IACnE,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAA8B;IAEvD,YAAY,KAAK,EAAE,wBAAwB,EAK1C;IAED,OAAO,CAAC,cAAc,EAAE,MAAM,GAAG,6BAA6B,CAO7D;IAED,KAAK,CAAC,KAAK,EAAE,sBAAsB,GAAG,uBAAuB,CAsC5D;IAED,eAAe,CAAC,MAAM,EAAE,2BAA2B,EAAE,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAO,GAAG,IAAI,CAErG;IAED,YAAY,CACX,MAAM,EAAE,2BAA2B,EACnC,UAAU,EAAE,MAAM,EAClB,OAAO,GAAE;QAAE,eAAe,CAAC,EAAE,MAAM,CAAA;KAAO,GACxC,IAAI,CAON;IAED,OAAO,CAAC,cAAc;IA8BtB,OAAO,CAAC,UAAU;IAclB,OAAO,CAAC,WAAW;IAQnB,OAAO,CAAC,aAAa;CA4BrB","sourcesContent":["import { createHash } from \"node:crypto\";\nimport { existsSync } from \"node:fs\";\nimport path from \"node:path\";\nimport { workerActionJournalFile } from \"../agent-paths.ts\";\nimport { withFileLockSync, writeFileAtomicSync } from \"../util/atomic-file.ts\";\nimport { readBoundedTextFileSync } from \"../util/bounded-file.ts\";\nimport { requireBoundedTrimmedText } from \"../util/bounded-value.ts\";\n\nconst JOURNAL_SCHEMA_VERSION = 1;\nconst MAX_IDENTIFIER_CHARS = 256;\nconst MAX_TARGET_CHARS = 2048;\nconst MAX_REASON_CHARS = 512;\nconst MAX_EVIDENCE_POINTER_CHARS = 512;\nconst MAX_ENTRIES = 64;\nconst MAX_JOURNAL_BYTES = 256 * 1024;\n\nexport type WorkerActionJournalState = \"not_started\" | \"unknown\" | \"succeeded\" | \"failed\";\n\nexport interface WorkerActionJournalScope {\n\tagentDir: string;\n\tparentSessionId: string;\n\ttaskId: string;\n\tattemptId: string;\n\tfencingToken: number;\n}\n\nexport interface WorkerActionJournalAction {\n\top: \"write\" | \"edit\";\n\tpath: string;\n\tcontent?: string;\n\told?: string;\n\tnew?: string;\n}\n\nexport interface BeginWorkerActionInput {\n\tindex: number;\n\taction: WorkerActionJournalAction;\n\t/** Realpath-resolved target used by the executor, never model-provided text alone. */\n\ttargetPath: string;\n}\n\nexport interface WorkerActionExecutionPermit {\n\tkind: \"execute\";\n\tstate: \"not_started\";\n\tactionId: string;\n\tactionDigest: string;\n\tnormalizedTarget: string;\n}\n\nexport interface WorkerActionInspectionRequired {\n\tkind: \"inspection_required\";\n\tstate: Exclude<WorkerActionJournalState, \"not_started\">;\n\tactionId: string;\n\tactionDigest: string;\n\tnormalizedTarget: string;\n\treasonCode: string;\n\tevidencePointer?: string;\n}\n\nexport type BeginWorkerActionResult = WorkerActionExecutionPermit | WorkerActionInspectionRequired;\n\nexport interface WorkerActionJournalInspection {\n\tstate: WorkerActionJournalState;\n\tactionId: string;\n\tactionDigest?: string;\n\tnormalizedTarget?: string;\n\treasonCode?: string;\n\tevidencePointer?: string;\n}\n\ninterface PersistedJournalEntry {\n\tactionId: string;\n\tactionDigest: string;\n\tindex: number;\n\tattemptId: string;\n\tfencingToken: number;\n\toperation: \"write\" | \"edit\";\n\tnormalizedTarget: string;\n\tstatus: \"intent\" | \"succeeded\" | \"failed\";\n\tcreatedAt: string;\n\tupdatedAt: string;\n\treasonCode?: string;\n\tevidencePointer?: string;\n}\n\ninterface PersistedJournal {\n\tschemaVersion: number;\n\tscope: WorkerActionJournalIdentity;\n\tentries: PersistedJournalEntry[];\n}\n\ninterface WorkerActionJournalIdentity {\n\tparentSessionId: string;\n\ttaskId: string;\n}\n\nfunction safeFencingToken(value: unknown): number {\n\tif (typeof value !== \"number\" || !Number.isSafeInteger(value) || value < 1)\n\t\tthrow new TypeError(\"Worker action journal fencing token must be a positive safe integer.\");\n\treturn value;\n}\n\nfunction validateScope(scope: WorkerActionJournalScope): Omit<WorkerActionJournalScope, \"agentDir\"> {\n\treturn {\n\t\tparentSessionId: requireBoundedTrimmedText(scope.parentSessionId, MAX_IDENTIFIER_CHARS, \"Parent session id\"),\n\t\ttaskId: requireBoundedTrimmedText(scope.taskId, MAX_IDENTIFIER_CHARS, \"Task id\"),\n\t\tattemptId: requireBoundedTrimmedText(scope.attemptId, MAX_IDENTIFIER_CHARS, \"Attempt id\"),\n\t\tfencingToken: safeFencingToken(scope.fencingToken),\n\t};\n}\n\nfunction journalIdentity(scope: Omit<WorkerActionJournalScope, \"agentDir\">): WorkerActionJournalIdentity {\n\treturn { parentSessionId: scope.parentSessionId, taskId: scope.taskId };\n}\n\nfunction scopeDigest(scope: WorkerActionJournalIdentity): string {\n\treturn createHash(\"sha256\")\n\t\t.update(\"pi-worker-action-journal-scope-v1\")\n\t\t.update(\"\\0\")\n\t\t.update(scope.parentSessionId)\n\t\t.update(\"\\0\")\n\t\t.update(scope.taskId)\n\t\t.update(\"\\0\")\n\t\t.digest(\"hex\");\n}\n\nfunction usesWindowsPath(value: string): boolean {\n\treturn /^[a-zA-Z]:([\\\\/]|$)/.test(value) || value.startsWith(\"\\\\\\\\\") || value.startsWith(\"//\");\n}\n\n/** Canonical lexical identity for an already-authorized real target, including native Windows paths. */\nexport function normalizeWorkerActionTarget(cwd: string, targetPath: string): string {\n\tconst pathApi = usesWindowsPath(cwd) || usesWindowsPath(targetPath) ? path.win32 : path.posix;\n\tconst normalized = pathApi.resolve(cwd, targetPath);\n\treturn pathApi === path.win32 ? normalized.toLowerCase() : normalized;\n}\n\nfunction actionDigest(input: BeginWorkerActionInput, normalizedTarget: string): string {\n\tconst hash = createHash(\"sha256\");\n\thash.update(\"pi-worker-action-v1\");\n\thash.update(\"\\0\");\n\thash.update(input.action.op);\n\thash.update(\"\\0\");\n\thash.update(normalizedTarget);\n\thash.update(\"\\0\");\n\tif (input.action.op === \"write\") {\n\t\thash.update(input.action.content ?? \"\");\n\t} else {\n\t\thash.update(input.action.old ?? \"\");\n\t\thash.update(\"\\0\");\n\t\thash.update(input.action.new ?? \"\");\n\t}\n\treturn hash.digest(\"hex\");\n}\n\nfunction actionId(scope: Omit<WorkerActionJournalScope, \"agentDir\">, index: number, digest: string): string {\n\treturn createHash(\"sha256\")\n\t\t.update(\"pi-worker-action-id-v1\")\n\t\t.update(\"\\0\")\n\t\t.update(scope.attemptId)\n\t\t.update(\"\\0\")\n\t\t.update(String(scope.fencingToken))\n\t\t.update(\"\\0\")\n\t\t.update(String(index))\n\t\t.update(\"\\0\")\n\t\t.update(digest)\n\t\t.digest(\"hex\")\n\t\t.slice(0, 40);\n}\n\nfunction stringValue(value: unknown, label: string, maximum: number): string {\n\tif (typeof value !== \"string\" || value.length === 0 || value.length > maximum) {\n\t\tthrow new Error(`Worker action journal ${label} is invalid.`);\n\t}\n\treturn value;\n}\n\nfunction objectValue(value: unknown, label: string): Record<string, unknown> {\n\tif (!value || typeof value !== \"object\" || Array.isArray(value))\n\t\tthrow new Error(`Worker action journal ${label} is invalid.`);\n\treturn value as Record<string, unknown>;\n}\n\nfunction parseEntry(value: unknown): PersistedJournalEntry {\n\tconst entry = objectValue(value, \"entry\");\n\tconst index = entry.index;\n\tif (typeof index !== \"number\" || !Number.isSafeInteger(index) || index < 0)\n\t\tthrow new Error(\"Worker action journal entry index is invalid.\");\n\tconst parsedIndex = index;\n\tconst operation = entry.operation;\n\tconst status = entry.status;\n\tif (\n\t\t(operation !== \"write\" && operation !== \"edit\") ||\n\t\t(status !== \"intent\" && status !== \"succeeded\" && status !== \"failed\")\n\t) {\n\t\tthrow new Error(\"Worker action journal entry shape is invalid.\");\n\t}\n\tconst reasonCode = entry.reasonCode;\n\tconst evidencePointer = entry.evidencePointer;\n\tif (reasonCode !== undefined && (typeof reasonCode !== \"string\" || reasonCode.length > MAX_REASON_CHARS)) {\n\t\tthrow new Error(\"Worker action journal entry reason is invalid.\");\n\t}\n\tif (\n\t\tevidencePointer !== undefined &&\n\t\t(typeof evidencePointer !== \"string\" || evidencePointer.length > MAX_EVIDENCE_POINTER_CHARS)\n\t) {\n\t\tthrow new Error(\"Worker action journal entry evidence pointer is invalid.\");\n\t}\n\treturn {\n\t\tactionId: stringValue(entry.actionId, \"entry action id\", 128),\n\t\tactionDigest: stringValue(entry.actionDigest, \"entry action digest\", 128),\n\t\tindex: parsedIndex,\n\t\tattemptId: stringValue(entry.attemptId, \"entry attempt id\", MAX_IDENTIFIER_CHARS),\n\t\tfencingToken: safeFencingToken(entry.fencingToken),\n\t\toperation,\n\t\tnormalizedTarget: stringValue(entry.normalizedTarget, \"entry target\", MAX_TARGET_CHARS),\n\t\tstatus,\n\t\tcreatedAt: stringValue(entry.createdAt, \"entry created time\", 128),\n\t\tupdatedAt: stringValue(entry.updatedAt, \"entry updated time\", 128),\n\t\t...(reasonCode ? { reasonCode } : {}),\n\t\t...(evidencePointer ? { evidencePointer } : {}),\n\t};\n}\n\nfunction parseJournal(value: unknown, expectedScope: WorkerActionJournalIdentity): PersistedJournal {\n\tconst journal = objectValue(value, \"document\");\n\tif (journal.schemaVersion !== JOURNAL_SCHEMA_VERSION)\n\t\tthrow new Error(\"Worker action journal schema is unsupported.\");\n\tconst scope = objectValue(journal.scope, \"scope\");\n\tconst parsedScope = {\n\t\tparentSessionId: stringValue(scope.parentSessionId, \"scope parent session\", MAX_IDENTIFIER_CHARS),\n\t\ttaskId: stringValue(scope.taskId, \"scope task\", MAX_IDENTIFIER_CHARS),\n\t};\n\tif (parsedScope.parentSessionId !== expectedScope.parentSessionId || parsedScope.taskId !== expectedScope.taskId) {\n\t\tthrow new Error(\"Worker action journal scope conflicts with the current fenced attempt.\");\n\t}\n\tif (!Array.isArray(journal.entries) || journal.entries.length > MAX_ENTRIES) {\n\t\tthrow new Error(\"Worker action journal entries are invalid.\");\n\t}\n\tconst entries = journal.entries.map(parseEntry);\n\tif (new Set(entries.map((entry) => entry.actionId)).size !== entries.length) {\n\t\tthrow new Error(\"Worker action journal contains duplicate action identities.\");\n\t}\n\treturn { schemaVersion: JOURNAL_SCHEMA_VERSION, scope: parsedScope, entries };\n}\n\nfunction now(): string {\n\treturn new Date().toISOString();\n}\n\n/**\n * Durable intent/receipt journal for model-emitted structured mutations. It deliberately records\n * only action digests and normalized targets; operation payloads can contain source text or secrets\n * and must never leave the model result in persisted orchestration state.\n */\nexport class WorkerActionJournal {\n\treadonly agentDir: string;\n\treadonly filePath: string;\n\tprivate readonly scope: Omit<WorkerActionJournalScope, \"agentDir\">;\n\tprivate readonly identity: WorkerActionJournalIdentity;\n\n\tconstructor(scope: WorkerActionJournalScope) {\n\t\tthis.agentDir = requireBoundedTrimmedText(scope.agentDir, MAX_TARGET_CHARS, \"Agent directory\");\n\t\tthis.scope = validateScope(scope);\n\t\tthis.identity = journalIdentity(this.scope);\n\t\tthis.filePath = workerActionJournalFile(this.agentDir, this.scope.parentSessionId, scopeDigest(this.identity));\n\t}\n\n\tinspect(actionIdentity: string): WorkerActionJournalInspection {\n\t\tconst actionId = requireBoundedTrimmedText(actionIdentity, 128, \"Worker action id\");\n\t\treturn withFileLockSync(this.filePath, () => {\n\t\t\tconst entry = this.readLocked().entries.find((candidate) => candidate.actionId === actionId);\n\t\t\tif (!entry) return { state: \"not_started\", actionId };\n\t\t\treturn this.inspectionFor(entry);\n\t\t});\n\t}\n\n\tbegin(input: BeginWorkerActionInput): BeginWorkerActionResult {\n\t\tif (!Number.isSafeInteger(input.index) || input.index < 0 || input.index >= MAX_ENTRIES) {\n\t\t\tthrow new TypeError(`Worker action index must be a safe integer from 0 through ${MAX_ENTRIES - 1}.`);\n\t\t}\n\t\tconst normalizedTarget = normalizeWorkerActionTarget(this.agentDir, input.targetPath);\n\t\tif (normalizedTarget.length > MAX_TARGET_CHARS) throw new TypeError(\"Worker action target is too long.\");\n\t\tconst digest = actionDigest(input, normalizedTarget);\n\t\tconst id = actionId(this.scope, input.index, digest);\n\t\treturn withFileLockSync(this.filePath, () => {\n\t\t\tconst journal = this.readLocked();\n\t\t\tconst existing = journal.entries.find((entry) => entry.actionId === id);\n\t\t\tif (existing) {\n\t\t\t\tif (existing.actionDigest !== digest) throw new Error(\"Worker action journal action identity collision.\");\n\t\t\t\treturn this.inspectionFor(existing);\n\t\t\t}\n\t\t\tconst previousFence = journal.entries.find(\n\t\t\t\t(entry) =>\n\t\t\t\t\tentry.actionDigest === digest &&\n\t\t\t\t\tentry.operation === input.action.op &&\n\t\t\t\t\tentry.normalizedTarget === normalizedTarget,\n\t\t\t);\n\t\t\tif (previousFence) return this.inspectionFor(previousFence, true);\n\t\t\tconst timestamp = now();\n\t\t\tjournal.entries.push({\n\t\t\t\tactionId: id,\n\t\t\t\tactionDigest: digest,\n\t\t\t\tindex: input.index,\n\t\t\t\tattemptId: this.scope.attemptId,\n\t\t\t\tfencingToken: this.scope.fencingToken,\n\t\t\t\toperation: input.action.op,\n\t\t\t\tnormalizedTarget,\n\t\t\t\tstatus: \"intent\",\n\t\t\t\tcreatedAt: timestamp,\n\t\t\t\tupdatedAt: timestamp,\n\t\t\t});\n\t\t\tthis.writeLocked(journal);\n\t\t\treturn { kind: \"execute\", state: \"not_started\", actionId: id, actionDigest: digest, normalizedTarget };\n\t\t});\n\t}\n\n\trecordSucceeded(permit: WorkerActionExecutionPermit, options: { evidencePointer?: string } = {}): void {\n\t\tthis.recordTerminal(permit, \"succeeded\", \"worker_action_applied\", options.evidencePointer);\n\t}\n\n\trecordFailed(\n\t\tpermit: WorkerActionExecutionPermit,\n\t\treasonCode: string,\n\t\toptions: { evidencePointer?: string } = {},\n\t): void {\n\t\tthis.recordTerminal(\n\t\t\tpermit,\n\t\t\t\"failed\",\n\t\t\trequireBoundedTrimmedText(reasonCode, MAX_REASON_CHARS, \"Worker action failure reason\"),\n\t\t\toptions.evidencePointer,\n\t\t);\n\t}\n\n\tprivate recordTerminal(\n\t\tpermit: WorkerActionExecutionPermit,\n\t\tstatus: \"succeeded\" | \"failed\",\n\t\treasonCode: string,\n\t\tevidencePointer: string | undefined,\n\t): void {\n\t\tconst boundedEvidence = evidencePointer\n\t\t\t? requireBoundedTrimmedText(evidencePointer, MAX_EVIDENCE_POINTER_CHARS, \"Worker action evidence pointer\")\n\t\t\t: undefined;\n\t\twithFileLockSync(this.filePath, () => {\n\t\t\tconst journal = this.readLocked();\n\t\t\tconst entry = journal.entries.find((candidate) => candidate.actionId === permit.actionId);\n\t\t\tif (\n\t\t\t\t!entry ||\n\t\t\t\tentry.actionDigest !== permit.actionDigest ||\n\t\t\t\tentry.normalizedTarget !== permit.normalizedTarget ||\n\t\t\t\tentry.attemptId !== this.scope.attemptId ||\n\t\t\t\tentry.fencingToken !== this.scope.fencingToken\n\t\t\t) {\n\t\t\t\tthrow new Error(\"Worker action journal receipt does not match a persisted intent.\");\n\t\t\t}\n\t\t\tif (entry.status !== \"intent\") throw new Error(\"Worker action journal intent already has a terminal receipt.\");\n\t\t\tentry.status = status;\n\t\t\tentry.reasonCode = reasonCode;\n\t\t\tentry.updatedAt = now();\n\t\t\tif (boundedEvidence) entry.evidencePointer = boundedEvidence;\n\t\t\tthis.writeLocked(journal);\n\t\t});\n\t}\n\n\tprivate readLocked(): PersistedJournal {\n\t\tif (!existsSync(this.filePath)) {\n\t\t\treturn { schemaVersion: JOURNAL_SCHEMA_VERSION, scope: structuredClone(this.identity), entries: [] };\n\t\t}\n\t\tconst content = readBoundedTextFileSync(this.filePath, MAX_JOURNAL_BYTES, \"Worker action journal\");\n\t\tlet raw: unknown;\n\t\ttry {\n\t\t\traw = JSON.parse(content);\n\t\t} catch {\n\t\t\tthrow new Error(\"Worker action journal is unreadable; refusing mutation replay.\");\n\t\t}\n\t\treturn parseJournal(raw, this.identity);\n\t}\n\n\tprivate writeLocked(journal: PersistedJournal): void {\n\t\tconst serialized = `${JSON.stringify(journal)}\\n`;\n\t\tif (Buffer.byteLength(serialized, \"utf-8\") > MAX_JOURNAL_BYTES) {\n\t\t\tthrow new Error(\"Worker action journal would exceed its byte limit.\");\n\t\t}\n\t\twriteFileAtomicSync(this.filePath, serialized, { mode: 0o600 });\n\t}\n\n\tprivate inspectionFor(entry: PersistedJournalEntry, fromPreviousFence = false): WorkerActionInspectionRequired {\n\t\tif (entry.status === \"intent\") {\n\t\t\treturn {\n\t\t\t\tkind: \"inspection_required\",\n\t\t\t\tstate: \"unknown\",\n\t\t\t\tactionId: entry.actionId,\n\t\t\t\tactionDigest: entry.actionDigest,\n\t\t\t\tnormalizedTarget: entry.normalizedTarget,\n\t\t\t\treasonCode: fromPreviousFence\n\t\t\t\t\t? \"worker_action_prior_fence_requires_inspection\"\n\t\t\t\t\t: \"worker_action_outcome_unknown\",\n\t\t\t\t...(entry.evidencePointer ? { evidencePointer: entry.evidencePointer } : {}),\n\t\t\t};\n\t\t}\n\t\treturn {\n\t\t\tkind: \"inspection_required\",\n\t\t\tstate: entry.status,\n\t\t\tactionId: entry.actionId,\n\t\t\tactionDigest: entry.actionDigest,\n\t\t\tnormalizedTarget: entry.normalizedTarget,\n\t\t\treasonCode: fromPreviousFence\n\t\t\t\t? \"worker_action_prior_fence_requires_inspection\"\n\t\t\t\t: entry.status === \"succeeded\"\n\t\t\t\t\t? \"worker_action_already_succeeded\"\n\t\t\t\t\t: \"worker_action_previously_failed\",\n\t\t\t...(entry.evidencePointer ? { evidencePointer: entry.evidencePointer } : {}),\n\t\t};\n\t}\n}\n"]}
@@ -0,0 +1,297 @@
1
+ import { createHash } from "node:crypto";
2
+ import { existsSync } from "node:fs";
3
+ import path from "node:path";
4
+ import { workerActionJournalFile } from "../agent-paths.js";
5
+ import { withFileLockSync, writeFileAtomicSync } from "../util/atomic-file.js";
6
+ import { readBoundedTextFileSync } from "../util/bounded-file.js";
7
+ import { requireBoundedTrimmedText } from "../util/bounded-value.js";
8
+ const JOURNAL_SCHEMA_VERSION = 1;
9
+ const MAX_IDENTIFIER_CHARS = 256;
10
+ const MAX_TARGET_CHARS = 2048;
11
+ const MAX_REASON_CHARS = 512;
12
+ const MAX_EVIDENCE_POINTER_CHARS = 512;
13
+ const MAX_ENTRIES = 64;
14
+ const MAX_JOURNAL_BYTES = 256 * 1024;
15
+ function safeFencingToken(value) {
16
+ if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1)
17
+ throw new TypeError("Worker action journal fencing token must be a positive safe integer.");
18
+ return value;
19
+ }
20
+ function validateScope(scope) {
21
+ return {
22
+ parentSessionId: requireBoundedTrimmedText(scope.parentSessionId, MAX_IDENTIFIER_CHARS, "Parent session id"),
23
+ taskId: requireBoundedTrimmedText(scope.taskId, MAX_IDENTIFIER_CHARS, "Task id"),
24
+ attemptId: requireBoundedTrimmedText(scope.attemptId, MAX_IDENTIFIER_CHARS, "Attempt id"),
25
+ fencingToken: safeFencingToken(scope.fencingToken),
26
+ };
27
+ }
28
+ function journalIdentity(scope) {
29
+ return { parentSessionId: scope.parentSessionId, taskId: scope.taskId };
30
+ }
31
+ function scopeDigest(scope) {
32
+ return createHash("sha256")
33
+ .update("pi-worker-action-journal-scope-v1")
34
+ .update("\0")
35
+ .update(scope.parentSessionId)
36
+ .update("\0")
37
+ .update(scope.taskId)
38
+ .update("\0")
39
+ .digest("hex");
40
+ }
41
+ function usesWindowsPath(value) {
42
+ return /^[a-zA-Z]:([\\/]|$)/.test(value) || value.startsWith("\\\\") || value.startsWith("//");
43
+ }
44
+ /** Canonical lexical identity for an already-authorized real target, including native Windows paths. */
45
+ export function normalizeWorkerActionTarget(cwd, targetPath) {
46
+ const pathApi = usesWindowsPath(cwd) || usesWindowsPath(targetPath) ? path.win32 : path.posix;
47
+ const normalized = pathApi.resolve(cwd, targetPath);
48
+ return pathApi === path.win32 ? normalized.toLowerCase() : normalized;
49
+ }
50
+ function actionDigest(input, normalizedTarget) {
51
+ const hash = createHash("sha256");
52
+ hash.update("pi-worker-action-v1");
53
+ hash.update("\0");
54
+ hash.update(input.action.op);
55
+ hash.update("\0");
56
+ hash.update(normalizedTarget);
57
+ hash.update("\0");
58
+ if (input.action.op === "write") {
59
+ hash.update(input.action.content ?? "");
60
+ }
61
+ else {
62
+ hash.update(input.action.old ?? "");
63
+ hash.update("\0");
64
+ hash.update(input.action.new ?? "");
65
+ }
66
+ return hash.digest("hex");
67
+ }
68
+ function actionId(scope, index, digest) {
69
+ return createHash("sha256")
70
+ .update("pi-worker-action-id-v1")
71
+ .update("\0")
72
+ .update(scope.attemptId)
73
+ .update("\0")
74
+ .update(String(scope.fencingToken))
75
+ .update("\0")
76
+ .update(String(index))
77
+ .update("\0")
78
+ .update(digest)
79
+ .digest("hex")
80
+ .slice(0, 40);
81
+ }
82
+ function stringValue(value, label, maximum) {
83
+ if (typeof value !== "string" || value.length === 0 || value.length > maximum) {
84
+ throw new Error(`Worker action journal ${label} is invalid.`);
85
+ }
86
+ return value;
87
+ }
88
+ function objectValue(value, label) {
89
+ if (!value || typeof value !== "object" || Array.isArray(value))
90
+ throw new Error(`Worker action journal ${label} is invalid.`);
91
+ return value;
92
+ }
93
+ function parseEntry(value) {
94
+ const entry = objectValue(value, "entry");
95
+ const index = entry.index;
96
+ if (typeof index !== "number" || !Number.isSafeInteger(index) || index < 0)
97
+ throw new Error("Worker action journal entry index is invalid.");
98
+ const parsedIndex = index;
99
+ const operation = entry.operation;
100
+ const status = entry.status;
101
+ if ((operation !== "write" && operation !== "edit") ||
102
+ (status !== "intent" && status !== "succeeded" && status !== "failed")) {
103
+ throw new Error("Worker action journal entry shape is invalid.");
104
+ }
105
+ const reasonCode = entry.reasonCode;
106
+ const evidencePointer = entry.evidencePointer;
107
+ if (reasonCode !== undefined && (typeof reasonCode !== "string" || reasonCode.length > MAX_REASON_CHARS)) {
108
+ throw new Error("Worker action journal entry reason is invalid.");
109
+ }
110
+ if (evidencePointer !== undefined &&
111
+ (typeof evidencePointer !== "string" || evidencePointer.length > MAX_EVIDENCE_POINTER_CHARS)) {
112
+ throw new Error("Worker action journal entry evidence pointer is invalid.");
113
+ }
114
+ return {
115
+ actionId: stringValue(entry.actionId, "entry action id", 128),
116
+ actionDigest: stringValue(entry.actionDigest, "entry action digest", 128),
117
+ index: parsedIndex,
118
+ attemptId: stringValue(entry.attemptId, "entry attempt id", MAX_IDENTIFIER_CHARS),
119
+ fencingToken: safeFencingToken(entry.fencingToken),
120
+ operation,
121
+ normalizedTarget: stringValue(entry.normalizedTarget, "entry target", MAX_TARGET_CHARS),
122
+ status,
123
+ createdAt: stringValue(entry.createdAt, "entry created time", 128),
124
+ updatedAt: stringValue(entry.updatedAt, "entry updated time", 128),
125
+ ...(reasonCode ? { reasonCode } : {}),
126
+ ...(evidencePointer ? { evidencePointer } : {}),
127
+ };
128
+ }
129
+ function parseJournal(value, expectedScope) {
130
+ const journal = objectValue(value, "document");
131
+ if (journal.schemaVersion !== JOURNAL_SCHEMA_VERSION)
132
+ throw new Error("Worker action journal schema is unsupported.");
133
+ const scope = objectValue(journal.scope, "scope");
134
+ const parsedScope = {
135
+ parentSessionId: stringValue(scope.parentSessionId, "scope parent session", MAX_IDENTIFIER_CHARS),
136
+ taskId: stringValue(scope.taskId, "scope task", MAX_IDENTIFIER_CHARS),
137
+ };
138
+ if (parsedScope.parentSessionId !== expectedScope.parentSessionId || parsedScope.taskId !== expectedScope.taskId) {
139
+ throw new Error("Worker action journal scope conflicts with the current fenced attempt.");
140
+ }
141
+ if (!Array.isArray(journal.entries) || journal.entries.length > MAX_ENTRIES) {
142
+ throw new Error("Worker action journal entries are invalid.");
143
+ }
144
+ const entries = journal.entries.map(parseEntry);
145
+ if (new Set(entries.map((entry) => entry.actionId)).size !== entries.length) {
146
+ throw new Error("Worker action journal contains duplicate action identities.");
147
+ }
148
+ return { schemaVersion: JOURNAL_SCHEMA_VERSION, scope: parsedScope, entries };
149
+ }
150
+ function now() {
151
+ return new Date().toISOString();
152
+ }
153
+ /**
154
+ * Durable intent/receipt journal for model-emitted structured mutations. It deliberately records
155
+ * only action digests and normalized targets; operation payloads can contain source text or secrets
156
+ * and must never leave the model result in persisted orchestration state.
157
+ */
158
+ export class WorkerActionJournal {
159
+ agentDir;
160
+ filePath;
161
+ scope;
162
+ identity;
163
+ constructor(scope) {
164
+ this.agentDir = requireBoundedTrimmedText(scope.agentDir, MAX_TARGET_CHARS, "Agent directory");
165
+ this.scope = validateScope(scope);
166
+ this.identity = journalIdentity(this.scope);
167
+ this.filePath = workerActionJournalFile(this.agentDir, this.scope.parentSessionId, scopeDigest(this.identity));
168
+ }
169
+ inspect(actionIdentity) {
170
+ const actionId = requireBoundedTrimmedText(actionIdentity, 128, "Worker action id");
171
+ return withFileLockSync(this.filePath, () => {
172
+ const entry = this.readLocked().entries.find((candidate) => candidate.actionId === actionId);
173
+ if (!entry)
174
+ return { state: "not_started", actionId };
175
+ return this.inspectionFor(entry);
176
+ });
177
+ }
178
+ begin(input) {
179
+ if (!Number.isSafeInteger(input.index) || input.index < 0 || input.index >= MAX_ENTRIES) {
180
+ throw new TypeError(`Worker action index must be a safe integer from 0 through ${MAX_ENTRIES - 1}.`);
181
+ }
182
+ const normalizedTarget = normalizeWorkerActionTarget(this.agentDir, input.targetPath);
183
+ if (normalizedTarget.length > MAX_TARGET_CHARS)
184
+ throw new TypeError("Worker action target is too long.");
185
+ const digest = actionDigest(input, normalizedTarget);
186
+ const id = actionId(this.scope, input.index, digest);
187
+ return withFileLockSync(this.filePath, () => {
188
+ const journal = this.readLocked();
189
+ const existing = journal.entries.find((entry) => entry.actionId === id);
190
+ if (existing) {
191
+ if (existing.actionDigest !== digest)
192
+ throw new Error("Worker action journal action identity collision.");
193
+ return this.inspectionFor(existing);
194
+ }
195
+ const previousFence = journal.entries.find((entry) => entry.actionDigest === digest &&
196
+ entry.operation === input.action.op &&
197
+ entry.normalizedTarget === normalizedTarget);
198
+ if (previousFence)
199
+ return this.inspectionFor(previousFence, true);
200
+ const timestamp = now();
201
+ journal.entries.push({
202
+ actionId: id,
203
+ actionDigest: digest,
204
+ index: input.index,
205
+ attemptId: this.scope.attemptId,
206
+ fencingToken: this.scope.fencingToken,
207
+ operation: input.action.op,
208
+ normalizedTarget,
209
+ status: "intent",
210
+ createdAt: timestamp,
211
+ updatedAt: timestamp,
212
+ });
213
+ this.writeLocked(journal);
214
+ return { kind: "execute", state: "not_started", actionId: id, actionDigest: digest, normalizedTarget };
215
+ });
216
+ }
217
+ recordSucceeded(permit, options = {}) {
218
+ this.recordTerminal(permit, "succeeded", "worker_action_applied", options.evidencePointer);
219
+ }
220
+ recordFailed(permit, reasonCode, options = {}) {
221
+ this.recordTerminal(permit, "failed", requireBoundedTrimmedText(reasonCode, MAX_REASON_CHARS, "Worker action failure reason"), options.evidencePointer);
222
+ }
223
+ recordTerminal(permit, status, reasonCode, evidencePointer) {
224
+ const boundedEvidence = evidencePointer
225
+ ? requireBoundedTrimmedText(evidencePointer, MAX_EVIDENCE_POINTER_CHARS, "Worker action evidence pointer")
226
+ : undefined;
227
+ withFileLockSync(this.filePath, () => {
228
+ const journal = this.readLocked();
229
+ const entry = journal.entries.find((candidate) => candidate.actionId === permit.actionId);
230
+ if (!entry ||
231
+ entry.actionDigest !== permit.actionDigest ||
232
+ entry.normalizedTarget !== permit.normalizedTarget ||
233
+ entry.attemptId !== this.scope.attemptId ||
234
+ entry.fencingToken !== this.scope.fencingToken) {
235
+ throw new Error("Worker action journal receipt does not match a persisted intent.");
236
+ }
237
+ if (entry.status !== "intent")
238
+ throw new Error("Worker action journal intent already has a terminal receipt.");
239
+ entry.status = status;
240
+ entry.reasonCode = reasonCode;
241
+ entry.updatedAt = now();
242
+ if (boundedEvidence)
243
+ entry.evidencePointer = boundedEvidence;
244
+ this.writeLocked(journal);
245
+ });
246
+ }
247
+ readLocked() {
248
+ if (!existsSync(this.filePath)) {
249
+ return { schemaVersion: JOURNAL_SCHEMA_VERSION, scope: structuredClone(this.identity), entries: [] };
250
+ }
251
+ const content = readBoundedTextFileSync(this.filePath, MAX_JOURNAL_BYTES, "Worker action journal");
252
+ let raw;
253
+ try {
254
+ raw = JSON.parse(content);
255
+ }
256
+ catch {
257
+ throw new Error("Worker action journal is unreadable; refusing mutation replay.");
258
+ }
259
+ return parseJournal(raw, this.identity);
260
+ }
261
+ writeLocked(journal) {
262
+ const serialized = `${JSON.stringify(journal)}\n`;
263
+ if (Buffer.byteLength(serialized, "utf-8") > MAX_JOURNAL_BYTES) {
264
+ throw new Error("Worker action journal would exceed its byte limit.");
265
+ }
266
+ writeFileAtomicSync(this.filePath, serialized, { mode: 0o600 });
267
+ }
268
+ inspectionFor(entry, fromPreviousFence = false) {
269
+ if (entry.status === "intent") {
270
+ return {
271
+ kind: "inspection_required",
272
+ state: "unknown",
273
+ actionId: entry.actionId,
274
+ actionDigest: entry.actionDigest,
275
+ normalizedTarget: entry.normalizedTarget,
276
+ reasonCode: fromPreviousFence
277
+ ? "worker_action_prior_fence_requires_inspection"
278
+ : "worker_action_outcome_unknown",
279
+ ...(entry.evidencePointer ? { evidencePointer: entry.evidencePointer } : {}),
280
+ };
281
+ }
282
+ return {
283
+ kind: "inspection_required",
284
+ state: entry.status,
285
+ actionId: entry.actionId,
286
+ actionDigest: entry.actionDigest,
287
+ normalizedTarget: entry.normalizedTarget,
288
+ reasonCode: fromPreviousFence
289
+ ? "worker_action_prior_fence_requires_inspection"
290
+ : entry.status === "succeeded"
291
+ ? "worker_action_already_succeeded"
292
+ : "worker_action_previously_failed",
293
+ ...(entry.evidencePointer ? { evidencePointer: entry.evidencePointer } : {}),
294
+ };
295
+ }
296
+ }
297
+ //# sourceMappingURL=worker-action-journal.js.map