@ornexus/neocortex 4.60.73 → 4.60.74

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 (241) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1216 -1210
  3. package/install.ps1 +1 -1
  4. package/install.sh +1 -1
  5. package/package.json +2 -2
  6. package/packages/client/dist/adapters/adapter-registry.js +1 -108
  7. package/packages/client/dist/adapters/antigravity-adapter.js +2 -77
  8. package/packages/client/dist/adapters/claude-code-adapter.js +3 -79
  9. package/packages/client/dist/adapters/codex-adapter.js +2 -80
  10. package/packages/client/dist/adapters/cursor-adapter.js +4 -115
  11. package/packages/client/dist/adapters/gemini-adapter.js +2 -71
  12. package/packages/client/dist/adapters/grok-adapter.js +2 -42
  13. package/packages/client/dist/adapters/index.js +1 -22
  14. package/packages/client/dist/adapters/platform-detector.js +1 -212
  15. package/packages/client/dist/adapters/target-adapter.js +0 -12
  16. package/packages/client/dist/adapters/vscode-adapter.js +2 -72
  17. package/packages/client/dist/agent/refresh-stubs.js +2 -417
  18. package/packages/client/dist/agent/update-agent-yaml.js +1 -102
  19. package/packages/client/dist/agent/update-description.js +1 -251
  20. package/packages/client/dist/cache/crypto-utils.js +1 -78
  21. package/packages/client/dist/cache/encrypted-cache.js +1 -108
  22. package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
  23. package/packages/client/dist/cache/index.js +1 -13
  24. package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
  25. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
  26. package/packages/client/dist/checkpoint/index.js +1 -11
  27. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
  28. package/packages/client/dist/cli.js +5 -358
  29. package/packages/client/dist/commands/activate.js +8 -394
  30. package/packages/client/dist/commands/architecture-answers.js +7 -274
  31. package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
  32. package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
  33. package/packages/client/dist/commands/architecture-root-binding.js +1 -51
  34. package/packages/client/dist/commands/cache-status.js +2 -112
  35. package/packages/client/dist/commands/config.js +1 -88
  36. package/packages/client/dist/commands/doctor.js +2 -635
  37. package/packages/client/dist/commands/invoke.js +143 -7200
  38. package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
  39. package/packages/client/dist/commands/legacy-story-branch.js +1 -96
  40. package/packages/client/dist/commands/legacy-story-pr.js +1 -276
  41. package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
  42. package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
  43. package/packages/client/dist/commands/mutation-qa-git.js +1 -41
  44. package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
  45. package/packages/client/dist/commands/mutation-qa-run.js +3 -219
  46. package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
  47. package/packages/client/dist/commands/mutation-qa.js +1 -220
  48. package/packages/client/dist/commands/native-agent.js +2 -136
  49. package/packages/client/dist/commands/planning-diagnosis.js +1 -43
  50. package/packages/client/dist/commands/planning-generation.js +1 -53
  51. package/packages/client/dist/commands/planning-memory.js +1 -40
  52. package/packages/client/dist/commands/planning-research.js +1 -42
  53. package/packages/client/dist/commands/private-session.js +1 -75
  54. package/packages/client/dist/commands/property-qa.js +1 -139
  55. package/packages/client/dist/commands/qa-control.js +1 -16
  56. package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
  57. package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
  58. package/packages/client/dist/commands/qa-scan-capture.js +5 -663
  59. package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
  60. package/packages/client/dist/commands/qa-scan-review.js +5 -826
  61. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
  62. package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
  63. package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
  64. package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
  65. package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
  66. package/packages/client/dist/commands/refactor-characterization.js +21 -671
  67. package/packages/client/dist/commands/refactor-commit.js +13 -399
  68. package/packages/client/dist/commands/refactor-control.js +3 -142
  69. package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
  70. package/packages/client/dist/commands/refactor-review.js +5 -283
  71. package/packages/client/dist/commands/refactor-root.js +7 -588
  72. package/packages/client/dist/commands/refresh-memory.js +3 -156
  73. package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
  74. package/packages/client/dist/commands/story-checkpoint.js +1 -171
  75. package/packages/client/dist/config/profile-directory.js +1 -13
  76. package/packages/client/dist/config/resolver-selection.js +1 -278
  77. package/packages/client/dist/config/secure-config.js +12 -281
  78. package/packages/client/dist/config.js +2 -223
  79. package/packages/client/dist/constants.js +1 -25
  80. package/packages/client/dist/context/context-collector.js +2 -222
  81. package/packages/client/dist/context/context-sanitizer.js +1 -145
  82. package/packages/client/dist/continuity/autonomous-governance.js +1 -285
  83. package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
  84. package/packages/client/dist/continuity/invoke-hooks.js +1 -129
  85. package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
  86. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
  87. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
  88. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
  89. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
  90. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
  91. package/packages/client/dist/continuity/native-agent-store.js +1 -69
  92. package/packages/client/dist/continuity/native-agent-types.js +1 -90
  93. package/packages/client/dist/continuity/outbox.js +1 -117
  94. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
  95. package/packages/client/dist/continuity/sqlite-store.js +81 -2612
  96. package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
  97. package/packages/client/dist/errors/error-messages.js +2 -228
  98. package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
  99. package/packages/client/dist/evidence/collector.js +1 -347
  100. package/packages/client/dist/evidence/index.js +1 -1
  101. package/packages/client/dist/evidence/types.js +0 -2
  102. package/packages/client/dist/fs/atomic-state-replace.js +1 -152
  103. package/packages/client/dist/generated/command-registry.generated.js +1 -4076
  104. package/packages/client/dist/generated/public-projections.generated.js +1 -149
  105. package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
  106. package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
  107. package/packages/client/dist/git/epic-operational-state.js +2 -672
  108. package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
  109. package/packages/client/dist/git/git-lifecycle-store.d.ts +23 -0
  110. package/packages/client/dist/git/git-lifecycle-store.js +10 -1981
  111. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
  112. package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
  113. package/packages/client/dist/git/legacy-story-pr.js +70 -3538
  114. package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
  115. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
  116. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
  117. package/packages/client/dist/i18n/first-run.js +2 -60
  118. package/packages/client/dist/index.js +1 -47
  119. package/packages/client/dist/invocation/invoke-input.js +1 -24
  120. package/packages/client/dist/license/index.js +1 -5
  121. package/packages/client/dist/license/license-client.js +1 -304
  122. package/packages/client/dist/machine/fingerprint.js +2 -163
  123. package/packages/client/dist/machine/index.js +1 -5
  124. package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
  125. package/packages/client/dist/memory/project-memory-writer.js +40 -1007
  126. package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
  127. package/packages/client/dist/migrations/epic-lifecycle-backfill.js +3 -1060
  128. package/packages/client/dist/migrations/project-identity-capability.js +1 -50
  129. package/packages/client/dist/migrations/project-identity.js +7 -493
  130. package/packages/client/dist/migrations/state-json.js +4 -393
  131. package/packages/client/dist/policy/architecture-policy.js +2 -184
  132. package/packages/client/dist/policy/index.js +1 -7
  133. package/packages/client/dist/policy/shared-policy-types.js +0 -38
  134. package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
  135. package/packages/client/dist/private-execution/clean-baseline.js +2 -279
  136. package/packages/client/dist/private-execution/codex-executor.js +4 -574
  137. package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
  138. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
  139. package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
  140. package/packages/client/dist/private-execution/delivery.js +13 -410
  141. package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
  142. package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
  143. package/packages/client/dist/private-execution/implementation-validation.js +2 -106
  144. package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
  145. package/packages/client/dist/private-execution/isolated-session.js +5 -725
  146. package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
  147. package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
  148. package/packages/client/dist/private-execution/pact-test-source.js +1 -258
  149. package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
  150. package/packages/client/dist/private-execution/pact-write-set.js +1 -172
  151. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
  152. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
  153. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
  154. package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
  155. package/packages/client/dist/private-execution/private-report-store.js +1 -42
  156. package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
  157. package/packages/client/dist/private-execution/property-test-choices.js +3 -147
  158. package/packages/client/dist/private-execution/property-test-plan.js +7 -271
  159. package/packages/client/dist/private-execution/property-test-review.js +4 -258
  160. package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
  161. package/packages/client/dist/private-execution/property-test-source.js +1 -139
  162. package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
  163. package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
  164. package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
  165. package/packages/client/dist/private-execution/root-memory-request.js +1 -29
  166. package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
  167. package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
  168. package/packages/client/dist/private-execution/session-lease.js +1 -63
  169. package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
  170. package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
  171. package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
  172. package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
  173. package/packages/client/dist/private-execution/ux-write-set.js +2 -191
  174. package/packages/client/dist/registry/registry-reconciliation.js +1 -234
  175. package/packages/client/dist/resilience/circuit-breaker.js +1 -170
  176. package/packages/client/dist/resilience/degradation-manager.js +1 -164
  177. package/packages/client/dist/resilience/freshness-indicator.js +1 -100
  178. package/packages/client/dist/resilience/index.js +1 -8
  179. package/packages/client/dist/resilience/recovery-detector.js +1 -74
  180. package/packages/client/dist/resolvers/asset-resolver.js +0 -13
  181. package/packages/client/dist/resolvers/local-resolver.js +8 -255
  182. package/packages/client/dist/resolvers/remote-resolver.js +1 -233
  183. package/packages/client/dist/runner/binary.js +1 -404
  184. package/packages/client/dist/runner/cli.js +17 -1571
  185. package/packages/client/dist/runner/headless/adapters.js +1 -49
  186. package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
  187. package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
  188. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
  189. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +1 -1
  190. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
  191. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +2 -0
  192. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +10 -1236
  193. package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +18 -2
  194. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
  195. package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
  196. package/packages/client/dist/runner/headless/managed-profile.js +1 -132
  197. package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
  198. package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
  199. package/packages/client/dist/runner/headless/resolver.js +1 -231
  200. package/packages/client/dist/runner/headless/run-yolo.js +1 -885
  201. package/packages/client/dist/runner/headless/run-yoloop.d.ts +1 -0
  202. package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
  203. package/packages/client/dist/runner/headless/types.js +2 -574
  204. package/packages/client/dist/runner/local-console.js +13 -396
  205. package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
  206. package/packages/client/dist/runner/project-identity.js +1 -106
  207. package/packages/client/dist/runner/scheduler.js +7 -995
  208. package/packages/client/dist/runner-cli.js +2 -18
  209. package/packages/client/dist/state/invocation-shape.js +1 -13
  210. package/packages/client/dist/state/project-state-snapshot.js +1 -1731
  211. package/packages/client/dist/state/state-json-repair.js +3 -785
  212. package/packages/client/dist/state/structural-dag-projection.js +1 -118
  213. package/packages/client/dist/telemetry/index.js +1 -5
  214. package/packages/client/dist/telemetry/offline-queue.js +1 -131
  215. package/packages/client/dist/tier/index.js +1 -5
  216. package/packages/client/dist/tier/tier-aware-client.js +1 -405
  217. package/packages/client/dist/types/index.js +1 -38
  218. package/packages/client/dist/version.js +1 -27
  219. package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
  220. package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
  221. package/packages/client/dist/yolo/spec-envelope-collector.js +5 -184
  222. package/packages/client/dist/yoloop/discovery-hook.js +2 -300
  223. package/packages/client/dist/yoloop/index.js +1 -8
  224. package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
  225. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
  226. package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
  227. package/packages/client/dist/yoloop/target-normalization.js +1 -180
  228. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1920
  229. package/packages/shared/dist/yolo/change-evidence.js +1 -1
  230. package/packages/shared/dist/yoloop/epic-terminal-git.js +144 -2
  231. package/targets-stubs/antigravity/gemini.md +1 -1
  232. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  233. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  234. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  235. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  236. package/targets-stubs/claude-code/neocortex.md +2 -2
  237. package/targets-stubs/codex/AGENTS.md +1 -1
  238. package/targets-stubs/cursor/agent.md +2 -2
  239. package/targets-stubs/gemini-cli/agent.md +2 -2
  240. package/targets-stubs/opencode/neocortex-root.md +1 -1
  241. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,1234 +1,4 @@
1
- /** Root-owned two-phase commit/checkpoint boundary for direct `*yolo` runs. */
2
- import { execFile } from 'node:child_process';
3
- import { createHash, randomBytes, timingSafeEqual } from 'node:crypto';
4
- import { readFile } from 'node:fs/promises';
5
- import { join, resolve } from 'node:path';
6
- import { promisify } from 'node:util';
7
- import { readRootMemoryEffectForCheckpoint } from '../private-execution/root-memory-scope.js';
8
- import { rootMemoryEffectDigest, verifyRootMemoryPhysicalWriteSet } from '../private-execution/root-memory-git-evidence.js';
9
- import { acquireGitLifecyclePhysicalIntegrationLock, applyGitLifecycleRuntimeOverlay, computeImmutableStoryQaEvidenceDigest, computeGitLifecyclePhysicalIntegrationLockOwnerDigest, computeP205StoryQaEvidenceDigest, computeLegacyDirectYoloRecoveryReceiptRef, ensureRuntimeEpic, ensureRuntimeStory, ensureGitLifecyclePrivateChildDirectory, executeP205TransientAuthority, projectP205TransientExecutionEvidence, publicStoryReviewArtifactFromGit, LEGACY_DIRECT_YOLO_RECOVERY_COMMITS, mutateGitLifecycleRuntime, P205_COMPLETE_COMMAND, readGitLifecycleRuntime, gitLifecycleRuntimeDirectory, assertGitLifecyclePrivateFile, releaseGitLifecyclePhysicalIntegrationLock, releaseGitLifecyclePhysicalIntegrationLockForCheckpoint, verifyGitLifecyclePhysicalIntegrationLock, verifyAcceptedGitLifecycleStoryCheckpoint, } from './git-lifecycle-store.js';
10
- import { anchoredAtomicWriteFile } from './secure-filesystem-boundary.js';
11
- import { GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID, GIT_LIFECYCLE_REVIEW_PR_STEP_ID, GIT_LIFECYCLE_SETUP_BRANCH_STEP_ID, } from './git-lifecycle-step-ids.js';
12
- const execFileAsync = promisify(execFile);
13
- /**
14
- * Productive P207 setup boundary. It owns only the current checkout and the
15
- * epic branch; it never creates, removes or repositions a worktree. Existing
16
- * staged and unstaged bytes must remain identical across the branch switch.
17
- */
18
- export async function prepareDirectYoloSetup(options) {
19
- try {
20
- const authority = await resolveLogicalAuthority(options.projectRoot, options.storyId);
21
- const nowIso = normalizedTime(options.nowIso);
22
- const nowMs = Date.parse(nowIso);
23
- const currentBranch = await git(authority.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
24
- const currentHead = await git(authority.projectRoot, ['rev-parse', 'HEAD']);
25
- const runtimeBefore = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
26
- const runtimeEpic = asRecord(runtimeBefore.epics[authority.epicId]);
27
- const currentLease = asRecord(runtimeEpic?.branch_lease);
28
- const liveLease = currentLease && Number.isFinite(Date.parse(String(currentLease.expiresAt)))
29
- && Date.parse(String(currentLease.expiresAt)) > nowMs;
30
- if (liveLease && currentLease?.ownerStoryId !== options.storyId) {
31
- return failure('direct-yolo-writer-active');
32
- }
33
- let originBinding = validOriginBinding(runtimeEpic?.origin_binding, authority.executionBranch, authority.originBranch);
34
- if (currentBranch === authority.executionBranch) {
35
- if (!originBinding)
36
- return failure('direct-yolo-origin-binding-invalid');
37
- }
38
- else {
39
- if (currentBranch !== authority.originBranch)
40
- return failure('direct-yolo-current-branch-mismatch');
41
- if (originBinding && originBinding.originHeadSha !== currentHead) {
42
- return failure('direct-yolo-origin-binding-conflict');
43
- }
44
- originBinding ??= {
45
- schemaVersion: 1,
46
- originBranch: authority.originBranch,
47
- originHeadSha: currentHead,
48
- executionBranch: authority.executionBranch,
49
- capturedFromCurrentCheckout: true,
50
- capturedAt: nowIso,
51
- };
52
- const occupiedElsewhere = (await worktreeBranches(authority.projectRoot)).some((item) => item.branch === authority.executionBranch && resolve(item.path) !== authority.projectRoot);
53
- if (occupiedElsewhere)
54
- return failure('direct-yolo-execution-branch-checked-out-elsewhere');
55
- const checkoutBefore = await checkoutPayload(authority.projectRoot);
56
- const executionRef = `refs/heads/${authority.executionBranch}`;
57
- if (await gitExitOk(authority.projectRoot, ['show-ref', '--verify', '--quiet', executionRef])) {
58
- const executionHead = await git(authority.projectRoot, ['rev-parse', executionRef]);
59
- if (executionHead !== currentHead) {
60
- if (!(await gitExitOk(authority.projectRoot, ['merge-base', '--is-ancestor', executionHead, currentHead]))) {
61
- return failure('direct-yolo-execution-branch-diverged');
62
- }
63
- await git(authority.projectRoot, ['update-ref', executionRef, currentHead, executionHead]);
64
- }
65
- await git(authority.projectRoot, ['switch', authority.executionBranch]);
66
- }
67
- else {
68
- await git(authority.projectRoot, ['switch', '-c', authority.executionBranch]);
69
- }
70
- if (await checkoutPayload(authority.projectRoot) !== checkoutBefore) {
71
- return failure('direct-yolo-checkout-payload-raced');
72
- }
73
- }
74
- const branchAfter = await git(authority.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
75
- const headAfter = await git(authority.projectRoot, ['rev-parse', 'HEAD']);
76
- if (branchAfter !== authority.executionBranch)
77
- return failure('direct-yolo-current-branch-mismatch');
78
- if (liveLease && currentLease?.ownerStoryId === options.storyId) {
79
- if (currentLease.setupHeadSha !== headAfter)
80
- return failure('direct-yolo-setup-lease-head-unbound');
81
- return { ok: true, value: setupReceipt(authority, originBinding, String(currentLease.expiresAt), true) };
82
- }
83
- const acquiredAt = nowIso;
84
- const expiresAt = new Date(nowMs + 60 * 60 * 1000).toISOString();
85
- const sessionId = `setup-${randomBytes(32).toString('hex')}`;
86
- const runtimeAtCas = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
87
- await mutateGitLifecycleRuntime(authority.projectRoot, (document) => {
88
- const epic = ensureRuntimeEpic(document, authority.epicId);
89
- const lease = asRecord(epic.branch_lease);
90
- if (lease && Date.parse(String(lease.expiresAt)) > nowMs && lease.ownerStoryId !== options.storyId) {
91
- throw new Error('direct-yolo-writer-active');
92
- }
93
- const persistedBinding = validOriginBinding(epic.origin_binding, authority.executionBranch, authority.originBranch);
94
- if (epic.origin_binding && !persistedBinding)
95
- throw new Error('direct-yolo-origin-binding-conflict');
96
- if (persistedBinding && JSON.stringify(persistedBinding) !== JSON.stringify(originBinding)) {
97
- throw new Error('direct-yolo-origin-binding-conflict');
98
- }
99
- epic.branch_mode = 'epic';
100
- epic.execution_branch = authority.executionBranch;
101
- epic.origin_branch = authority.originBranch;
102
- epic.graph_revision = authority.graphRevision;
103
- epic.origin_binding = originBinding;
104
- epic.branch_lease = {
105
- schemaVersion: 1, ownerStoryId: options.storyId, sessionId, idempotencyKey: sessionId,
106
- acquiredAt, expiresAt, setupHeadSha: headAfter,
107
- };
108
- }, {
109
- expectedRevision: runtimeAtCas.revision,
110
- preCommit: async () => {
111
- if (await git(authority.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']) !== authority.executionBranch
112
- || await git(authority.projectRoot, ['rev-parse', 'HEAD']) !== headAfter) {
113
- throw new Error('direct-yolo-setup-physical-state-raced');
114
- }
115
- },
116
- });
117
- return { ok: true, value: setupReceipt(authority, originBinding, expiresAt, false) };
118
- }
119
- catch (error) {
120
- return failure(publicReason(error, 'direct-yolo-setup-failed'));
121
- }
122
- }
123
- /** Accept C01 only from the root after its own physical setup and live lease. */
124
- export async function acceptDirectYoloSetupCheckpoint(options) {
125
- let physicalLock;
126
- try {
127
- const authority = await resolveAuthority(options.projectRoot, options.storyId);
128
- const nowIso = normalizedTime(options.nowIso);
129
- const statePath = join(authority.projectRoot, '.neocortex/state.json');
130
- const trackedBefore = await readFile(statePath, 'utf8');
131
- const payloadBefore = await checkoutPayload(authority.projectRoot);
132
- const headSha = await git(authority.projectRoot, ['rev-parse', 'HEAD']);
133
- const executionRef = `refs/heads/${authority.executionBranch}`;
134
- const runtime = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
135
- const epic = asRecord(runtime.epics[authority.epicId]);
136
- const binding = validOriginBinding(epic?.origin_binding, authority.executionBranch, authority.originBranch);
137
- const lease = asRecord(epic?.branch_lease);
138
- if (!binding)
139
- return failure('direct-yolo-origin-binding-invalid');
140
- if (!lease || !isLiveSameStorySetupLease(lease, options.storyId, nowIso)
141
- || lease?.sessionId !== lease?.idempotencyKey)
142
- return failure('direct-yolo-setup-lease-invalid');
143
- const acquired = await acquireGitLifecyclePhysicalIntegrationLock(authority.projectRoot, {
144
- kind: 'direct', storyId: options.storyId,
145
- sessionId: String(lease.sessionId), idempotencyKey: String(lease.idempotencyKey),
146
- expiresAt: new Date(Date.now() + 5 * 60 * 1000).toISOString(), persistent: false,
147
- });
148
- if (!acquired.ok)
149
- return failure(acquired.reasonCode);
150
- physicalLock = acquired;
151
- if (headSha !== lease.setupHeadSha
152
- || !(await gitExitOk(authority.projectRoot, ['merge-base', '--is-ancestor', binding.originHeadSha, headSha]))
153
- || await git(authority.projectRoot, ['rev-parse', executionRef]) !== headSha) {
154
- return failure('direct-yolo-setup-head-mismatch');
155
- }
156
- const occupiedElsewhere = (await worktreeBranches(authority.projectRoot)).some((item) => item.branch === authority.executionBranch && resolve(item.path) !== authority.projectRoot);
157
- if (occupiedElsewhere)
158
- return failure('direct-yolo-execution-branch-checked-out-elsewhere');
159
- const tracked = asRecord(JSON.parse(trackedBefore));
160
- const trackedStory = asRecord(asRecord(tracked?.stories)?.[options.storyId]);
161
- const runtimeStory = asRecord(runtime.stories[options.storyId]);
162
- if (!trackedStory || !['backlog', 'ready_to_start'].includes(String(trackedStory.status))
163
- || (trackedStory.steps_completed !== undefined
164
- && (!Array.isArray(trackedStory.steps_completed) || trackedStory.steps_completed.length > 0))
165
- || trackedStory.branch_name || trackedStory.checkpoint) {
166
- return failure('direct-yolo-setup-story-progress-conflict');
167
- }
168
- const accepted = runtimeStory?.status === 'branch-ready'
169
- && runtimeStory.last_step === GIT_LIFECYCLE_SETUP_BRANCH_STEP_ID
170
- && Array.isArray(runtimeStory.steps_completed)
171
- && runtimeStory.steps_completed.length === 1
172
- && runtimeStory.steps_completed[0] === GIT_LIFECYCLE_SETUP_BRANCH_STEP_ID
173
- && Object.keys(runtimeStory).sort().join(',') === 'last_step,status,steps_completed';
174
- if (runtimeStory && Object.keys(runtimeStory).length > 0 && !accepted) {
175
- return failure('direct-yolo-setup-story-progress-conflict');
176
- }
177
- const physicalGuard = async () => {
178
- if (Date.parse(String(lease.expiresAt)) <= (options.nowIso ? Date.parse(nowIso) : Date.now())
179
- || !physicalLock || !(await verifyGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner))
180
- || await readFile(statePath, 'utf8') !== trackedBefore
181
- || await checkoutPayload(authority.projectRoot) !== payloadBefore
182
- || await git(authority.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']) !== authority.executionBranch
183
- || await git(authority.projectRoot, ['rev-parse', 'HEAD']) !== headSha
184
- || !(await gitExitOk(authority.projectRoot, ['merge-base', '--is-ancestor', binding.originHeadSha, headSha]))
185
- || await git(authority.projectRoot, ['rev-parse', executionRef]) !== headSha) {
186
- throw new Error('direct-yolo-setup-physical-state-raced');
187
- }
188
- };
189
- if (accepted) {
190
- await physicalGuard();
191
- }
192
- else {
193
- await mutateGitLifecycleRuntime(authority.projectRoot, (document) => {
194
- const currentEpic = asRecord(document.epics[authority.epicId]);
195
- const currentStory = ensureRuntimeStory(document, options.storyId);
196
- if (JSON.stringify(currentEpic?.branch_lease) !== JSON.stringify(lease)
197
- || JSON.stringify(currentEpic?.origin_binding) !== JSON.stringify(binding)
198
- || currentEpic?.graph_revision !== authority.graphRevision
199
- || Object.keys(currentStory).length > 0) {
200
- throw new Error('direct-yolo-setup-runtime-raced');
201
- }
202
- currentStory.status = 'branch-ready';
203
- currentStory.last_step = GIT_LIFECYCLE_SETUP_BRANCH_STEP_ID;
204
- currentStory.steps_completed = [GIT_LIFECYCLE_SETUP_BRANCH_STEP_ID];
205
- }, { expectedRevision: runtime.revision, preCommit: physicalGuard });
206
- }
207
- return { ok: true, value: Object.freeze({
208
- ...setupReceipt(authority, binding, String(lease.expiresAt), accepted),
209
- checkpointAccepted: true, graphRevision: authority.graphRevision, headSha,
210
- }) };
211
- }
212
- catch (error) {
213
- return failure(publicReason(error, 'direct-yolo-setup-acceptance-failed'));
214
- }
215
- finally {
216
- if (physicalLock) {
217
- await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner).catch(() => undefined);
218
- }
219
- }
220
- }
221
- /**
222
- * Productive setup-owner handoff emitter used immediately before C08. The
223
- * one-time token never crosses stdout; only a public receipt is returned.
224
- */
225
- export async function issueDirectYoloSetupLeaseHandoff(options) {
226
- try {
227
- const authority = await resolveAuthority(options.projectRoot, options.storyId);
228
- const changedPaths = splitNull(await gitRaw(authority.projectRoot, ['diff', '--cached', '--name-only', '-z']));
229
- const writeSet = validateDirectWriteSet(changedPaths, authority.authorizedWriteSet, options.storyId, authority.rootMemoryEffect);
230
- if (!writeSet.ok)
231
- return failure(writeSet.reasonCode);
232
- if (authority.rootMemoryEffect)
233
- verifyRootMemoryPhysicalWriteSet(authority.projectRoot, authority.rootMemoryEffect, { storyId: options.storyId, executionBranch: authority.executionBranch,
234
- baseSha: await git(authority.projectRoot, ['rev-parse', 'HEAD']), headRef: ':', childPaths: authority.authorizedWriteSet });
235
- const stagedReview = publicStoryReviewArtifactFromGit(authority.projectRoot, options.storyId, ':');
236
- if (stagedReview?.verdict !== 'approved')
237
- return failure('direct-yolo-review-artifact-not-approved');
238
- const unstagedPaths = splitNull(await gitRaw(authority.projectRoot, ['diff', '--name-only', '-z']));
239
- if (unstagedPaths.some((path) => changedPaths.includes(path)))
240
- return failure('direct-yolo-user-overlap');
241
- const payload = await gitRaw(authority.projectRoot, ['diff', '--cached', '--binary', '--full-index']);
242
- if (!payload)
243
- return failure('direct-yolo-staged-diff-empty');
244
- const bundleDigest = digest(payload);
245
- const claimRevision = digest([...authority.authorizedWriteSet].sort().join('\0'));
246
- const nowIso = normalizedTime(options.nowIso);
247
- const runtime = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
248
- const setupLease = asRecord(runtime.epics[authority.epicId]?.branch_lease);
249
- if (!isLiveSameStorySetupLease(setupLease, options.storyId, nowIso)) {
250
- return failure('direct-yolo-setup-handoff-owner-invalid');
251
- }
252
- const sessionId = String(setupLease.sessionId);
253
- const leaseExpiresAt = String(setupLease.expiresAt);
254
- const candidateExpiresAt = new Date(Math.min(Date.parse(leaseExpiresAt), Date.parse(nowIso) + 5 * 60 * 1000)).toISOString();
255
- const prior = await readSetupHandoffTokenRecord(authority.projectRoot, options.storyId);
256
- const reused = Boolean(prior?.state === 'issued'
257
- && prior.fromSessionId === sessionId && prior.bundleDigest === bundleDigest
258
- && prior.claimRevision === claimRevision
259
- && Date.parse(prior.expiresAt) > Date.parse(nowIso));
260
- const expiresAt = reused ? prior.expiresAt : candidateExpiresAt;
261
- const token = reused ? prior.token : randomBytes(32).toString('base64url');
262
- const tokenDigest = digest(token);
263
- const grant = Object.freeze({
264
- schemaVersion: 1,
265
- kind: 'direct-yolo-setup-handoff',
266
- storyId: options.storyId,
267
- fromSessionId: sessionId,
268
- tokenDigest,
269
- bundleDigest,
270
- claimRevision,
271
- expiresAt,
272
- });
273
- const grantDigest = digest(JSON.stringify(grant));
274
- const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(authority.projectRoot, {
275
- kind: 'direct', storyId: options.storyId, sessionId, idempotencyKey: sessionId,
276
- expiresAt, persistent: false, createdAt: nowIso,
277
- });
278
- if (!physicalLock.ok)
279
- return failure(physicalLock.reasonCode === 'git-lifecycle-integration-backpressure'
280
- ? 'direct-yolo-integration-backpressure' : 'direct-yolo-integration-lock-failed');
281
- try {
282
- await writeSetupHandoffTokenRecord(authority.projectRoot, {
283
- schemaVersion: 1, kind: 'direct-yolo-setup-handoff-token', state: 'issued',
284
- storyId: options.storyId, fromSessionId: sessionId, token, tokenDigest,
285
- bundleDigest, claimRevision, grantDigest, expiresAt,
286
- });
287
- await mutateGitLifecycleRuntime(authority.projectRoot, (document) => {
288
- const current = asRecord(ensureRuntimeEpic(document, authority.epicId).branch_lease);
289
- if (!isLiveSameStorySetupLease(current, options.storyId, nowIso)
290
- || current?.sessionId !== sessionId || current.idempotencyKey !== sessionId) {
291
- throw new Error('direct-yolo-setup-handoff-owner-raced');
292
- }
293
- current.handoffGrant = grant;
294
- }, {
295
- expectedRevision: runtime.revision,
296
- preCommit: async () => {
297
- if (!(await verifyGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner))) {
298
- throw new Error('direct-yolo-integration-lock-raced');
299
- }
300
- const persisted = await readSetupHandoffTokenRecord(authority.projectRoot, options.storyId);
301
- if (!persisted || persisted.state !== 'issued' || persisted.grantDigest !== grantDigest
302
- || persisted.tokenDigest !== tokenDigest)
303
- throw new Error('direct-yolo-setup-handoff-token-raced');
304
- },
305
- });
306
- }
307
- finally {
308
- await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner).catch(() => undefined);
309
- }
310
- return { ok: true, value: Object.freeze({
311
- schemaVersion: 1, kind: 'direct-yolo-setup-handoff-receipt', storyId: options.storyId,
312
- sessionId, bundleDigest, claimRevision, grantDigest, expiresAt, reused, publicSafe: true,
313
- }) };
314
- }
315
- catch (error) {
316
- return failure(error instanceof Error && /^direct-yolo-/.test(error.message)
317
- ? error.message : 'direct-yolo-setup-handoff-failed');
318
- }
319
- }
320
- export async function beginDirectYoloStoryCommit(options) {
321
- try {
322
- const authority = await resolveAuthority(options.projectRoot, options.storyId);
323
- const baseSha = await git(authority.projectRoot, ['rev-parse', 'HEAD']);
324
- const changedPaths = splitNull(await gitRaw(authority.projectRoot, ['diff', '--cached', '--name-only', '-z']));
325
- const writeSet = validateDirectWriteSet(changedPaths, authority.authorizedWriteSet, options.storyId, authority.rootMemoryEffect);
326
- if (!writeSet.ok)
327
- return failure(writeSet.reasonCode);
328
- if (authority.rootMemoryEffect)
329
- verifyRootMemoryPhysicalWriteSet(authority.projectRoot, authority.rootMemoryEffect, { storyId: options.storyId, executionBranch: authority.executionBranch, baseSha, headRef: ':', childPaths: authority.authorizedWriteSet });
330
- const stagedReview = publicStoryReviewArtifactFromGit(authority.projectRoot, options.storyId, ':');
331
- if (stagedReview?.verdict !== 'approved')
332
- return failure('direct-yolo-review-artifact-not-approved');
333
- const unstagedPaths = splitNull(await gitRaw(authority.projectRoot, ['diff', '--name-only', '-z']));
334
- if (unstagedPaths.some((path) => changedPaths.includes(path)))
335
- return failure('direct-yolo-user-overlap');
336
- const payload = await gitRaw(authority.projectRoot, ['diff', '--cached', '--binary', '--full-index']);
337
- if (!payload)
338
- return failure('direct-yolo-staged-diff-empty');
339
- const bundleDigest = digest(payload);
340
- const claimRevision = digest([...authority.authorizedWriteSet].sort().join('\0'));
341
- const idempotencyKey = digest([
342
- 'direct-yolo-commit-v1', options.storyId, authority.epicId, authority.executionBranch,
343
- baseSha, bundleDigest, authority.graphRevision, claimRevision,
344
- ].join('\0'));
345
- const nowIso = normalizedTime(options.nowIso);
346
- let issuedHandoff = options.setupLeaseHandoff
347
- ?? await resolveIssuedSetupLeaseHandoff(authority.projectRoot, options.storyId, bundleDigest, claimRevision, nowIso);
348
- const runtimeBeforeLock = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
349
- const priorDirectLease = asRecord(runtimeBeforeLock.epics[authority.epicId]?.branch_lease);
350
- const reusableDirectLease = priorDirectLease?.ownerStoryId === options.storyId
351
- && priorDirectLease.sessionId === idempotencyKey && priorDirectLease.idempotencyKey === idempotencyKey
352
- && typeof priorDirectLease.expiresAt === 'string'
353
- && Date.parse(priorDirectLease.expiresAt) > Date.parse(nowIso)
354
- ? priorDirectLease : undefined;
355
- if (reusableDirectLease && options.setupLeaseHandoff) {
356
- return failure('direct-yolo-setup-handoff-replayed');
357
- }
358
- const priorConsumption = asRecord(reusableDirectLease?.handoffConsumption);
359
- if (priorConsumption) {
360
- const privateRecord = await readSetupHandoffTokenRecord(authority.projectRoot, options.storyId);
361
- if (!privateRecord || !['consuming', 'consumed'].includes(privateRecord.state)
362
- || privateRecord.fromSessionId !== priorConsumption.fromSessionId
363
- || privateRecord.tokenDigest !== priorConsumption.tokenDigest
364
- || privateRecord.bundleDigest !== bundleDigest || privateRecord.claimRevision !== claimRevision
365
- || priorConsumption.bundleDigest !== bundleDigest || priorConsumption.claimRevision !== claimRevision
366
- || privateRecord.consumedBySessionId !== idempotencyKey
367
- || priorConsumption.consumedBySessionId !== idempotencyKey) {
368
- return failure('direct-yolo-setup-handoff-consume-invalid');
369
- }
370
- // The runtime CAS already consumed this exact grant. Recovery may finish
371
- // its private receipt after expiry; it never promotes a second writer.
372
- if (privateRecord.state === 'consuming') {
373
- if (!privateRecord.token || digest(privateRecord.token) !== privateRecord.tokenDigest) {
374
- return failure('direct-yolo-setup-handoff-consume-invalid');
375
- }
376
- issuedHandoff = { sessionId: privateRecord.fromSessionId, token: privateRecord.token };
377
- }
378
- }
379
- const expiresAt = reusableDirectLease
380
- ? String(reusableDirectLease.expiresAt)
381
- : new Date(Date.parse(nowIso) + 30 * 60 * 1000).toISOString();
382
- const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(authority.projectRoot, {
383
- kind: 'direct', storyId: options.storyId, sessionId: idempotencyKey, idempotencyKey,
384
- expiresAt, persistent: true,
385
- createdAt: reusableDirectLease && typeof reusableDirectLease.acquiredAt === 'string'
386
- ? reusableDirectLease.acquiredAt : nowIso,
387
- });
388
- if (!physicalLock.ok)
389
- return failure(physicalLock.reasonCode === 'git-lifecycle-integration-backpressure'
390
- ? 'direct-yolo-integration-backpressure' : 'direct-yolo-integration-lock-failed');
391
- try {
392
- if (issuedHandoff && options.setupLeaseHandoff === undefined) {
393
- await markSetupHandoffTokenConsuming(authority.projectRoot, options.storyId, issuedHandoff.sessionId, issuedHandoff.token, idempotencyKey, nowIso);
394
- await options.setupHandoffFault?.('after-consuming-persisted');
395
- }
396
- await mutateGitLifecycleRuntime(authority.projectRoot, (document) => {
397
- const epic = ensureRuntimeEpic(document, authority.epicId);
398
- const current = asRecord(epic.branch_lease);
399
- const live = current && Date.parse(String(current.expiresAt)) > Date.parse(nowIso);
400
- const alreadyPromoted = current?.ownerStoryId === options.storyId
401
- && current.sessionId === idempotencyKey && current.idempotencyKey === idempotencyKey;
402
- const sameStorySetup = current?.ownerStoryId === options.storyId
403
- && current.sessionId === current.idempotencyKey
404
- && typeof current.idempotencyKey === 'string'
405
- && /^setup-[a-f0-9]{64}$/.test(current.idempotencyKey);
406
- const setupHandoffAuthorized = live && sameStorySetup && validSetupLeaseHandoff({
407
- current,
408
- handoff: issuedHandoff,
409
- storyId: options.storyId,
410
- bundleDigest,
411
- claimRevision,
412
- nowIso,
413
- });
414
- if (issuedHandoff && live && !alreadyPromoted && !setupHandoffAuthorized) {
415
- throw new Error('direct-yolo-setup-handoff-invalid');
416
- }
417
- if (live && !alreadyPromoted && !setupHandoffAuthorized) {
418
- throw new Error('direct-yolo-writer-active');
419
- }
420
- const setupGrant = setupHandoffAuthorized ? asRecord(current?.handoffGrant) : undefined;
421
- const handoffConsumption = setupGrant ? {
422
- schemaVersion: 1,
423
- kind: 'direct-yolo-setup-handoff-consumption',
424
- state: 'consumed',
425
- storyId: options.storyId,
426
- fromSessionId: String(current?.sessionId),
427
- tokenDigest: String(setupGrant.tokenDigest),
428
- bundleDigest,
429
- claimRevision,
430
- consumedBySessionId: idempotencyKey,
431
- consumedAt: nowIso,
432
- } : undefined;
433
- epic.branch_mode = 'epic';
434
- epic.execution_branch = authority.executionBranch;
435
- epic.origin_branch = authority.originBranch;
436
- epic.graph_revision = authority.graphRevision;
437
- epic.branch_lease = live && alreadyPromoted ? current : {
438
- schemaVersion: 1, ownerStoryId: options.storyId, sessionId: idempotencyKey,
439
- idempotencyKey, acquiredAt: nowIso, expiresAt,
440
- ...(handoffConsumption ? { handoffConsumption } : {}),
441
- };
442
- }, {
443
- expectedRevision: runtimeBeforeLock.revision,
444
- preCommit: async () => {
445
- if (!(await verifyGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner))) {
446
- throw new Error('direct-yolo-integration-lock-raced');
447
- }
448
- },
449
- });
450
- }
451
- catch (error) {
452
- await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner).catch(() => undefined);
453
- throw error;
454
- }
455
- if (issuedHandoff && options.setupLeaseHandoff === undefined) {
456
- await options.setupHandoffFault?.('before-consumed-persist');
457
- await markSetupHandoffTokenConsumed(authority.projectRoot, authority.epicId, options.storyId, issuedHandoff.sessionId, issuedHandoff.token, bundleDigest, claimRevision, idempotencyKey, nowIso);
458
- }
459
- const trailers = Object.freeze([
460
- `Neocortex-Story: ${options.storyId}`,
461
- `Neocortex-Epic: ${authority.epicId}`,
462
- `Neocortex-Execution-Branch: ${authority.executionBranch}`,
463
- `Neocortex-Prepared-Base: ${baseSha}`,
464
- `Neocortex-Bundle-Digest: ${bundleDigest}`,
465
- `Neocortex-Review-Artifact-Digest: ${stagedReview.digest}`,
466
- `Neocortex-Graph-Revision: ${authority.graphRevision}`,
467
- `Neocortex-Claim-Revision: ${claimRevision}`,
468
- ...(authority.rootMemoryEffect ? [`Neocortex-Root-Memory-Effect: ${rootMemoryEffectDigest(authority.rootMemoryEffect)}`] : []),
469
- ]);
470
- return { ok: true, value: Object.freeze({
471
- schemaVersion: 1, storyId: options.storyId, epicId: authority.epicId,
472
- executionBranch: authority.executionBranch, baseSha, bundleDigest,
473
- reviewArtifactDigest: stagedReview.digest,
474
- graphRevision: authority.graphRevision, claimRevision, idempotencyKey,
475
- changedPaths: Object.freeze(changedPaths), trailers,
476
- }) };
477
- }
478
- catch (error) {
479
- return failure(publicReason(error, 'direct-yolo-begin-failed'));
480
- }
481
- }
482
- export async function finalizeDirectYoloStoryCheckpoint(options) {
483
- let cleanupAuthority;
484
- let cleanupLease;
485
- let cleanupPhysical;
486
- try {
487
- const authority = await resolveAuthority(options.projectRoot, options.storyId);
488
- cleanupAuthority = authority;
489
- const aggregateHeadSha = await git(authority.projectRoot, ['rev-parse', 'HEAD']);
490
- let runtime = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
491
- const existing = asRecord(runtime.stories[options.storyId]?.checkpoint);
492
- if (existing) {
493
- const checkpointHeadSha = typeof existing.headSha === 'string' ? existing.headSha : '';
494
- const checkpointGraphRevision = typeof existing.graphRevision === 'string' ? existing.graphRevision : '';
495
- const checkpointPaths = /^[a-f0-9]{40,64}$/.test(checkpointHeadSha)
496
- ? splitNull(await gitRaw(authority.projectRoot, ['diff-tree', '--no-commit-id', '--name-only', '-r', '-z', checkpointHeadSha]))
497
- : [];
498
- const replayWriteSet = validateDirectWriteSet(checkpointPaths, authority.authorizedWriteSet, options.storyId, authority.rootMemoryEffect);
499
- const ancestral = /^[a-f0-9]{40,64}$/.test(checkpointHeadSha)
500
- && await gitExitOk(authority.projectRoot, ['merge-base', '--is-ancestor', checkpointHeadSha, aggregateHeadSha]);
501
- if (!ancestral || !/^[a-f0-9]{64}$/.test(checkpointGraphRevision) || !replayWriteSet.ok) {
502
- return failure('direct-yolo-replay-invalid');
503
- }
504
- const replayQa = await runQa(options, authority.projectRoot, aggregateHeadSha, checkpointGraphRevision);
505
- if (!(await verifyAcceptedGitLifecycleStoryCheckpoint(authority.projectRoot, existing, options.storyId, authority.epicId, authority.executionBranch, replayQa.transientAuthority, authority.authorizedWriteSet)))
506
- return failure('direct-yolo-replay-invalid');
507
- if (!(await physicalCheckoutUnchanged(authority.projectRoot, authority.executionBranch, aggregateHeadSha, checkpointPaths)))
508
- return failure('direct-yolo-replay-head-raced');
509
- if (options.push && !(await remoteContainsHead(authority.projectRoot, options.remote ?? 'origin', authority.executionBranch, checkpointHeadSha)))
510
- return failure('direct-yolo-remote-head-mismatch');
511
- const physicalOwnerRef = Array.isArray(existing.receiptRefs)
512
- ? existing.receiptRefs.find((item) => typeof item === 'string' && /^physical-lock-owner:[a-f0-9]{64}$/.test(item))
513
- : undefined;
514
- if (physicalOwnerRef && typeof existing.idempotencyKey === 'string') {
515
- await releaseGitLifecyclePhysicalIntegrationLockForCheckpoint(authority.projectRoot, {
516
- storyId: options.storyId,
517
- idempotencyKey: existing.idempotencyKey,
518
- ownerDigest: physicalOwnerRef.slice('physical-lock-owner:'.length),
519
- });
520
- }
521
- return { ok: true, value: existing };
522
- }
523
- const headSha = aggregateHeadSha;
524
- const baseSha = await git(authority.projectRoot, ['rev-parse', `${headSha}^`]);
525
- const commitBody = await gitRaw(authority.projectRoot, ['show', '--no-patch', '--format=%B', headSha]);
526
- const changedPaths = splitNull(await gitRaw(authority.projectRoot, ['diff-tree', '--no-commit-id', '--name-only', '-r', '-z', headSha]));
527
- const writeSet = validateDirectWriteSet(changedPaths, authority.authorizedWriteSet, options.storyId, authority.rootMemoryEffect);
528
- if (!writeSet.ok)
529
- return failure(writeSet.reasonCode);
530
- if (authority.rootMemoryEffect)
531
- verifyRootMemoryPhysicalWriteSet(authority.projectRoot, authority.rootMemoryEffect, { storyId: options.storyId, executionBranch: authority.executionBranch, baseSha, headRef: headSha, childPaths: authority.authorizedWriteSet });
532
- const bundleDigest = trailer(commitBody, 'Neocortex-Bundle-Digest');
533
- const graphRevision = trailer(commitBody, 'Neocortex-Graph-Revision');
534
- const claimRevision = trailer(commitBody, 'Neocortex-Claim-Revision');
535
- const required = new Map([
536
- ['Neocortex-Story', options.storyId], ['Neocortex-Epic', authority.epicId],
537
- ['Neocortex-Execution-Branch', authority.executionBranch], ['Neocortex-Prepared-Base', baseSha],
538
- ['Neocortex-Graph-Revision', authority.graphRevision],
539
- ['Neocortex-Claim-Revision', digest([...authority.authorizedWriteSet].sort().join('\0'))],
540
- ]);
541
- if (!bundleDigest || !/^[a-f0-9]{64}$/.test(bundleDigest) || !graphRevision || !claimRevision
542
- || [...required].some(([key, value]) => trailer(commitBody, key) !== value)) {
543
- return failure('direct-yolo-trailers-invalid');
544
- }
545
- const publicReview = publicStoryReviewArtifactFromGit(authority.projectRoot, options.storyId, headSha);
546
- if (publicReview?.verdict !== 'approved')
547
- return failure('direct-yolo-review-artifact-not-approved');
548
- const reviewTrailer = trailer(commitBody, 'Neocortex-Review-Artifact-Digest');
549
- if (reviewTrailer !== undefined && reviewTrailer !== publicReview.digest) {
550
- return failure('direct-yolo-review-artifact-digest-mismatch');
551
- }
552
- const expectedPayloadDigest = digest(await gitRaw(authority.projectRoot, ['diff', '--binary', '--full-index', `${baseSha}..${headSha}`]));
553
- if (bundleDigest !== expectedPayloadDigest)
554
- return failure('direct-yolo-bundle-digest-mismatch');
555
- const idempotencyKey = digest([
556
- 'direct-yolo-commit-v1', options.storyId, authority.epicId, authority.executionBranch,
557
- baseSha, bundleDigest, graphRevision, claimRevision,
558
- ].join('\0'));
559
- const currentLease = asRecord(runtime.epics[authority.epicId]?.branch_lease);
560
- const nowIso = normalizedTime(options.nowIso);
561
- const matchingLease = currentLease?.ownerStoryId === options.storyId
562
- && currentLease.idempotencyKey === idempotencyKey
563
- && currentLease.sessionId === idempotencyKey
564
- && Date.parse(String(currentLease.expiresAt)) > Date.now()
565
- ? currentLease : undefined;
566
- if (currentLease && Date.parse(String(currentLease.expiresAt)) > Date.now() && !matchingLease) {
567
- return failure('direct-yolo-writer-active');
568
- }
569
- const requestedLease = matchingLease ?? {
570
- schemaVersion: 1, ownerStoryId: options.storyId, sessionId: idempotencyKey,
571
- idempotencyKey, acquiredAt: nowIso,
572
- expiresAt: new Date(Date.parse(nowIso) + 30 * 60 * 1000).toISOString(),
573
- };
574
- const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(authority.projectRoot, {
575
- kind: 'direct', storyId: options.storyId, sessionId: idempotencyKey, idempotencyKey,
576
- expiresAt: String(requestedLease.expiresAt), persistent: true,
577
- createdAt: String(requestedLease.acquiredAt),
578
- });
579
- if (!physicalLock.ok)
580
- return failure(physicalLock.reasonCode === 'git-lifecycle-integration-backpressure'
581
- ? 'direct-yolo-integration-backpressure' : 'direct-yolo-integration-lock-failed');
582
- cleanupPhysical = physicalLock;
583
- if (!matchingLease) {
584
- const leased = await mutateGitLifecycleRuntime(authority.projectRoot, (document) => {
585
- const epic = ensureRuntimeEpic(document, authority.epicId);
586
- const current = asRecord(epic.branch_lease);
587
- if (current && Date.parse(String(current.expiresAt)) > Date.parse(nowIso)) {
588
- throw new Error('direct-yolo-writer-active');
589
- }
590
- if (epic.graph_revision !== authority.graphRevision)
591
- throw new Error('direct-yolo-graph-revision-raced');
592
- epic.branch_lease = requestedLease;
593
- }, { expectedRevision: runtime.revision });
594
- runtime = leased.document;
595
- }
596
- cleanupLease = requestedLease;
597
- {
598
- const qaExecution = await runQa(options, authority.projectRoot, headSha, authority.graphRevision);
599
- if (!(await physicalCheckoutUnchanged(authority.projectRoot, authority.executionBranch, headSha, changedPaths))) {
600
- return failure('direct-yolo-head-raced');
601
- }
602
- if (options.push) {
603
- const remote = safeRemote(options.remote ?? 'origin');
604
- await git(authority.projectRoot, ['push', remote, authority.executionBranch]);
605
- if (!(await remoteHeadIsExact(authority.projectRoot, remote, authority.executionBranch, headSha))) {
606
- return failure('direct-yolo-remote-head-mismatch');
607
- }
608
- }
609
- const checkpoint = await buildCheckpoint({
610
- projectRoot: authority.projectRoot, storyId: options.storyId, epicId: authority.epicId,
611
- executionBranch: authority.executionBranch, baseSha, headSha, bundleDigest,
612
- graphRevision, claimRevision, idempotencyKey, qaExecution,
613
- physicalLockOwnerDigest: computeGitLifecyclePhysicalIntegrationLockOwnerDigest(physicalLock.owner),
614
- nowIso: normalizedTime(options.nowIso), legacyReceiptRef: undefined, rootMemoryEffect: authority.rootMemoryEffect,
615
- });
616
- await options.beforeCheckpointPersist?.();
617
- const persisted = await persistCheckpoint({
618
- projectRoot: authority.projectRoot, checkpoint,
619
- remote: options.push ? options.remote ?? 'origin' : undefined,
620
- expectedRevision: runtime.revision, expectedLease: requestedLease,
621
- expectedGraphRevision: authority.graphRevision,
622
- physicalLockPath: physicalLock.path, physicalLockOwner: physicalLock.owner,
623
- transientAuthority: qaExecution.transientAuthority,
624
- authorizedWriteSet: authority.authorizedWriteSet,
625
- });
626
- if (!persisted)
627
- return failure('direct-yolo-checkpoint-persist-failed');
628
- await options.afterCheckpointPersist?.();
629
- return { ok: true, value: checkpoint };
630
- }
631
- }
632
- catch (error) {
633
- return failure(publicReason(error, 'direct-yolo-finalize-failed'));
634
- }
635
- finally {
636
- if (cleanupPhysical) {
637
- await releaseGitLifecyclePhysicalIntegrationLock(cleanupPhysical.path, cleanupPhysical.owner).catch(() => undefined);
638
- }
639
- if (cleanupAuthority && cleanupLease) {
640
- await releaseOwnedDirectLease(cleanupAuthority.projectRoot, cleanupAuthority.epicId, cleanupLease).catch(() => undefined);
641
- }
642
- else if (cleanupAuthority) {
643
- await cleanupOwnedDirectAuthority(cleanupAuthority, options.storyId).catch(() => undefined);
644
- }
645
- }
646
- }
647
- export async function recoverLegacyDirectYoloStoryCheckpoint(options) {
648
- try {
649
- const authority = await resolveAuthority(options.projectRoot, options.storyId);
650
- if (!/^[a-f0-9]{40,64}$/.test(options.commitSha))
651
- return failure('direct-yolo-recovery-commit-invalid');
652
- const headSha = await git(authority.projectRoot, ['rev-parse', options.commitSha]);
653
- if (LEGACY_DIRECT_YOLO_RECOVERY_COMMITS[options.storyId] !== headSha) {
654
- return failure('direct-yolo-recovery-not-allowlisted');
655
- }
656
- if (await git(authority.projectRoot, ['rev-parse', 'HEAD']) !== headSha) {
657
- return failure('direct-yolo-recovery-head-mismatch');
658
- }
659
- await git(authority.projectRoot, ['merge-base', '--is-ancestor', headSha, `refs/heads/${authority.executionBranch}`]);
660
- const baseSha = await git(authority.projectRoot, ['rev-parse', `${headSha}^`]);
661
- const payload = await gitRaw(authority.projectRoot, ['diff', '--binary', '--full-index', `${baseSha}..${headSha}`]);
662
- const changedPaths = splitNull(await gitRaw(authority.projectRoot, ['diff-tree', '--no-commit-id', '--name-only', '-r', '-z', headSha]));
663
- const recoveryWriteSet = validateDirectWriteSet(changedPaths, authority.authorizedWriteSet.length > 0 ? authority.authorizedWriteSet : changedPaths, options.storyId);
664
- if (!recoveryWriteSet.ok)
665
- return failure('direct-yolo-recovery-write-set-invalid');
666
- const bundleDigest = digest(payload);
667
- const claimRevision = digest([...changedPaths].sort().join('\0'));
668
- const idempotencyKey = digest(['legacy-direct-yolo-recovery-v1', options.storyId, headSha].join('\0'));
669
- const nowIso = normalizedTime(options.nowIso);
670
- const expiresAt = new Date(Date.parse(nowIso) + 30 * 60 * 1000).toISOString();
671
- const initialRuntime = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
672
- const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(authority.projectRoot, {
673
- kind: 'direct', storyId: options.storyId, sessionId: idempotencyKey, idempotencyKey,
674
- expiresAt, persistent: true, createdAt: nowIso,
675
- });
676
- if (!physicalLock.ok)
677
- return failure(physicalLock.reasonCode === 'git-lifecycle-integration-backpressure'
678
- ? 'direct-yolo-recovery-integration-backpressure' : 'direct-yolo-recovery-integration-lock-failed');
679
- const requestedLease = {
680
- schemaVersion: 1, ownerStoryId: options.storyId, sessionId: idempotencyKey,
681
- idempotencyKey, acquiredAt: nowIso, expiresAt,
682
- };
683
- let leaseAcquired = false;
684
- try {
685
- const leased = await mutateGitLifecycleRuntime(authority.projectRoot, (document) => {
686
- const epic = ensureRuntimeEpic(document, authority.epicId);
687
- const current = asRecord(epic.branch_lease);
688
- if (current && Date.parse(String(current.expiresAt)) > Date.parse(nowIso)
689
- && !sameLease(current, requestedLease))
690
- throw new Error('direct-yolo-recovery-writer-active');
691
- if (epic.graph_revision !== authority.graphRevision)
692
- throw new Error('direct-yolo-recovery-graph-raced');
693
- epic.branch_mode = 'epic';
694
- epic.execution_branch = authority.executionBranch;
695
- epic.origin_branch = authority.originBranch;
696
- epic.branch_lease = requestedLease;
697
- }, { expectedRevision: initialRuntime.revision });
698
- leaseAcquired = true;
699
- const qaExecution = await runQa(options, authority.projectRoot, headSha, authority.graphRevision);
700
- if (!(await physicalCheckoutUnchanged(authority.projectRoot, authority.executionBranch, headSha, changedPaths))) {
701
- return failure('direct-yolo-recovery-head-raced');
702
- }
703
- if (options.push) {
704
- const remote = safeRemote(options.remote ?? 'origin');
705
- const remoteHead = (await git(authority.projectRoot, ['ls-remote', '--heads', remote, `refs/heads/${authority.executionBranch}`])).split(/\s+/)[0];
706
- if (!remoteHead || !(await gitExitOk(authority.projectRoot, ['merge-base', '--is-ancestor', headSha, remoteHead]))) {
707
- return failure('direct-yolo-recovery-remote-proof-missing');
708
- }
709
- }
710
- const provisional = await buildCheckpoint({
711
- projectRoot: authority.projectRoot, storyId: options.storyId, epicId: authority.epicId,
712
- executionBranch: authority.executionBranch, baseSha, headSha, bundleDigest,
713
- graphRevision: authority.graphRevision, claimRevision, idempotencyKey,
714
- qaExecution,
715
- physicalLockOwnerDigest: computeGitLifecyclePhysicalIntegrationLockOwnerDigest(physicalLock.owner),
716
- nowIso, legacyReceiptRef: undefined,
717
- });
718
- const legacyReceiptRef = await computeLegacyDirectYoloRecoveryReceiptRef(authority.projectRoot, {
719
- storyId: options.storyId,
720
- epicId: authority.epicId,
721
- executionBranch: authority.executionBranch,
722
- baseSha,
723
- headSha,
724
- bundleDigest,
725
- graphRevision: authority.graphRevision,
726
- });
727
- if (!legacyReceiptRef)
728
- return failure('direct-yolo-recovery-evidence-invalid');
729
- const checkpoint = Object.freeze({
730
- ...provisional,
731
- receiptRefs: Object.freeze([...provisional.receiptRefs, legacyReceiptRef]),
732
- });
733
- const persisted = await persistCheckpoint({
734
- projectRoot: authority.projectRoot, checkpoint,
735
- remote: options.push ? options.remote ?? 'origin' : undefined,
736
- remotePolicy: 'ancestor-recovery',
737
- expectedRevision: leased.document.revision,
738
- expectedLease: requestedLease,
739
- expectedGraphRevision: authority.graphRevision,
740
- physicalLockPath: physicalLock.path,
741
- physicalLockOwner: physicalLock.owner,
742
- transientAuthority: qaExecution.transientAuthority,
743
- authorizedWriteSet: authority.authorizedWriteSet,
744
- });
745
- return persisted ? { ok: true, value: checkpoint } : failure('direct-yolo-recovery-persist-failed');
746
- }
747
- finally {
748
- await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner).catch(() => undefined);
749
- if (leaseAcquired)
750
- await releaseOwnedDirectLease(authority.projectRoot, authority.epicId, requestedLease).catch(() => undefined);
751
- }
752
- }
753
- catch (error) {
754
- return failure(publicReason(error, 'direct-yolo-recovery-failed'));
755
- }
756
- }
757
- async function resolveLogicalAuthority(projectRootInput, storyId) {
758
- if (!/^[A-Za-z][A-Za-z0-9_-]*\.[A-Za-z0-9._-]+$/.test(storyId))
759
- throw new Error('direct-yolo-story-id-invalid');
760
- const projectRoot = resolve(projectRootInput);
761
- const tracked = asRecord(JSON.parse(await readFile(join(projectRoot, '.neocortex/state.json'), 'utf8')));
762
- const runtime = await readGitLifecycleRuntime(projectRoot, { required: true });
763
- const effective = applyGitLifecycleRuntimeOverlay(tracked, runtime);
764
- const stories = asRecord(effective.stories);
765
- const epics = asRecord(effective.epics);
766
- const story = asRecord(stories?.[storyId]);
767
- const epicId = String(story?.epic_id ?? storyId.split('.')[0]);
768
- const epic = asRecord(epics?.[epicId]);
769
- const executionBranch = String(epic?.execution_branch ?? '');
770
- const originBranch = String(epic?.origin_branch ?? '');
771
- const graphRevision = String(epic?.graph_revision ?? '');
772
- const authorizedWriteSet = Array.isArray(story?.files_to_modify)
773
- ? [...new Set(story.files_to_modify.filter((item) => typeof item === 'string' && safePath(item)))].sort()
774
- : [];
775
- if (!story)
776
- throw new Error('direct-yolo-story-state-missing');
777
- if (epic?.branch_mode !== 'epic')
778
- throw new Error('direct-yolo-branch-mode-invalid');
779
- if (!safeRef(executionBranch)
780
- || !(await gitExitOk(projectRoot, ['check-ref-format', '--branch', executionBranch]))) {
781
- throw new Error('direct-yolo-execution-branch-invalid');
782
- }
783
- if (!safeRef(originBranch)
784
- || !(await gitExitOk(projectRoot, ['check-ref-format', '--branch', originBranch]))) {
785
- throw new Error('direct-yolo-origin-branch-invalid');
786
- }
787
- if (!/^[a-f0-9]{64}$/.test(graphRevision))
788
- throw new Error('direct-yolo-graph-revision-invalid');
789
- const rootMemoryEffect = await readRootMemoryEffectForCheckpoint({ projectRoot, storyId, graphRevision,
790
- executionBranch, childPaths: authorizedWriteSet });
791
- return { projectRoot, storyId, story, epicId, executionBranch, originBranch, graphRevision, authorizedWriteSet, rootMemoryEffect };
792
- }
793
- async function resolveAuthority(projectRootInput, storyId) {
794
- const authority = await resolveLogicalAuthority(projectRootInput, storyId);
795
- const currentBranch = await git(authority.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
796
- if (currentBranch !== authority.executionBranch)
797
- throw new Error('direct-yolo-current-branch-mismatch');
798
- return authority;
799
- }
800
- async function buildCheckpoint(input) {
801
- const checkedAt = input.nowIso;
802
- const commitBody = await gitRaw(input.projectRoot, ['show', '--no-patch', '--format=%H%n%P%n%B', input.headSha]);
803
- const changedPaths = splitNull(await gitRaw(input.projectRoot, ['diff-tree', '--no-commit-id', '--name-only', '-r', '-z', input.headSha]));
804
- const gitEvidenceDigest = computeImmutableStoryQaEvidenceDigest({
805
- storyId: input.storyId, baseSha: input.baseSha, headSha: input.headSha,
806
- bundleDigest: input.bundleDigest, graphRevision: input.graphRevision,
807
- commitBody, changedPaths,
808
- });
809
- const qaDigest = computeP205StoryQaEvidenceDigest({
810
- gitEvidenceDigest, headSha: input.headSha, graphRevision: input.graphRevision,
811
- manifestDigest: input.qaExecution.manifestDigest, gateIds: input.qaExecution.gateIds,
812
- resultDigest: input.qaExecution.resultDigest,
813
- });
814
- const qaReceiptRef = `story-qa:${qaDigest}`;
815
- const qaReceipt = Object.freeze({
816
- schemaVersion: 1, kind: 'story_qa_evidence', producer: 'local-yolo-tdd', evidenceVersion: 'p205-execution-v2',
817
- storyId: input.storyId, epicId: input.epicId, baseSha: input.baseSha, headSha: input.headSha,
818
- bundleDigest: input.bundleDigest, graphRevision: input.graphRevision,
819
- contract: input.qaExecution.contract, command: input.qaExecution.command,
820
- manifestDigest: input.qaExecution.manifestDigest, gateIds: input.qaExecution.gateIds,
821
- resultDigest: input.qaExecution.resultDigest,
822
- sourceEvidenceDigest: qaDigest, verdict: 'passed', checkedAt, receiptRef: qaReceiptRef,
823
- });
824
- const publicReview = publicStoryReviewArtifactFromGit(input.projectRoot, input.storyId, input.headSha);
825
- if (publicReview?.verdict !== 'approved')
826
- throw new Error('direct-yolo-review-artifact-not-approved');
827
- const reviewDigest = digest([
828
- 'root-commit-range-review-v2', input.storyId, input.baseSha, input.headSha,
829
- input.bundleDigest, input.graphRevision, qaReceiptRef, digest(commitBody), [...changedPaths].sort().join(','),
830
- publicReview.digest,
831
- ].join('\0'));
832
- const reviewReceiptRef = `story-review:${reviewDigest}`;
833
- const reviewReceipt = Object.freeze({
834
- schemaVersion: 1, kind: 'story_review_evidence', producer: 'root-commit-range-review',
835
- storyId: input.storyId, epicId: input.epicId, baseSha: input.baseSha, headSha: input.headSha,
836
- bundleDigest: input.bundleDigest, graphRevision: input.graphRevision,
837
- sourceEvidenceDigest: reviewDigest, reviewArtifactDigest: publicReview.digest,
838
- qaReceiptRef, verdict: 'approved', reviewedAt: checkedAt,
839
- receiptRef: reviewReceiptRef,
840
- });
841
- const evidenceRefs = [
842
- `.neocortex/stories/${input.storyId}/qa-gate-result.json`,
843
- `.neocortex/stories/${input.storyId}/validation-evidence.md`, qaReceiptRef, reviewReceiptRef,
844
- ...(input.physicalLockOwnerDigest ? [`physical-lock-owner:${input.physicalLockOwnerDigest}`] : []),
845
- ...(input.legacyReceiptRef ? [input.legacyReceiptRef] : []),
846
- ];
847
- return Object.freeze({
848
- schemaVersion: 1, storyId: input.storyId, epicId: input.epicId, branch: input.executionBranch,
849
- baseSha: input.baseSha, headSha: input.headSha, commits: Object.freeze([input.headSha]),
850
- idempotencyKey: input.idempotencyKey, bundleDigest: input.bundleDigest,
851
- graphRevision: input.graphRevision, claimRevision: input.claimRevision,
852
- receiptRefs: Object.freeze(evidenceRefs), qaVerdict: 'passed', reviewVerdict: 'approved',
853
- qaReceipt, reviewReceipt, recordedAt: checkedAt,
854
- ...(input.rootMemoryEffect ? { rootMemoryEffect: input.rootMemoryEffect } : {}),
855
- });
856
- }
857
- async function persistCheckpoint(input) {
858
- const { projectRoot, checkpoint, remote } = input;
859
- let conflict = false;
860
- await mutateGitLifecycleRuntime(projectRoot, (document) => {
861
- const epic = ensureRuntimeEpic(document, checkpoint.epicId);
862
- if (input.expectedLease) {
863
- const currentLease = asRecord(epic.branch_lease);
864
- if (!sameLease(currentLease, input.expectedLease))
865
- throw new Error('direct-yolo-runtime-revision-conflict');
866
- if (Date.parse(String(currentLease?.expiresAt)) <= Date.now())
867
- throw new Error('direct-yolo-writer-lease-expired');
868
- if (epic.graph_revision !== input.expectedGraphRevision || checkpoint.graphRevision !== input.expectedGraphRevision) {
869
- throw new Error('direct-yolo-graph-revision-raced');
870
- }
871
- }
872
- const story = ensureRuntimeStory(document, checkpoint.storyId);
873
- const existing = asRecord(story.checkpoint);
874
- if (existing && existing.headSha !== checkpoint.headSha) {
875
- conflict = true;
876
- return;
877
- }
878
- story.checkpoint = checkpoint;
879
- story.status = 'done';
880
- story.last_step = GIT_LIFECYCLE_REVIEW_PR_STEP_ID;
881
- const steps = Array.isArray(story.steps_completed) ? story.steps_completed.filter((item) => typeof item === 'string') : [];
882
- story.steps_completed = [...new Set([...steps, GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID, GIT_LIFECYCLE_REVIEW_PR_STEP_ID])];
883
- epic.branch_lease = null;
884
- }, { expectedRevision: input.expectedRevision, preCommit: async () => {
885
- if (conflict)
886
- throw new Error('direct-yolo-checkpoint-conflict');
887
- const currentBranch = await git(projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
888
- if (currentBranch !== checkpoint.branch || await git(projectRoot, ['rev-parse', 'HEAD']) !== checkpoint.headSha) {
889
- throw new Error('direct-yolo-checkpoint-head-raced');
890
- }
891
- if (!(await verifyAcceptedGitLifecycleStoryCheckpoint(projectRoot, checkpoint, checkpoint.storyId, checkpoint.epicId, checkpoint.branch, input.transientAuthority, input.authorizedWriteSet)))
892
- throw new Error('direct-yolo-checkpoint-physical-invalid');
893
- if (input.physicalLockPath && input.physicalLockOwner
894
- && !(await verifyGitLifecyclePhysicalIntegrationLock(input.physicalLockPath, input.physicalLockOwner))) {
895
- throw new Error('direct-yolo-integration-lock-raced');
896
- }
897
- if (remote) {
898
- const accepted = input.remotePolicy === 'ancestor-recovery'
899
- ? await remoteContainsHead(projectRoot, remote, checkpoint.branch, checkpoint.headSha)
900
- : await remoteHeadIsExact(projectRoot, remote, checkpoint.branch, checkpoint.headSha);
901
- if (!accepted) {
902
- throw new Error('direct-yolo-checkpoint-remote-raced');
903
- }
904
- }
905
- } });
906
- return !conflict;
907
- }
908
- async function remoteContainsHead(projectRoot, remoteInput, branch, headSha) {
909
- const remote = safeRemote(remoteInput);
910
- const remoteHead = (await git(projectRoot, ['ls-remote', '--heads', remote, `refs/heads/${branch}`])).split(/\s+/)[0];
911
- return Boolean(remoteHead && await gitExitOk(projectRoot, ['merge-base', '--is-ancestor', headSha, remoteHead]));
912
- }
913
- function isLiveSameStorySetupLease(lease, storyId, nowIso) {
914
- return Boolean(lease?.ownerStoryId === storyId
915
- && lease.sessionId === lease.idempotencyKey
916
- && typeof lease.idempotencyKey === 'string'
917
- && /^setup-[a-f0-9]{64}$/.test(lease.idempotencyKey)
918
- && typeof lease.expiresAt === 'string'
919
- && Date.parse(lease.expiresAt) > Date.parse(nowIso));
920
- }
921
- async function setupHandoffTokenLocation(projectRoot, storyId) {
922
- const runtimeDirectory = await gitLifecycleRuntimeDirectory(projectRoot);
923
- const parent = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'handoffs');
924
- const name = `direct-${digest(storyId)}.json`;
925
- return { parent, name, path: join(parent, name) };
926
- }
927
- async function writeSetupHandoffTokenRecord(projectRoot, record) {
928
- const location = await setupHandoffTokenLocation(projectRoot, record.storyId);
929
- await anchoredAtomicWriteFile(location.parent, location.name, `${JSON.stringify(record, null, 2)}\n`);
930
- await assertGitLifecyclePrivateFile(location.path, location.parent);
931
- }
932
- async function readSetupHandoffTokenRecord(projectRoot, storyId) {
933
- try {
934
- const location = await setupHandoffTokenLocation(projectRoot, storyId);
935
- await assertGitLifecyclePrivateFile(location.path, location.parent);
936
- const item = JSON.parse(await readFile(location.path, 'utf8'));
937
- const exactKeys = item.state === 'issued'
938
- ? ['schemaVersion', 'kind', 'state', 'storyId', 'fromSessionId', 'token', 'tokenDigest', 'bundleDigest', 'claimRevision', 'grantDigest', 'expiresAt']
939
- : item.state === 'consuming'
940
- ? ['schemaVersion', 'kind', 'state', 'storyId', 'fromSessionId', 'token', 'tokenDigest', 'bundleDigest', 'claimRevision', 'grantDigest', 'expiresAt', 'consumedBySessionId', 'consumeStartedAt']
941
- : ['schemaVersion', 'kind', 'state', 'storyId', 'fromSessionId', 'tokenDigest', 'bundleDigest', 'claimRevision', 'grantDigest', 'expiresAt', 'consumedBySessionId', 'consumedAt'];
942
- if (Object.keys(item).sort().join('\0') !== [...exactKeys].sort().join('\0')
943
- || item.schemaVersion !== 1 || item.kind !== 'direct-yolo-setup-handoff-token'
944
- || (item.state !== 'issued' && item.state !== 'consuming' && item.state !== 'consumed') || item.storyId !== storyId
945
- || typeof item.fromSessionId !== 'string' || !/^setup-[a-f0-9]{64}$/.test(item.fromSessionId)
946
- || ![item.tokenDigest, item.bundleDigest, item.claimRevision, item.grantDigest].every((value) => typeof value === 'string' && /^[a-f0-9]{64}$/.test(value))
947
- || typeof item.expiresAt !== 'string' || !Number.isFinite(Date.parse(item.expiresAt))
948
- || (item.state === 'issued' || item.state === 'consuming')
949
- && (typeof item.token !== 'string' || !/^[A-Za-z0-9_-]{32,256}$/.test(item.token))
950
- || item.state === 'consuming' && (typeof item.consumedBySessionId !== 'string'
951
- || !/^[a-f0-9]{64}$/.test(item.consumedBySessionId)
952
- || typeof item.consumeStartedAt !== 'string' || !Number.isFinite(Date.parse(item.consumeStartedAt)))
953
- || item.state === 'consumed' && (typeof item.consumedBySessionId !== 'string'
954
- || !/^[a-f0-9]{64}$/.test(item.consumedBySessionId)
955
- || typeof item.consumedAt !== 'string' || !Number.isFinite(Date.parse(item.consumedAt))))
956
- return undefined;
957
- return item;
958
- }
959
- catch {
960
- return undefined;
961
- }
962
- }
963
- async function resolveIssuedSetupLeaseHandoff(projectRoot, storyId, bundleDigest, claimRevision, nowIso) {
964
- const record = await readSetupHandoffTokenRecord(projectRoot, storyId);
965
- if (!record || record.state === 'consumed' || !record.token
966
- || record.bundleDigest !== bundleDigest || record.claimRevision !== claimRevision
967
- || Date.parse(record.expiresAt) <= Date.parse(nowIso)
968
- || digest(record.token) !== record.tokenDigest)
969
- return undefined;
970
- return { sessionId: record.fromSessionId, token: record.token };
971
- }
972
- async function markSetupHandoffTokenConsuming(projectRoot, storyId, fromSessionId, token, consumedBySessionId, consumeStartedAt) {
973
- const record = await readSetupHandoffTokenRecord(projectRoot, storyId);
974
- if (!record || record.state === 'consumed' || record.fromSessionId !== fromSessionId
975
- || record.token !== token || record.tokenDigest !== digest(token)) {
976
- throw new Error('direct-yolo-setup-handoff-consume-invalid');
977
- }
978
- if (record.state === 'consuming') {
979
- if (record.consumedBySessionId !== consumedBySessionId) {
980
- throw new Error('direct-yolo-setup-handoff-consume-raced');
981
- }
982
- return;
983
- }
984
- await writeSetupHandoffTokenRecord(projectRoot, {
985
- ...record,
986
- state: 'consuming',
987
- consumedBySessionId,
988
- consumeStartedAt,
989
- });
990
- }
991
- async function markSetupHandoffTokenConsumed(projectRoot, epicId, storyId, fromSessionId, token, bundleDigest, claimRevision, consumedBySessionId, consumedAt) {
992
- const record = await readSetupHandoffTokenRecord(projectRoot, storyId);
993
- if (record?.state === 'consumed' && record.fromSessionId === fromSessionId
994
- && record.consumedBySessionId === consumedBySessionId)
995
- return;
996
- const runtime = await readGitLifecycleRuntime(projectRoot, { required: true });
997
- const lease = asRecord(runtime.epics[epicId]?.branch_lease);
998
- const consumption = asRecord(lease?.handoffConsumption);
999
- if (!record || record.state !== 'consuming' || record.fromSessionId !== fromSessionId
1000
- || record.token !== token || record.tokenDigest !== digest(token)
1001
- || record.bundleDigest !== bundleDigest || record.claimRevision !== claimRevision
1002
- || record.consumedBySessionId !== consumedBySessionId
1003
- || lease?.ownerStoryId !== storyId || lease.sessionId !== consumedBySessionId
1004
- || consumption?.kind !== 'direct-yolo-setup-handoff-consumption'
1005
- || consumption.state !== 'consumed' || consumption.fromSessionId !== fromSessionId
1006
- || consumption.tokenDigest !== record.tokenDigest || consumption.bundleDigest !== bundleDigest
1007
- || consumption.claimRevision !== claimRevision || consumption.consumedBySessionId !== consumedBySessionId) {
1008
- throw new Error('direct-yolo-setup-handoff-consume-invalid');
1009
- }
1010
- try {
1011
- await writeSetupHandoffTokenRecord(projectRoot, {
1012
- schemaVersion: 1, kind: record.kind, state: 'consumed', storyId,
1013
- fromSessionId, tokenDigest: record.tokenDigest, bundleDigest: record.bundleDigest,
1014
- claimRevision: record.claimRevision, grantDigest: record.grantDigest, expiresAt: record.expiresAt,
1015
- consumedBySessionId, consumedAt,
1016
- });
1017
- }
1018
- catch {
1019
- throw new Error('direct-yolo-setup-handoff-consume-persist-failed');
1020
- }
1021
- }
1022
- function validSetupLeaseHandoff(input) {
1023
- const grant = asRecord(input.current?.handoffGrant);
1024
- const token = input.handoff?.token;
1025
- const tokenDigest = typeof token === 'string' && /^[A-Za-z0-9_-]{32,256}$/.test(token)
1026
- ? digest(token)
1027
- : undefined;
1028
- return Boolean(grant && tokenDigest && input.handoff
1029
- && input.handoff.sessionId === input.current?.sessionId
1030
- && grant.schemaVersion === 1
1031
- && grant.kind === 'direct-yolo-setup-handoff'
1032
- && grant.storyId === input.storyId
1033
- && grant.fromSessionId === input.current?.sessionId
1034
- && grant.bundleDigest === input.bundleDigest
1035
- && grant.claimRevision === input.claimRevision
1036
- && typeof grant.expiresAt === 'string'
1037
- && Date.parse(grant.expiresAt) > Date.parse(input.nowIso)
1038
- && typeof grant.tokenDigest === 'string'
1039
- && /^[a-f0-9]{64}$/.test(grant.tokenDigest)
1040
- && safeDigestEqual(grant.tokenDigest, tokenDigest));
1041
- }
1042
- function safeDigestEqual(left, right) {
1043
- const leftBytes = Buffer.from(left, 'hex');
1044
- const rightBytes = Buffer.from(right, 'hex');
1045
- return leftBytes.length === 32 && rightBytes.length === 32 && timingSafeEqual(leftBytes, rightBytes);
1046
- }
1047
- function sameLease(left, right) {
1048
- return Boolean(left && ['schemaVersion', 'ownerStoryId', 'sessionId', 'idempotencyKey', 'acquiredAt', 'expiresAt']
1049
- .every((key) => left[key] === right[key]));
1050
- }
1051
- async function releaseOwnedDirectLease(projectRoot, epicId, expected) {
1052
- await mutateGitLifecycleRuntime(projectRoot, (document) => {
1053
- const epic = ensureRuntimeEpic(document, epicId);
1054
- const current = asRecord(epic.branch_lease);
1055
- if (sameLease(current, expected))
1056
- epic.branch_lease = null;
1057
- });
1058
- }
1059
- async function cleanupOwnedDirectAuthority(authority, storyId) {
1060
- const runtime = await readGitLifecycleRuntime(authority.projectRoot, { required: true });
1061
- const lease = asRecord(runtime.epics[authority.epicId]?.branch_lease);
1062
- if (!lease || lease.ownerStoryId !== storyId || !safeTokenValue(lease.sessionId)
1063
- || !safeTokenValue(lease.idempotencyKey) || !Number.isFinite(Date.parse(String(lease.acquiredAt)))
1064
- || !Number.isFinite(Date.parse(String(lease.expiresAt))))
1065
- return;
1066
- const physical = await acquireGitLifecyclePhysicalIntegrationLock(authority.projectRoot, {
1067
- kind: 'direct', storyId, sessionId: String(lease.sessionId), idempotencyKey: String(lease.idempotencyKey),
1068
- createdAt: String(lease.acquiredAt), expiresAt: String(lease.expiresAt), persistent: true,
1069
- });
1070
- if (!physical.ok)
1071
- return;
1072
- const released = await releaseGitLifecyclePhysicalIntegrationLock(physical.path, physical.owner);
1073
- if (released)
1074
- await releaseOwnedDirectLease(authority.projectRoot, authority.epicId, lease);
1075
- }
1076
- async function runQa(options, projectRoot, headSha, graphRevision) {
1077
- const transientAuthority = await executeP205TransientAuthority(projectRoot, {
1078
- headSha,
1079
- graphRevision,
1080
- nowIso: options.nowIso,
1081
- });
1082
- await options.qaRunner?.({ projectRoot, storyId: options.storyId, headSha });
1083
- const evidence = projectP205TransientExecutionEvidence(transientAuthority);
1084
- if (!evidence)
1085
- throw new Error('p205-transient-authority-invalid');
1086
- return {
1087
- contract: 'P205-CI-02', command: P205_COMPLETE_COMMAND,
1088
- manifestDigest: evidence.manifestDigest, gateIds: evidence.gateIds,
1089
- resultDigest: evidence.resultDigest, transientAuthority,
1090
- };
1091
- }
1092
- async function physicalCheckoutUnchanged(projectRoot, executionBranch, headSha, committedPaths) {
1093
- if (await git(projectRoot, ['rev-parse', 'HEAD']) !== headSha
1094
- || await git(projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']) !== executionBranch
1095
- || !(await gitExitOk(projectRoot, ['diff', '--cached', '--quiet'])))
1096
- return false;
1097
- return gitExitOk(projectRoot, ['diff', '--quiet', 'HEAD', '--', ...committedPaths]);
1098
- }
1099
- async function remoteHeadIsExact(projectRoot, remoteInput, branch, headSha) {
1100
- const remote = safeRemote(remoteInput);
1101
- const remoteHead = (await git(projectRoot, ['ls-remote', '--heads', remote, `refs/heads/${branch}`])).split(/\s+/)[0];
1102
- return remoteHead === headSha;
1103
- }
1104
- function validateDirectWriteSet(paths, authorizedWriteSet, storyId, rootMemoryEffect) {
1105
- if (paths.length === 0 || paths.some((path) => !safePath(path))) {
1106
- return { ok: false, reasonCode: 'direct-yolo-write-set-invalid' };
1107
- }
1108
- const required = [
1109
- '.neocortex/state.json', `docs/stories/${storyId}.story.md`,
1110
- `.neocortex/stories/${storyId}/qa-gate-result.json`,
1111
- `.neocortex/stories/${storyId}/validation-evidence.md`,
1112
- `.neocortex/stories/${storyId}/review.md`,
1113
- ];
1114
- if (!required.every((path) => paths.includes(path)) || !required.every((path) => authorizedWriteSet.includes(path))) {
1115
- return { ok: false, reasonCode: 'direct-yolo-write-set-invalid' };
1116
- }
1117
- if (rootMemoryEffect && (rootMemoryEffect.storyId !== storyId
1118
- || rootMemoryEffect.childClaimRevision !== digest([...authorizedWriteSet].sort().join('\0')))) {
1119
- return { ok: false, reasonCode: 'direct-yolo-root-memory-claim-mismatch' };
1120
- }
1121
- if (paths.some((path) => !authorizedWriteSet.includes(path) && !rootMemoryEffect?.files.some(file => file.path === path))) {
1122
- return { ok: false, reasonCode: 'direct-yolo-write-set-unauthorized' };
1123
- }
1124
- return { ok: true };
1125
- }
1126
- function safePath(value) {
1127
- return value.length > 0 && value.length <= 1024 && !value.startsWith('/') && !value.includes('\\')
1128
- && !value.split('/').includes('..') && !value.startsWith('.git/') && !value.includes('\0');
1129
- }
1130
- function safeTokenValue(value) {
1131
- return typeof value === 'string' && value.length > 0 && value.length <= 512
1132
- && /^[A-Za-z0-9._:@/+\-=]+$/.test(value);
1133
- }
1134
- function safeRef(value) {
1135
- return value.length > 0 && value.length <= 240 && !value.startsWith('-') && !/[\s~^:?*[\\]/.test(value) && !value.includes('..');
1136
- }
1137
- function safeRemote(value) {
1138
- if (!/^[A-Za-z0-9._-]{1,128}$/.test(value))
1139
- throw new Error('direct-yolo-remote-invalid');
1140
- return value;
1141
- }
1142
- function trailer(body, key) {
1143
- const prefix = `${key}: `;
1144
- const values = body.split('\n').map((line) => line.trim()).filter((line) => line.startsWith(prefix)).map((line) => line.slice(prefix.length));
1145
- return values.length === 1 ? values[0] : undefined;
1146
- }
1147
- function digest(value) { return createHash('sha256').update(value).digest('hex'); }
1148
- function splitNull(value) { return value.split('\0').filter(Boolean); }
1149
- function normalizedTime(value) {
1150
- return value && Number.isFinite(Date.parse(value)) ? new Date(Date.parse(value)).toISOString() : new Date().toISOString();
1151
- }
1152
- function asRecord(value) {
1153
- return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
1154
- }
1155
- function validOriginBinding(value, executionBranch, originBranch) {
1156
- const item = asRecord(value);
1157
- if (!item || item.schemaVersion !== 1 || item.originBranch !== originBranch
1158
- || item.executionBranch !== executionBranch || item.capturedFromCurrentCheckout !== true
1159
- || typeof item.originHeadSha !== 'string' || !/^[a-f0-9]{40,64}$/.test(item.originHeadSha)
1160
- || typeof item.capturedAt !== 'string' || !Number.isFinite(Date.parse(item.capturedAt)))
1161
- return undefined;
1162
- return item;
1163
- }
1164
- function setupReceipt(authority, binding, leaseExpiresAt, reused) {
1165
- return Object.freeze({
1166
- schemaVersion: 1, kind: 'direct-yolo-setup-receipt', storyId: authority.storyId,
1167
- epicId: authority.epicId, executionBranch: authority.executionBranch, originBranch: authority.originBranch,
1168
- originHeadSha: binding.originHeadSha, leaseExpiresAt, reused, publicSafe: true,
1169
- });
1170
- }
1171
- async function checkoutPayload(projectRoot) {
1172
- const untrackedPaths = splitNull(await gitRaw(projectRoot, [
1173
- 'ls-files', '--others', '--exclude-standard', '-z',
1174
- ])).sort();
1175
- const untrackedBlobs = await Promise.all(untrackedPaths.map(async (path) => {
1176
- if (!safePath(path))
1177
- throw new Error('direct-yolo-checkout-payload-invalid');
1178
- return `${path}\0${await git(projectRoot, ['hash-object', '--no-filters', '--', path])}`;
1179
- }));
1180
- return digest([
1181
- await gitRaw(projectRoot, ['diff', '--cached', '--binary', '--full-index']),
1182
- await gitRaw(projectRoot, ['diff', '--binary', '--full-index']),
1183
- await gitRaw(projectRoot, ['status', '--porcelain=v1', '-z', '--untracked-files=all']),
1184
- ...untrackedBlobs,
1185
- ].join('\0'));
1186
- }
1187
- /** Physical observation for a private YOLO agent step; this is not actor attribution. */
1188
- export async function captureDirectYoloCheckoutEvidence(projectRootInput) {
1189
- const projectRoot = resolve(projectRootInput);
1190
- const headSha = await git(projectRoot, ['rev-parse', 'HEAD']);
1191
- const branch = await git(projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
1192
- const payloadDigest = await checkoutPayload(projectRoot);
1193
- if (await git(projectRoot, ['rev-parse', 'HEAD']) !== headSha
1194
- || await git(projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']) !== branch) {
1195
- throw new Error('direct-yolo-checkout-observation-raced');
1196
- }
1197
- return Object.freeze({ headSha, branch, payloadDigest });
1198
- }
1199
- async function worktreeBranches(projectRoot) {
1200
- const records = [];
1201
- let current;
1202
- for (const line of (await gitRaw(projectRoot, ['worktree', 'list', '--porcelain'])).split('\n')) {
1203
- if (line.startsWith('worktree ')) {
1204
- current = { path: line.slice('worktree '.length) };
1205
- records.push(current);
1206
- }
1207
- else if (current && line.startsWith('branch refs/heads/')) {
1208
- current.branch = line.slice('branch refs/heads/'.length);
1209
- }
1210
- }
1211
- return records;
1212
- }
1213
- function publicReason(error, fallback) {
1214
- if (error instanceof Error && error.message === 'git-lifecycle-runtime-revision-conflict') {
1215
- return 'direct-yolo-runtime-revision-conflict';
1216
- }
1217
- return error instanceof Error && /^direct-yolo-[a-z0-9-]+$/.test(error.message) ? error.message : fallback;
1218
- }
1219
- function failure(reasonCode) { return { ok: false, reasonCode }; }
1220
- async function git(cwd, args) {
1221
- return String((await execFileAsync('git', [...args], { cwd, encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 })).stdout).trim();
1222
- }
1223
- async function gitRaw(cwd, args) {
1224
- return String((await execFileAsync('git', [...args], { cwd, encoding: 'utf8', maxBuffer: 32 * 1024 * 1024 })).stdout);
1225
- }
1226
- async function gitExitOk(cwd, args) {
1227
- try {
1228
- await execFileAsync('git', [...args], { cwd, maxBuffer: 8 * 1024 * 1024 });
1229
- return true;
1230
- }
1231
- catch {
1232
- return false;
1233
- }
1234
- }
1
+ import{execFile as _e}from"node:child_process";import{createHash as Le,randomBytes as le,timingSafeEqual as He}from"node:crypto";import{readFile as J}from"node:fs/promises";import{join as te,resolve as Z}from"node:path";import{promisify as Ce}from"node:util";import{readRootMemoryEffectForCheckpoint as qe}from"../private-execution/root-memory-scope.js";import{rootMemoryEffectDigest as Oe,verifyRootMemoryPhysicalWriteSet as re}from"../private-execution/root-memory-git-evidence.js";import{acquireGitLifecyclePhysicalIntegrationLock as W,applyGitLifecycleRuntimeOverlay as $e,computeImmutableStoryQaEvidenceDigest as ze,computeGitLifecyclePhysicalIntegrationLockOwnerDigest as ge,computeP205StoryQaEvidenceDigest as Pe,computeLegacyDirectYoloRecoveryReceiptRef as Ne,ensureRuntimeEpic as P,ensureRuntimeStory as me,ensureGitLifecyclePrivateChildDirectory as We,executeP205TransientAuthority as Ge,projectP205TransientExecutionEvidence as Me,publicStoryReviewArtifactFromGit as Q,LEGACY_DIRECT_YOLO_RECOVERY_COMMITS as Ke,mutateGitLifecycleRuntime as $,P205_COMPLETE_COMMAND as Ve,readGitLifecycleRuntime as C,gitLifecycleRuntimeDirectory as Fe,assertGitLifecyclePrivateFile as we,releaseGitLifecyclePhysicalIntegrationLock as G,releaseGitLifecyclePhysicalIntegrationLockForCheckpoint as Te,verifyGitLifecyclePhysicalIntegrationLock as U,verifyAcceptedGitLifecycleStoryCheckpoint as Ie}from"./git-lifecycle-store.js";import{anchoredAtomicWriteFile as Ye}from"./secure-filesystem-boundary.js";import{GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID as Je,GIT_LIFECYCLE_REVIEW_PR_STEP_ID as Re,GIT_LIFECYCLE_SETUP_BRANCH_STEP_ID as X}from"./git-lifecycle-step-ids.js";const oe=Ce(_e);async function yt(e){try{const t=await ve(e.projectRoot,e.storyId),r=N(e.nowIso),o=Date.parse(r),i=await l(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),n=await l(t.projectRoot,["rev-parse","HEAD"]),y=await C(t.projectRoot,{required:!0}),h=m(y.epics[t.epicId]),d=m(h?.branch_lease),a=d&&Number.isFinite(Date.parse(String(d.expiresAt)))&&Date.parse(String(d.expiresAt))>o;if(a&&d?.ownerStoryId!==e.storyId)return c("direct-yolo-writer-active");let s=he(h?.origin_binding,t.executionBranch,t.originBranch);if(i===t.executionBranch){if(!s)return c("direct-yolo-origin-binding-invalid")}else{if(i!==t.originBranch)return c("direct-yolo-current-branch-mismatch");if(s&&s.originHeadSha!==n)return c("direct-yolo-origin-binding-conflict");if(s??={schemaVersion:1,originBranch:t.originBranch,originHeadSha:n,executionBranch:t.executionBranch,capturedFromCurrentCheckout:!0,capturedAt:r},(await Ee(t.projectRoot)).some(u=>u.branch===t.executionBranch&&Z(u.path)!==t.projectRoot))return c("direct-yolo-execution-branch-checked-out-elsewhere");const w=await T(t.projectRoot),j=`refs/heads/${t.executionBranch}`;if(await L(t.projectRoot,["show-ref","--verify","--quiet",j])){const u=await l(t.projectRoot,["rev-parse",j]);if(u!==n){if(!await L(t.projectRoot,["merge-base","--is-ancestor",u,n]))return c("direct-yolo-execution-branch-diverged");await l(t.projectRoot,["update-ref",j,n,u])}await l(t.projectRoot,["switch",t.executionBranch])}else await l(t.projectRoot,["switch","-c",t.executionBranch]);if(await T(t.projectRoot)!==w)return c("direct-yolo-checkout-payload-raced")}const p=await l(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),f=await l(t.projectRoot,["rev-parse","HEAD"]);if(p!==t.executionBranch)return c("direct-yolo-current-branch-mismatch");if(a&&d?.ownerStoryId===e.storyId)return d.setupHeadSha!==f?c("direct-yolo-setup-lease-head-unbound"):{ok:!0,value:ue(t,s,String(d.expiresAt),!0)};const R=r,k=new Date(o+3600*1e3).toISOString(),I=`setup-${le(32).toString("hex")}`,v=await C(t.projectRoot,{required:!0});return await $(t.projectRoot,x=>{const w=P(x,t.epicId),j=m(w.branch_lease);if(j&&Date.parse(String(j.expiresAt))>o&&j.ownerStoryId!==e.storyId)throw new Error("direct-yolo-writer-active");const u=he(w.origin_binding,t.executionBranch,t.originBranch);if(w.origin_binding&&!u)throw new Error("direct-yolo-origin-binding-conflict");if(u&&JSON.stringify(u)!==JSON.stringify(s))throw new Error("direct-yolo-origin-binding-conflict");w.branch_mode="epic",w.execution_branch=t.executionBranch,w.origin_branch=t.originBranch,w.graph_revision=t.graphRevision,w.origin_binding=s,w.branch_lease={schemaVersion:1,ownerStoryId:e.storyId,sessionId:I,idempotencyKey:I,acquiredAt:R,expiresAt:k,setupHeadSha:f}},{expectedRevision:v.revision,preCommit:async()=>{if(await l(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"])!==t.executionBranch||await l(t.projectRoot,["rev-parse","HEAD"])!==f)throw new Error("direct-yolo-setup-physical-state-raced")}}),{ok:!0,value:ue(t,s,k,!1)}}catch(t){return c(Y(t,"direct-yolo-setup-failed"))}}async function pt(e){let t;try{const r=await K(e.projectRoot,e.storyId),o=N(e.nowIso),i=te(r.projectRoot,".neocortex/state.json"),n=await J(i,"utf8"),y=await T(r.projectRoot),h=await l(r.projectRoot,["rev-parse","HEAD"]),d=`refs/heads/${r.executionBranch}`,a=await C(r.projectRoot,{required:!0}),s=m(a.epics[r.epicId]),p=he(s?.origin_binding,r.executionBranch,r.originBranch),f=m(s?.branch_lease);if(!p)return c("direct-yolo-origin-binding-invalid");if(!f||!ie(f,e.storyId,o)||f?.sessionId!==f?.idempotencyKey)return c("direct-yolo-setup-lease-invalid");const R=await W(r.projectRoot,{kind:"direct",storyId:e.storyId,sessionId:String(f.sessionId),idempotencyKey:String(f.idempotencyKey),expiresAt:new Date(Date.now()+300*1e3).toISOString(),persistent:!1});if(!R.ok)return c(R.reasonCode);if(t=R,h!==f.setupHeadSha||!await L(r.projectRoot,["merge-base","--is-ancestor",p.originHeadSha,h])||await l(r.projectRoot,["rev-parse",d])!==h)return c("direct-yolo-setup-head-mismatch");if((await Ee(r.projectRoot)).some(u=>u.branch===r.executionBranch&&Z(u.path)!==r.projectRoot))return c("direct-yolo-execution-branch-checked-out-elsewhere");const I=m(JSON.parse(n)),v=m(m(I?.stories)?.[e.storyId]),x=m(a.stories[e.storyId]);if(!v||!["backlog","ready_to_start"].includes(String(v.status))||v.steps_completed!==void 0&&(!Array.isArray(v.steps_completed)||v.steps_completed.length>0)||v.branch_name||v.checkpoint)return c("direct-yolo-setup-story-progress-conflict");const w=x?.status==="branch-ready"&&x.last_step===X&&Array.isArray(x.steps_completed)&&x.steps_completed.length===1&&x.steps_completed[0]===X&&Object.keys(x).sort().join(",")==="last_step,status,steps_completed";if(x&&Object.keys(x).length>0&&!w)return c("direct-yolo-setup-story-progress-conflict");const j=async()=>{if(Date.parse(String(f.expiresAt))<=(e.nowIso?Date.parse(o):Date.now())||!t||!await U(t.path,t.owner)||await J(i,"utf8")!==n||await T(r.projectRoot)!==y||await l(r.projectRoot,["symbolic-ref","--quiet","--short","HEAD"])!==r.executionBranch||await l(r.projectRoot,["rev-parse","HEAD"])!==h||!await L(r.projectRoot,["merge-base","--is-ancestor",p.originHeadSha,h])||await l(r.projectRoot,["rev-parse",d])!==h)throw new Error("direct-yolo-setup-physical-state-raced")};return w?await j():await $(r.projectRoot,u=>{const b=m(u.epics[r.epicId]),g=me(u,e.storyId);if(JSON.stringify(b?.branch_lease)!==JSON.stringify(f)||JSON.stringify(b?.origin_binding)!==JSON.stringify(p)||b?.graph_revision!==r.graphRevision||Object.keys(g).length>0)throw new Error("direct-yolo-setup-runtime-raced");g.status="branch-ready",g.last_step=X,g.steps_completed=[X]},{expectedRevision:a.revision,preCommit:j}),{ok:!0,value:Object.freeze({...ue(r,p,String(f.expiresAt),w),checkpointAccepted:!0,graphRevision:r.graphRevision,headSha:h})}}catch(r){return c(Y(r,"direct-yolo-setup-acceptance-failed"))}finally{t&&await G(t.path,t.owner).catch(()=>{})}}async function lt(e){try{const t=await K(e.projectRoot,e.storyId),r=q(await A(t.projectRoot,["diff","--cached","--name-only","-z"])),o=V(r,t.authorizedWriteSet,e.storyId,t.rootMemoryEffect);if(!o.ok)return c(o.reasonCode);if(t.rootMemoryEffect&&re(t.projectRoot,t.rootMemoryEffect,{storyId:e.storyId,executionBranch:t.executionBranch,baseSha:await l(t.projectRoot,["rev-parse","HEAD"]),headRef:":",childPaths:t.authorizedWriteSet}),Q(t.projectRoot,e.storyId,":")?.verdict!=="approved")return c("direct-yolo-review-artifact-not-approved");if(q(await A(t.projectRoot,["diff","--name-only","-z"])).some(S=>r.includes(S)))return c("direct-yolo-user-overlap");const y=await A(t.projectRoot,["diff","--cached","--binary","--full-index"]);if(!y)return c("direct-yolo-staged-diff-empty");const h=D(y),d=D([...t.authorizedWriteSet].sort().join("\0")),a=N(e.nowIso),s=await C(t.projectRoot,{required:!0}),p=m(s.epics[t.epicId]?.branch_lease);if(!ie(p,e.storyId,a))return c("direct-yolo-setup-handoff-owner-invalid");const f=String(p.sessionId),R=String(p.expiresAt),k=new Date(Math.min(Date.parse(R),Date.parse(a)+300*1e3)).toISOString(),I=await M(t.projectRoot,e.storyId),v=I?.state==="issued"&&I.fromSessionId===f&&I.bundleDigest===h&&I.claimRevision===d&&Date.parse(I.expiresAt)>Date.parse(a),x=v?I.expiresAt:k,w=v?I.token:le(32).toString("base64url"),j=D(w),u=Object.freeze({schemaVersion:1,kind:"direct-yolo-setup-handoff",storyId:e.storyId,fromSessionId:f,tokenDigest:j,bundleDigest:h,claimRevision:d,expiresAt:x}),b=D(JSON.stringify(u)),g=await W(t.projectRoot,{kind:"direct",storyId:e.storyId,sessionId:f,idempotencyKey:f,expiresAt:x,persistent:!1,createdAt:a});if(!g.ok)return c(g.reasonCode==="git-lifecycle-integration-backpressure"?"direct-yolo-integration-backpressure":"direct-yolo-integration-lock-failed");try{await ne(t.projectRoot,{schemaVersion:1,kind:"direct-yolo-setup-handoff-token",state:"issued",storyId:e.storyId,fromSessionId:f,token:w,tokenDigest:j,bundleDigest:h,claimRevision:d,grantDigest:b,expiresAt:x}),await $(t.projectRoot,S=>{const E=m(P(S,t.epicId).branch_lease);if(!ie(E,e.storyId,a)||E?.sessionId!==f||E.idempotencyKey!==f)throw new Error("direct-yolo-setup-handoff-owner-raced");E.handoffGrant=u},{expectedRevision:s.revision,preCommit:async()=>{if(!await U(g.path,g.owner))throw new Error("direct-yolo-integration-lock-raced");const S=await M(t.projectRoot,e.storyId);if(!S||S.state!=="issued"||S.grantDigest!==b||S.tokenDigest!==j)throw new Error("direct-yolo-setup-handoff-token-raced")}})}finally{await G(g.path,g.owner).catch(()=>{})}return{ok:!0,value:Object.freeze({schemaVersion:1,kind:"direct-yolo-setup-handoff-receipt",storyId:e.storyId,sessionId:f,bundleDigest:h,claimRevision:d,grantDigest:b,expiresAt:x,reused:v,publicSafe:!0})}}catch(t){return c(t instanceof Error&&/^direct-yolo-/.test(t.message)?t.message:"direct-yolo-setup-handoff-failed")}}async function gt(e){try{const t=await K(e.projectRoot,e.storyId),r=await l(t.projectRoot,["rev-parse","HEAD"]),o=q(await A(t.projectRoot,["diff","--cached","--name-only","-z"])),i=V(o,t.authorizedWriteSet,e.storyId,t.rootMemoryEffect);if(!i.ok)return c(i.reasonCode);t.rootMemoryEffect&&re(t.projectRoot,t.rootMemoryEffect,{storyId:e.storyId,executionBranch:t.executionBranch,baseSha:r,headRef:":",childPaths:t.authorizedWriteSet});const n=Q(t.projectRoot,e.storyId,":");if(n?.verdict!=="approved")return c("direct-yolo-review-artifact-not-approved");if(q(await A(t.projectRoot,["diff","--name-only","-z"])).some(u=>o.includes(u)))return c("direct-yolo-user-overlap");const h=await A(t.projectRoot,["diff","--cached","--binary","--full-index"]);if(!h)return c("direct-yolo-staged-diff-empty");const d=D(h),a=D([...t.authorizedWriteSet].sort().join("\0")),s=D(["direct-yolo-commit-v1",e.storyId,t.epicId,t.executionBranch,r,d,t.graphRevision,a].join("\0")),p=N(e.nowIso);let f=e.setupLeaseHandoff??await Ze(t.projectRoot,e.storyId,d,a,p);const R=await C(t.projectRoot,{required:!0}),k=m(R.epics[t.epicId]?.branch_lease),I=k?.ownerStoryId===e.storyId&&k.sessionId===s&&k.idempotencyKey===s&&typeof k.expiresAt=="string"&&Date.parse(k.expiresAt)>Date.parse(p)?k:void 0;if(I&&e.setupLeaseHandoff)return c("direct-yolo-setup-handoff-replayed");const v=m(I?.handoffConsumption);if(v){const u=await M(t.projectRoot,e.storyId);if(!u||!["consuming","consumed"].includes(u.state)||u.fromSessionId!==v.fromSessionId||u.tokenDigest!==v.tokenDigest||u.bundleDigest!==d||u.claimRevision!==a||v.bundleDigest!==d||v.claimRevision!==a||u.consumedBySessionId!==s||v.consumedBySessionId!==s)return c("direct-yolo-setup-handoff-consume-invalid");if(u.state==="consuming"){if(!u.token||D(u.token)!==u.tokenDigest)return c("direct-yolo-setup-handoff-consume-invalid");f={sessionId:u.fromSessionId,token:u.token}}}const x=I?String(I.expiresAt):new Date(Date.parse(p)+1800*1e3).toISOString(),w=await W(t.projectRoot,{kind:"direct",storyId:e.storyId,sessionId:s,idempotencyKey:s,expiresAt:x,persistent:!0,createdAt:I&&typeof I.acquiredAt=="string"?I.acquiredAt:p});if(!w.ok)return c(w.reasonCode==="git-lifecycle-integration-backpressure"?"direct-yolo-integration-backpressure":"direct-yolo-integration-lock-failed");try{f&&e.setupLeaseHandoff===void 0&&(await Qe(t.projectRoot,e.storyId,f.sessionId,f.token,s,p),await e.setupHandoffFault?.("after-consuming-persisted")),await $(t.projectRoot,u=>{const b=P(u,t.epicId),g=m(b.branch_lease),S=g&&Date.parse(String(g.expiresAt))>Date.parse(p),E=g?.ownerStoryId===e.storyId&&g.sessionId===s&&g.idempotencyKey===s,O=g?.ownerStoryId===e.storyId&&g.sessionId===g.idempotencyKey&&typeof g.idempotencyKey=="string"&&/^setup-[a-f0-9]{64}$/.test(g.idempotencyKey),B=S&&O&&Xe({current:g,handoff:f,storyId:e.storyId,bundleDigest:d,claimRevision:a,nowIso:p});if(f&&S&&!E&&!B)throw new Error("direct-yolo-setup-handoff-invalid");if(S&&!E&&!B)throw new Error("direct-yolo-writer-active");const _=B?m(g?.handoffGrant):void 0,H=_?{schemaVersion:1,kind:"direct-yolo-setup-handoff-consumption",state:"consumed",storyId:e.storyId,fromSessionId:String(g?.sessionId),tokenDigest:String(_.tokenDigest),bundleDigest:d,claimRevision:a,consumedBySessionId:s,consumedAt:p}:void 0;b.branch_mode="epic",b.execution_branch=t.executionBranch,b.origin_branch=t.originBranch,b.graph_revision=t.graphRevision,b.branch_lease=S&&E?g:{schemaVersion:1,ownerStoryId:e.storyId,sessionId:s,idempotencyKey:s,acquiredAt:p,expiresAt:x,...H?{handoffConsumption:H}:{}}},{expectedRevision:R.revision,preCommit:async()=>{if(!await U(w.path,w.owner))throw new Error("direct-yolo-integration-lock-raced")}})}catch(u){throw await G(w.path,w.owner).catch(()=>{}),u}f&&e.setupLeaseHandoff===void 0&&(await e.setupHandoffFault?.("before-consumed-persist"),await Ue(t.projectRoot,t.epicId,e.storyId,f.sessionId,f.token,d,a,s,p));const j=Object.freeze([`Neocortex-Story: ${e.storyId}`,`Neocortex-Epic: ${t.epicId}`,`Neocortex-Execution-Branch: ${t.executionBranch}`,`Neocortex-Prepared-Base: ${r}`,`Neocortex-Bundle-Digest: ${d}`,`Neocortex-Review-Artifact-Digest: ${n.digest}`,`Neocortex-Graph-Revision: ${t.graphRevision}`,`Neocortex-Claim-Revision: ${a}`,...t.rootMemoryEffect?[`Neocortex-Root-Memory-Effect: ${Oe(t.rootMemoryEffect)}`]:[]]);return{ok:!0,value:Object.freeze({schemaVersion:1,storyId:e.storyId,epicId:t.epicId,executionBranch:t.executionBranch,baseSha:r,bundleDigest:d,reviewArtifactDigest:n.digest,graphRevision:t.graphRevision,claimRevision:a,idempotencyKey:s,changedPaths:Object.freeze(o),trailers:j})}}catch(t){return c(Y(t,"direct-yolo-begin-failed"))}}async function mt(e){let t,r,o;try{const i=await K(e.projectRoot,e.storyId);t=i;const n=await l(i.projectRoot,["rev-parse","HEAD"]);let y=await C(i.projectRoot,{required:!0});const h=m(y.stories[e.storyId]?.checkpoint);if(h){const B=typeof h.headSha=="string"?h.headSha:"",_=typeof h.graphRevision=="string"?h.graphRevision:"",H=/^[a-f0-9]{40,64}$/.test(B)?q(await A(i.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",B])):[],z=V(H,i.authorizedWriteSet,e.storyId,i.rootMemoryEffect);if(!(/^[a-f0-9]{40,64}$/.test(B)&&await L(i.projectRoot,["merge-base","--is-ancestor",B,n]))||!/^[a-f0-9]{64}$/.test(_)||!z.ok)return c("direct-yolo-replay-invalid");const Be=await se(e,i.projectRoot,n,_);if(!await Ie(i.projectRoot,h,e.storyId,i.epicId,i.executionBranch,Be.transientAuthority,i.authorizedWriteSet))return c("direct-yolo-replay-invalid");if(!await de(i.projectRoot,i.executionBranch,n,H))return c("direct-yolo-replay-head-raced");if(e.push&&!await ke(i.projectRoot,e.remote??"origin",i.executionBranch,B))return c("direct-yolo-remote-head-mismatch");const ye=Array.isArray(h.receiptRefs)?h.receiptRefs.find(pe=>typeof pe=="string"&&/^physical-lock-owner:[a-f0-9]{64}$/.test(pe)):void 0;return ye&&typeof h.idempotencyKey=="string"&&await Te(i.projectRoot,{storyId:e.storyId,idempotencyKey:h.idempotencyKey,ownerDigest:ye.slice(20)}),{ok:!0,value:h}}const d=n,a=await l(i.projectRoot,["rev-parse",`${d}^`]),s=await A(i.projectRoot,["show","--no-patch","--format=%B",d]),p=q(await A(i.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",d])),f=V(p,i.authorizedWriteSet,e.storyId,i.rootMemoryEffect);if(!f.ok)return c(f.reasonCode);i.rootMemoryEffect&&re(i.projectRoot,i.rootMemoryEffect,{storyId:e.storyId,executionBranch:i.executionBranch,baseSha:a,headRef:d,childPaths:i.authorizedWriteSet});const R=F(s,"Neocortex-Bundle-Digest"),k=F(s,"Neocortex-Graph-Revision"),I=F(s,"Neocortex-Claim-Revision"),v=new Map([["Neocortex-Story",e.storyId],["Neocortex-Epic",i.epicId],["Neocortex-Execution-Branch",i.executionBranch],["Neocortex-Prepared-Base",a],["Neocortex-Graph-Revision",i.graphRevision],["Neocortex-Claim-Revision",D([...i.authorizedWriteSet].sort().join("\0"))]]);if(!R||!/^[a-f0-9]{64}$/.test(R)||!k||!I||[...v].some(([B,_])=>F(s,B)!==_))return c("direct-yolo-trailers-invalid");const x=Q(i.projectRoot,e.storyId,d);if(x?.verdict!=="approved")return c("direct-yolo-review-artifact-not-approved");const w=F(s,"Neocortex-Review-Artifact-Digest");if(w!==void 0&&w!==x.digest)return c("direct-yolo-review-artifact-digest-mismatch");const j=D(await A(i.projectRoot,["diff","--binary","--full-index",`${a}..${d}`]));if(R!==j)return c("direct-yolo-bundle-digest-mismatch");const u=D(["direct-yolo-commit-v1",e.storyId,i.epicId,i.executionBranch,a,R,k,I].join("\0")),b=m(y.epics[i.epicId]?.branch_lease),g=N(e.nowIso),S=b?.ownerStoryId===e.storyId&&b.idempotencyKey===u&&b.sessionId===u&&Date.parse(String(b.expiresAt))>Date.now()?b:void 0;if(b&&Date.parse(String(b.expiresAt))>Date.now()&&!S)return c("direct-yolo-writer-active");const E=S??{schemaVersion:1,ownerStoryId:e.storyId,sessionId:u,idempotencyKey:u,acquiredAt:g,expiresAt:new Date(Date.parse(g)+1800*1e3).toISOString()},O=await W(i.projectRoot,{kind:"direct",storyId:e.storyId,sessionId:u,idempotencyKey:u,expiresAt:String(E.expiresAt),persistent:!0,createdAt:String(E.acquiredAt)});if(!O.ok)return c(O.reasonCode==="git-lifecycle-integration-backpressure"?"direct-yolo-integration-backpressure":"direct-yolo-integration-lock-failed");o=O,S||(y=(await $(i.projectRoot,_=>{const H=P(_,i.epicId),z=m(H.branch_lease);if(z&&Date.parse(String(z.expiresAt))>Date.parse(g))throw new Error("direct-yolo-writer-active");if(H.graph_revision!==i.graphRevision)throw new Error("direct-yolo-graph-revision-raced");H.branch_lease=E},{expectedRevision:y.revision})).document),r=E;{const B=await se(e,i.projectRoot,d,i.graphRevision);if(!await de(i.projectRoot,i.executionBranch,d,p))return c("direct-yolo-head-raced");if(e.push){const z=ee(e.remote??"origin");if(await l(i.projectRoot,["push",z,i.executionBranch]),!await De(i.projectRoot,z,i.executionBranch,d))return c("direct-yolo-remote-head-mismatch")}const _=await Se({projectRoot:i.projectRoot,storyId:e.storyId,epicId:i.epicId,executionBranch:i.executionBranch,baseSha:a,headSha:d,bundleDigest:R,graphRevision:k,claimRevision:I,idempotencyKey:u,qaExecution:B,physicalLockOwnerDigest:ge(O.owner),nowIso:N(e.nowIso),legacyReceiptRef:void 0,rootMemoryEffect:i.rootMemoryEffect});return await e.beforeCheckpointPersist?.(),await xe({projectRoot:i.projectRoot,checkpoint:_,remote:e.push?e.remote??"origin":void 0,expectedRevision:y.revision,expectedLease:E,expectedGraphRevision:i.graphRevision,physicalLockPath:O.path,physicalLockOwner:O.owner,transientAuthority:B.transientAuthority,authorizedWriteSet:i.authorizedWriteSet})?(await e.afterCheckpointPersist?.(),{ok:!0,value:_}):c("direct-yolo-checkpoint-persist-failed")}}catch(i){return c(Y(i,"direct-yolo-finalize-failed"))}finally{o&&await G(o.path,o.owner).catch(()=>{}),t&&r?await ce(t.projectRoot,t.epicId,r).catch(()=>{}):t&&await tt(t,e.storyId).catch(()=>{})}}async function wt(e){try{const t=await K(e.projectRoot,e.storyId);if(!/^[a-f0-9]{40,64}$/.test(e.commitSha))return c("direct-yolo-recovery-commit-invalid");const r=await l(t.projectRoot,["rev-parse",e.commitSha]);if(Ke[e.storyId]!==r)return c("direct-yolo-recovery-not-allowlisted");if(await l(t.projectRoot,["rev-parse","HEAD"])!==r)return c("direct-yolo-recovery-head-mismatch");await l(t.projectRoot,["merge-base","--is-ancestor",r,`refs/heads/${t.executionBranch}`]);const o=await l(t.projectRoot,["rev-parse",`${r}^`]),i=await A(t.projectRoot,["diff","--binary","--full-index",`${o}..${r}`]),n=q(await A(t.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",r]));if(!V(n,t.authorizedWriteSet.length>0?t.authorizedWriteSet:n,e.storyId).ok)return c("direct-yolo-recovery-write-set-invalid");const h=D(i),d=D([...n].sort().join("\0")),a=D(["legacy-direct-yolo-recovery-v1",e.storyId,r].join("\0")),s=N(e.nowIso),p=new Date(Date.parse(s)+1800*1e3).toISOString(),f=await C(t.projectRoot,{required:!0}),R=await W(t.projectRoot,{kind:"direct",storyId:e.storyId,sessionId:a,idempotencyKey:a,expiresAt:p,persistent:!0,createdAt:s});if(!R.ok)return c(R.reasonCode==="git-lifecycle-integration-backpressure"?"direct-yolo-recovery-integration-backpressure":"direct-yolo-recovery-integration-lock-failed");const k={schemaVersion:1,ownerStoryId:e.storyId,sessionId:a,idempotencyKey:a,acquiredAt:s,expiresAt:p};let I=!1;try{const v=await $(t.projectRoot,g=>{const S=P(g,t.epicId),E=m(S.branch_lease);if(E&&Date.parse(String(E.expiresAt))>Date.parse(s)&&!ae(E,k))throw new Error("direct-yolo-recovery-writer-active");if(S.graph_revision!==t.graphRevision)throw new Error("direct-yolo-recovery-graph-raced");S.branch_mode="epic",S.execution_branch=t.executionBranch,S.origin_branch=t.originBranch,S.branch_lease=k},{expectedRevision:f.revision});I=!0;const x=await se(e,t.projectRoot,r,t.graphRevision);if(!await de(t.projectRoot,t.executionBranch,r,n))return c("direct-yolo-recovery-head-raced");if(e.push){const g=ee(e.remote??"origin"),S=(await l(t.projectRoot,["ls-remote","--heads",g,`refs/heads/${t.executionBranch}`])).split(/\s+/)[0];if(!S||!await L(t.projectRoot,["merge-base","--is-ancestor",r,S]))return c("direct-yolo-recovery-remote-proof-missing")}const w=await Se({projectRoot:t.projectRoot,storyId:e.storyId,epicId:t.epicId,executionBranch:t.executionBranch,baseSha:o,headSha:r,bundleDigest:h,graphRevision:t.graphRevision,claimRevision:d,idempotencyKey:a,qaExecution:x,physicalLockOwnerDigest:ge(R.owner),nowIso:s,legacyReceiptRef:void 0}),j=await Ne(t.projectRoot,{storyId:e.storyId,epicId:t.epicId,executionBranch:t.executionBranch,baseSha:o,headSha:r,bundleDigest:h,graphRevision:t.graphRevision});if(!j)return c("direct-yolo-recovery-evidence-invalid");const u=Object.freeze({...w,receiptRefs:Object.freeze([...w.receiptRefs,j])});return await xe({projectRoot:t.projectRoot,checkpoint:u,remote:e.push?e.remote??"origin":void 0,remotePolicy:"ancestor-recovery",expectedRevision:v.document.revision,expectedLease:k,expectedGraphRevision:t.graphRevision,physicalLockPath:R.path,physicalLockOwner:R.owner,transientAuthority:x.transientAuthority,authorizedWriteSet:t.authorizedWriteSet})?{ok:!0,value:u}:c("direct-yolo-recovery-persist-failed")}finally{await G(R.path,R.owner).catch(()=>{}),I&&await ce(t.projectRoot,t.epicId,k).catch(()=>{})}}catch(t){return c(Y(t,"direct-yolo-recovery-failed"))}}async function ve(e,t){if(!/^[A-Za-z][A-Za-z0-9_-]*\.[A-Za-z0-9._-]+$/.test(t))throw new Error("direct-yolo-story-id-invalid");const r=Z(e),o=m(JSON.parse(await J(te(r,".neocortex/state.json"),"utf8"))),i=await C(r,{required:!0}),n=$e(o,i),y=m(n.stories),h=m(n.epics),d=m(y?.[t]),a=String(d?.epic_id??t.split(".")[0]),s=m(h?.[a]),p=String(s?.execution_branch??""),f=String(s?.origin_branch??""),R=String(s?.graph_revision??""),k=Array.isArray(d?.files_to_modify)?[...new Set(d.files_to_modify.filter(v=>typeof v=="string"&&fe(v)))].sort():[];if(!d)throw new Error("direct-yolo-story-state-missing");if(s?.branch_mode!=="epic")throw new Error("direct-yolo-branch-mode-invalid");if(!Ae(p)||!await L(r,["check-ref-format","--branch",p]))throw new Error("direct-yolo-execution-branch-invalid");if(!Ae(f)||!await L(r,["check-ref-format","--branch",f]))throw new Error("direct-yolo-origin-branch-invalid");if(!/^[a-f0-9]{64}$/.test(R))throw new Error("direct-yolo-graph-revision-invalid");const I=await qe({projectRoot:r,storyId:t,graphRevision:R,executionBranch:p,childPaths:k});return{projectRoot:r,storyId:t,story:d,epicId:a,executionBranch:p,originBranch:f,graphRevision:R,authorizedWriteSet:k,rootMemoryEffect:I}}async function K(e,t){const r=await ve(e,t);if(await l(r.projectRoot,["symbolic-ref","--quiet","--short","HEAD"])!==r.executionBranch)throw new Error("direct-yolo-current-branch-mismatch");return r}async function Se(e){const t=e.nowIso,r=await A(e.projectRoot,["show","--no-patch","--format=%H%n%P%n%B",e.headSha]),o=q(await A(e.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",e.headSha])),i=ze({storyId:e.storyId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundleDigest,graphRevision:e.graphRevision,commitBody:r,changedPaths:o}),n=Pe({gitEvidenceDigest:i,headSha:e.headSha,graphRevision:e.graphRevision,manifestDigest:e.qaExecution.manifestDigest,gateIds:e.qaExecution.gateIds,resultDigest:e.qaExecution.resultDigest}),y=`story-qa:${n}`,h=Object.freeze({schemaVersion:1,kind:"story_qa_evidence",producer:"local-yolo-tdd",evidenceVersion:"p205-execution-v2",storyId:e.storyId,epicId:e.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundleDigest,graphRevision:e.graphRevision,contract:e.qaExecution.contract,command:e.qaExecution.command,manifestDigest:e.qaExecution.manifestDigest,gateIds:e.qaExecution.gateIds,resultDigest:e.qaExecution.resultDigest,sourceEvidenceDigest:n,verdict:"passed",checkedAt:t,receiptRef:y}),d=Q(e.projectRoot,e.storyId,e.headSha);if(d?.verdict!=="approved")throw new Error("direct-yolo-review-artifact-not-approved");const a=D(["root-commit-range-review-v2",e.storyId,e.baseSha,e.headSha,e.bundleDigest,e.graphRevision,y,D(r),[...o].sort().join(","),d.digest].join("\0")),s=`story-review:${a}`,p=Object.freeze({schemaVersion:1,kind:"story_review_evidence",producer:"root-commit-range-review",storyId:e.storyId,epicId:e.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundleDigest,graphRevision:e.graphRevision,sourceEvidenceDigest:a,reviewArtifactDigest:d.digest,qaReceiptRef:y,verdict:"approved",reviewedAt:t,receiptRef:s}),f=[`.neocortex/stories/${e.storyId}/qa-gate-result.json`,`.neocortex/stories/${e.storyId}/validation-evidence.md`,y,s,...e.physicalLockOwnerDigest?[`physical-lock-owner:${e.physicalLockOwnerDigest}`]:[],...e.legacyReceiptRef?[e.legacyReceiptRef]:[]];return Object.freeze({schemaVersion:1,storyId:e.storyId,epicId:e.epicId,branch:e.executionBranch,baseSha:e.baseSha,headSha:e.headSha,commits:Object.freeze([e.headSha]),idempotencyKey:e.idempotencyKey,bundleDigest:e.bundleDigest,graphRevision:e.graphRevision,claimRevision:e.claimRevision,receiptRefs:Object.freeze(f),qaVerdict:"passed",reviewVerdict:"approved",qaReceipt:h,reviewReceipt:p,recordedAt:t,...e.rootMemoryEffect?{rootMemoryEffect:e.rootMemoryEffect}:{}})}async function xe(e){const{projectRoot:t,checkpoint:r,remote:o}=e;let i=!1;return await $(t,n=>{const y=P(n,r.epicId);if(e.expectedLease){const s=m(y.branch_lease);if(!ae(s,e.expectedLease))throw new Error("direct-yolo-runtime-revision-conflict");if(Date.parse(String(s?.expiresAt))<=Date.now())throw new Error("direct-yolo-writer-lease-expired");if(y.graph_revision!==e.expectedGraphRevision||r.graphRevision!==e.expectedGraphRevision)throw new Error("direct-yolo-graph-revision-raced")}const h=me(n,r.storyId),d=m(h.checkpoint);if(d&&d.headSha!==r.headSha){i=!0;return}h.checkpoint=r,h.status="done",h.last_step=Re;const a=Array.isArray(h.steps_completed)?h.steps_completed.filter(s=>typeof s=="string"):[];h.steps_completed=[...new Set([...a,Je,Re])],y.branch_lease=null},{expectedRevision:e.expectedRevision,preCommit:async()=>{if(i)throw new Error("direct-yolo-checkpoint-conflict");if(await l(t,["symbolic-ref","--quiet","--short","HEAD"])!==r.branch||await l(t,["rev-parse","HEAD"])!==r.headSha)throw new Error("direct-yolo-checkpoint-head-raced");if(!await Ie(t,r,r.storyId,r.epicId,r.branch,e.transientAuthority,e.authorizedWriteSet))throw new Error("direct-yolo-checkpoint-physical-invalid");if(e.physicalLockPath&&e.physicalLockOwner&&!await U(e.physicalLockPath,e.physicalLockOwner))throw new Error("direct-yolo-integration-lock-raced");if(o&&!(e.remotePolicy==="ancestor-recovery"?await ke(t,o,r.branch,r.headSha):await De(t,o,r.branch,r.headSha)))throw new Error("direct-yolo-checkpoint-remote-raced")}}),!i}async function ke(e,t,r,o){const i=ee(t),n=(await l(e,["ls-remote","--heads",i,`refs/heads/${r}`])).split(/\s+/)[0];return!!(n&&await L(e,["merge-base","--is-ancestor",o,n]))}function ie(e,t,r){return!!(e?.ownerStoryId===t&&e.sessionId===e.idempotencyKey&&typeof e.idempotencyKey=="string"&&/^setup-[a-f0-9]{64}$/.test(e.idempotencyKey)&&typeof e.expiresAt=="string"&&Date.parse(e.expiresAt)>Date.parse(r))}async function be(e,t){const r=await Fe(e),o=await We(r,"handoffs"),i=`direct-${D(t)}.json`;return{parent:o,name:i,path:te(o,i)}}async function ne(e,t){const r=await be(e,t.storyId);await Ye(r.parent,r.name,`${JSON.stringify(t,null,2)}
2
+ `),await we(r.path,r.parent)}async function M(e,t){try{const r=await be(e,t);await we(r.path,r.parent);const o=JSON.parse(await J(r.path,"utf8")),i=o.state==="issued"?["schemaVersion","kind","state","storyId","fromSessionId","token","tokenDigest","bundleDigest","claimRevision","grantDigest","expiresAt"]:o.state==="consuming"?["schemaVersion","kind","state","storyId","fromSessionId","token","tokenDigest","bundleDigest","claimRevision","grantDigest","expiresAt","consumedBySessionId","consumeStartedAt"]:["schemaVersion","kind","state","storyId","fromSessionId","tokenDigest","bundleDigest","claimRevision","grantDigest","expiresAt","consumedBySessionId","consumedAt"];return Object.keys(o).sort().join("\0")!==[...i].sort().join("\0")||o.schemaVersion!==1||o.kind!=="direct-yolo-setup-handoff-token"||o.state!=="issued"&&o.state!=="consuming"&&o.state!=="consumed"||o.storyId!==t||typeof o.fromSessionId!="string"||!/^setup-[a-f0-9]{64}$/.test(o.fromSessionId)||![o.tokenDigest,o.bundleDigest,o.claimRevision,o.grantDigest].every(n=>typeof n=="string"&&/^[a-f0-9]{64}$/.test(n))||typeof o.expiresAt!="string"||!Number.isFinite(Date.parse(o.expiresAt))||(o.state==="issued"||o.state==="consuming")&&(typeof o.token!="string"||!/^[A-Za-z0-9_-]{32,256}$/.test(o.token))||o.state==="consuming"&&(typeof o.consumedBySessionId!="string"||!/^[a-f0-9]{64}$/.test(o.consumedBySessionId)||typeof o.consumeStartedAt!="string"||!Number.isFinite(Date.parse(o.consumeStartedAt)))||o.state==="consumed"&&(typeof o.consumedBySessionId!="string"||!/^[a-f0-9]{64}$/.test(o.consumedBySessionId)||typeof o.consumedAt!="string"||!Number.isFinite(Date.parse(o.consumedAt)))?void 0:o}catch{return}}async function Ze(e,t,r,o,i){const n=await M(e,t);if(!(!n||n.state==="consumed"||!n.token||n.bundleDigest!==r||n.claimRevision!==o||Date.parse(n.expiresAt)<=Date.parse(i)||D(n.token)!==n.tokenDigest))return{sessionId:n.fromSessionId,token:n.token}}async function Qe(e,t,r,o,i,n){const y=await M(e,t);if(!y||y.state==="consumed"||y.fromSessionId!==r||y.token!==o||y.tokenDigest!==D(o))throw new Error("direct-yolo-setup-handoff-consume-invalid");if(y.state==="consuming"){if(y.consumedBySessionId!==i)throw new Error("direct-yolo-setup-handoff-consume-raced");return}await ne(e,{...y,state:"consuming",consumedBySessionId:i,consumeStartedAt:n})}async function Ue(e,t,r,o,i,n,y,h,d){const a=await M(e,r);if(a?.state==="consumed"&&a.fromSessionId===o&&a.consumedBySessionId===h)return;const s=await C(e,{required:!0}),p=m(s.epics[t]?.branch_lease),f=m(p?.handoffConsumption);if(!a||a.state!=="consuming"||a.fromSessionId!==o||a.token!==i||a.tokenDigest!==D(i)||a.bundleDigest!==n||a.claimRevision!==y||a.consumedBySessionId!==h||p?.ownerStoryId!==r||p.sessionId!==h||f?.kind!=="direct-yolo-setup-handoff-consumption"||f.state!=="consumed"||f.fromSessionId!==o||f.tokenDigest!==a.tokenDigest||f.bundleDigest!==n||f.claimRevision!==y||f.consumedBySessionId!==h)throw new Error("direct-yolo-setup-handoff-consume-invalid");try{await ne(e,{schemaVersion:1,kind:a.kind,state:"consumed",storyId:r,fromSessionId:o,tokenDigest:a.tokenDigest,bundleDigest:a.bundleDigest,claimRevision:a.claimRevision,grantDigest:a.grantDigest,expiresAt:a.expiresAt,consumedBySessionId:h,consumedAt:d})}catch{throw new Error("direct-yolo-setup-handoff-consume-persist-failed")}}function Xe(e){const t=m(e.current?.handoffGrant),r=e.handoff?.token,o=typeof r=="string"&&/^[A-Za-z0-9_-]{32,256}$/.test(r)?D(r):void 0;return!!(t&&o&&e.handoff&&e.handoff.sessionId===e.current?.sessionId&&t.schemaVersion===1&&t.kind==="direct-yolo-setup-handoff"&&t.storyId===e.storyId&&t.fromSessionId===e.current?.sessionId&&t.bundleDigest===e.bundleDigest&&t.claimRevision===e.claimRevision&&typeof t.expiresAt=="string"&&Date.parse(t.expiresAt)>Date.parse(e.nowIso)&&typeof t.tokenDigest=="string"&&/^[a-f0-9]{64}$/.test(t.tokenDigest)&&et(t.tokenDigest,o))}function et(e,t){const r=Buffer.from(e,"hex"),o=Buffer.from(t,"hex");return r.length===32&&o.length===32&&He(r,o)}function ae(e,t){return!!(e&&["schemaVersion","ownerStoryId","sessionId","idempotencyKey","acquiredAt","expiresAt"].every(r=>e[r]===t[r]))}async function ce(e,t,r){await $(e,o=>{const i=P(o,t),n=m(i.branch_lease);ae(n,r)&&(i.branch_lease=null)})}async function tt(e,t){const r=await C(e.projectRoot,{required:!0}),o=m(r.epics[e.epicId]?.branch_lease);if(!o||o.ownerStoryId!==t||!je(o.sessionId)||!je(o.idempotencyKey)||!Number.isFinite(Date.parse(String(o.acquiredAt)))||!Number.isFinite(Date.parse(String(o.expiresAt))))return;const i=await W(e.projectRoot,{kind:"direct",storyId:t,sessionId:String(o.sessionId),idempotencyKey:String(o.idempotencyKey),createdAt:String(o.acquiredAt),expiresAt:String(o.expiresAt),persistent:!0});if(!i.ok)return;await G(i.path,i.owner)&&await ce(e.projectRoot,e.epicId,o)}async function se(e,t,r,o){const i=await Ge(t,{headSha:r,graphRevision:o,nowIso:e.nowIso});await e.qaRunner?.({projectRoot:t,storyId:e.storyId,headSha:r});const n=Me(i);if(!n)throw new Error("p205-transient-authority-invalid");return{contract:"P205-CI-02",command:Ve,manifestDigest:n.manifestDigest,gateIds:n.gateIds,resultDigest:n.resultDigest,transientAuthority:i}}async function de(e,t,r,o){return await l(e,["rev-parse","HEAD"])!==r||await l(e,["symbolic-ref","--quiet","--short","HEAD"])!==t||!await L(e,["diff","--cached","--quiet"])?!1:L(e,["diff","--quiet","HEAD","--",...o])}async function De(e,t,r,o){const i=ee(t);return(await l(e,["ls-remote","--heads",i,`refs/heads/${r}`])).split(/\s+/)[0]===o}function V(e,t,r,o){if(e.length===0||e.some(n=>!fe(n)))return{ok:!1,reasonCode:"direct-yolo-write-set-invalid"};const i=[".neocortex/state.json",`docs/stories/${r}.story.md`,`.neocortex/stories/${r}/qa-gate-result.json`,`.neocortex/stories/${r}/validation-evidence.md`,`.neocortex/stories/${r}/review.md`];return!i.every(n=>e.includes(n))||!i.every(n=>t.includes(n))?{ok:!1,reasonCode:"direct-yolo-write-set-invalid"}:o&&(o.storyId!==r||o.childClaimRevision!==D([...t].sort().join("\0")))?{ok:!1,reasonCode:"direct-yolo-root-memory-claim-mismatch"}:e.some(n=>!t.includes(n)&&!o?.files.some(y=>y.path===n))?{ok:!1,reasonCode:"direct-yolo-write-set-unauthorized"}:{ok:!0}}function fe(e){return e.length>0&&e.length<=1024&&!e.startsWith("/")&&!e.includes("\\")&&!e.split("/").includes("..")&&!e.startsWith(".git/")&&!e.includes("\0")}function je(e){return typeof e=="string"&&e.length>0&&e.length<=512&&/^[A-Za-z0-9._:@/+\-=]+$/.test(e)}function Ae(e){return e.length>0&&e.length<=240&&!e.startsWith("-")&&!/[\s~^:?*[\\]/.test(e)&&!e.includes("..")}function ee(e){if(!/^[A-Za-z0-9._-]{1,128}$/.test(e))throw new Error("direct-yolo-remote-invalid");return e}function F(e,t){const r=`${t}: `,o=e.split(`
3
+ `).map(i=>i.trim()).filter(i=>i.startsWith(r)).map(i=>i.slice(r.length));return o.length===1?o[0]:void 0}function D(e){return Le("sha256").update(e).digest("hex")}function q(e){return e.split("\0").filter(Boolean)}function N(e){return e&&Number.isFinite(Date.parse(e))?new Date(Date.parse(e)).toISOString():new Date().toISOString()}function m(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function he(e,t,r){const o=m(e);if(!(!o||o.schemaVersion!==1||o.originBranch!==r||o.executionBranch!==t||o.capturedFromCurrentCheckout!==!0||typeof o.originHeadSha!="string"||!/^[a-f0-9]{40,64}$/.test(o.originHeadSha)||typeof o.capturedAt!="string"||!Number.isFinite(Date.parse(o.capturedAt))))return o}function ue(e,t,r,o){return Object.freeze({schemaVersion:1,kind:"direct-yolo-setup-receipt",storyId:e.storyId,epicId:e.epicId,executionBranch:e.executionBranch,originBranch:e.originBranch,originHeadSha:t.originHeadSha,leaseExpiresAt:r,reused:o,publicSafe:!0})}async function T(e){const t=q(await A(e,["ls-files","--others","--exclude-standard","-z"])).sort(),r=await Promise.all(t.map(async o=>{if(!fe(o))throw new Error("direct-yolo-checkout-payload-invalid");return`${o}\0${await l(e,["hash-object","--no-filters","--",o])}`}));return D([await A(e,["diff","--cached","--binary","--full-index"]),await A(e,["diff","--binary","--full-index"]),await A(e,["status","--porcelain=v1","-z","--untracked-files=all"]),...r].join("\0"))}async function It(e){const t=Z(e),r=await l(t,["rev-parse","HEAD"]),o=await l(t,["symbolic-ref","--quiet","--short","HEAD"]),i=await T(t);if(await l(t,["rev-parse","HEAD"])!==r||await l(t,["symbolic-ref","--quiet","--short","HEAD"])!==o)throw new Error("direct-yolo-checkout-observation-raced");return Object.freeze({headSha:r,branch:o,payloadDigest:i})}async function Ee(e){const t=[];let r;for(const o of(await A(e,["worktree","list","--porcelain"])).split(`
4
+ `))o.startsWith("worktree ")?(r={path:o.slice(9)},t.push(r)):r&&o.startsWith("branch refs/heads/")&&(r.branch=o.slice(18));return t}function Y(e,t){return e instanceof Error&&e.message==="git-lifecycle-runtime-revision-conflict"?"direct-yolo-runtime-revision-conflict":e instanceof Error&&/^direct-yolo-[a-z0-9-]+$/.test(e.message)?e.message:t}function c(e){return{ok:!1,reasonCode:e}}async function l(e,t){return String((await oe("git",[...t],{cwd:e,encoding:"utf8",maxBuffer:32*1024*1024})).stdout).trim()}async function A(e,t){return String((await oe("git",[...t],{cwd:e,encoding:"utf8",maxBuffer:32*1024*1024})).stdout)}async function L(e,t){try{return await oe("git",[...t],{cwd:e,maxBuffer:8*1024*1024}),!0}catch{return!1}}export{pt as acceptDirectYoloSetupCheckpoint,gt as beginDirectYoloStoryCommit,It as captureDirectYoloCheckoutEvidence,mt as finalizeDirectYoloStoryCheckpoint,lt as issueDirectYoloSetupLeaseHandoff,yt as prepareDirectYoloSetup,wt as recoverLegacyDirectYoloStoryCheckpoint};