@ornexus/neocortex 4.60.73 → 4.60.75

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 (269) 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.d.ts +27 -0
  22. package/packages/client/dist/cache/encrypted-cache.js +1 -108
  23. package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
  24. package/packages/client/dist/cache/index.js +1 -13
  25. package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
  26. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
  27. package/packages/client/dist/checkpoint/index.js +1 -11
  28. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
  29. package/packages/client/dist/cli.js +5 -358
  30. package/packages/client/dist/commands/activate.js +8 -394
  31. package/packages/client/dist/commands/architecture-answers.js +7 -274
  32. package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
  33. package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
  34. package/packages/client/dist/commands/architecture-root-binding.js +1 -51
  35. package/packages/client/dist/commands/cache-status.js +2 -112
  36. package/packages/client/dist/commands/config.js +1 -88
  37. package/packages/client/dist/commands/doctor.js +2 -635
  38. package/packages/client/dist/commands/invoke.d.ts +38 -1
  39. package/packages/client/dist/commands/invoke.js +143 -7200
  40. package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
  41. package/packages/client/dist/commands/legacy-story-branch.js +1 -96
  42. package/packages/client/dist/commands/legacy-story-pr.js +1 -276
  43. package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
  44. package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
  45. package/packages/client/dist/commands/mutation-qa-git.js +1 -41
  46. package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
  47. package/packages/client/dist/commands/mutation-qa-run.js +3 -219
  48. package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
  49. package/packages/client/dist/commands/mutation-qa.js +1 -220
  50. package/packages/client/dist/commands/native-agent.js +2 -136
  51. package/packages/client/dist/commands/planning-diagnosis.js +1 -43
  52. package/packages/client/dist/commands/planning-generation.js +1 -53
  53. package/packages/client/dist/commands/planning-memory.js +1 -40
  54. package/packages/client/dist/commands/planning-research.js +1 -42
  55. package/packages/client/dist/commands/private-session.js +1 -75
  56. package/packages/client/dist/commands/property-qa.js +1 -139
  57. package/packages/client/dist/commands/qa-control.js +1 -16
  58. package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
  59. package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
  60. package/packages/client/dist/commands/qa-scan-capture.js +5 -663
  61. package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
  62. package/packages/client/dist/commands/qa-scan-review.js +5 -826
  63. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
  64. package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
  65. package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
  66. package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
  67. package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
  68. package/packages/client/dist/commands/refactor-characterization.js +21 -671
  69. package/packages/client/dist/commands/refactor-commit.js +13 -399
  70. package/packages/client/dist/commands/refactor-control.js +3 -142
  71. package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
  72. package/packages/client/dist/commands/refactor-review.js +5 -283
  73. package/packages/client/dist/commands/refactor-root.js +7 -588
  74. package/packages/client/dist/commands/refresh-memory.js +3 -156
  75. package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
  76. package/packages/client/dist/commands/story-checkpoint.js +1 -171
  77. package/packages/client/dist/config/host-auth-broker.d.ts +31 -0
  78. package/packages/client/dist/config/host-auth-broker.js +1 -0
  79. package/packages/client/dist/config/host-auth-reference.d.ts +32 -0
  80. package/packages/client/dist/config/host-auth-reference.js +1 -0
  81. package/packages/client/dist/config/profile-directory.js +1 -13
  82. package/packages/client/dist/config/resolver-selection.js +1 -278
  83. package/packages/client/dist/config/secure-config.js +12 -281
  84. package/packages/client/dist/config.js +2 -223
  85. package/packages/client/dist/constants.js +1 -25
  86. package/packages/client/dist/context/context-collector.js +2 -222
  87. package/packages/client/dist/context/context-sanitizer.js +1 -145
  88. package/packages/client/dist/continuity/autonomous-governance.js +1 -285
  89. package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
  90. package/packages/client/dist/continuity/invoke-hooks.js +1 -129
  91. package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
  92. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
  93. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
  94. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
  95. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
  96. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
  97. package/packages/client/dist/continuity/native-agent-store.js +1 -69
  98. package/packages/client/dist/continuity/native-agent-types.d.ts +11 -0
  99. package/packages/client/dist/continuity/native-agent-types.js +1 -90
  100. package/packages/client/dist/continuity/outbox.js +1 -117
  101. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
  102. package/packages/client/dist/continuity/sqlite-store.js +81 -2612
  103. package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
  104. package/packages/client/dist/errors/error-messages.d.ts +3 -0
  105. package/packages/client/dist/errors/error-messages.js +2 -228
  106. package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
  107. package/packages/client/dist/evidence/collector.js +1 -347
  108. package/packages/client/dist/evidence/index.js +1 -1
  109. package/packages/client/dist/evidence/types.js +0 -2
  110. package/packages/client/dist/fs/atomic-state-replace.js +1 -152
  111. package/packages/client/dist/generated/command-registry.generated.js +1 -4076
  112. package/packages/client/dist/generated/public-projections.generated.js +1 -149
  113. package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
  114. package/packages/client/dist/git/direct-yolo-checkpoint.d.ts +11 -1
  115. package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
  116. package/packages/client/dist/git/epic-operational-state.js +2 -672
  117. package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
  118. package/packages/client/dist/git/git-lifecycle-store.d.ts +23 -0
  119. package/packages/client/dist/git/git-lifecycle-store.js +10 -1981
  120. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
  121. package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
  122. package/packages/client/dist/git/legacy-story-pr.js +70 -3538
  123. package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
  124. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
  125. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
  126. package/packages/client/dist/i18n/first-run.js +2 -60
  127. package/packages/client/dist/index.d.ts +2 -0
  128. package/packages/client/dist/index.js +1 -47
  129. package/packages/client/dist/invocation/invoke-input.js +1 -24
  130. package/packages/client/dist/license/host-auth-recovery.d.ts +158 -0
  131. package/packages/client/dist/license/host-auth-recovery.js +1 -0
  132. package/packages/client/dist/license/index.js +1 -5
  133. package/packages/client/dist/license/license-client.d.ts +10 -1
  134. package/packages/client/dist/license/license-client.js +1 -304
  135. package/packages/client/dist/machine/fingerprint.js +2 -163
  136. package/packages/client/dist/machine/index.js +1 -5
  137. package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
  138. package/packages/client/dist/memory/project-memory-writer.js +40 -1007
  139. package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
  140. package/packages/client/dist/migrations/epic-lifecycle-backfill.js +3 -1060
  141. package/packages/client/dist/migrations/project-identity-capability.js +1 -50
  142. package/packages/client/dist/migrations/project-identity.js +7 -493
  143. package/packages/client/dist/migrations/state-json.js +4 -393
  144. package/packages/client/dist/policy/architecture-policy.js +2 -184
  145. package/packages/client/dist/policy/index.js +1 -7
  146. package/packages/client/dist/policy/shared-policy-types.js +0 -38
  147. package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
  148. package/packages/client/dist/private-execution/clean-baseline.js +2 -279
  149. package/packages/client/dist/private-execution/codex-executor.js +4 -574
  150. package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
  151. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
  152. package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
  153. package/packages/client/dist/private-execution/delivery.js +13 -410
  154. package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
  155. package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
  156. package/packages/client/dist/private-execution/implementation-validation.js +2 -106
  157. package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
  158. package/packages/client/dist/private-execution/isolated-session.js +5 -725
  159. package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
  160. package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
  161. package/packages/client/dist/private-execution/pact-test-source.js +1 -258
  162. package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
  163. package/packages/client/dist/private-execution/pact-write-set.js +1 -172
  164. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
  165. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
  166. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
  167. package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
  168. package/packages/client/dist/private-execution/private-report-store.js +1 -42
  169. package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
  170. package/packages/client/dist/private-execution/property-test-choices.js +3 -147
  171. package/packages/client/dist/private-execution/property-test-plan.js +7 -271
  172. package/packages/client/dist/private-execution/property-test-review.js +4 -258
  173. package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
  174. package/packages/client/dist/private-execution/property-test-source.js +1 -139
  175. package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
  176. package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
  177. package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
  178. package/packages/client/dist/private-execution/root-memory-request.js +1 -29
  179. package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
  180. package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
  181. package/packages/client/dist/private-execution/session-lease.js +1 -63
  182. package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
  183. package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
  184. package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
  185. package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
  186. package/packages/client/dist/private-execution/ux-write-set.js +2 -191
  187. package/packages/client/dist/registry/registry-reconciliation.js +1 -234
  188. package/packages/client/dist/resilience/circuit-breaker.js +1 -170
  189. package/packages/client/dist/resilience/degradation-manager.js +1 -164
  190. package/packages/client/dist/resilience/freshness-indicator.js +1 -100
  191. package/packages/client/dist/resilience/index.js +1 -8
  192. package/packages/client/dist/resilience/recovery-detector.js +1 -74
  193. package/packages/client/dist/resolvers/asset-resolver.js +0 -13
  194. package/packages/client/dist/resolvers/local-resolver.js +8 -255
  195. package/packages/client/dist/resolvers/remote-resolver.js +1 -233
  196. package/packages/client/dist/runner/binary.js +1 -404
  197. package/packages/client/dist/runner/cli.js +17 -1571
  198. package/packages/client/dist/runner/epic-background-dispatcher.d.ts +61 -0
  199. package/packages/client/dist/runner/epic-background-dispatcher.js +1 -0
  200. package/packages/client/dist/runner/headless/adapters.js +1 -49
  201. package/packages/client/dist/runner/headless/background-root.d.ts +65 -0
  202. package/packages/client/dist/runner/headless/background-root.js +1 -0
  203. package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
  204. package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
  205. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
  206. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.d.ts +1 -1
  207. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
  208. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.d.ts +2 -0
  209. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +10 -1236
  210. package/packages/client/dist/runner/headless/epic-terminal-git-runner.d.ts +27 -2
  211. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
  212. package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
  213. package/packages/client/dist/runner/headless/managed-environment-cleanup.d.ts +95 -0
  214. package/packages/client/dist/runner/headless/managed-environment-cleanup.js +1 -0
  215. package/packages/client/dist/runner/headless/managed-profile.js +1 -132
  216. package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
  217. package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
  218. package/packages/client/dist/runner/headless/resolver.js +1 -231
  219. package/packages/client/dist/runner/headless/run-yolo.js +1 -885
  220. package/packages/client/dist/runner/headless/run-yoloop.d.ts +1 -0
  221. package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
  222. package/packages/client/dist/runner/headless/types.js +2 -574
  223. package/packages/client/dist/runner/local-console.js +13 -396
  224. package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
  225. package/packages/client/dist/runner/project-identity.js +1 -106
  226. package/packages/client/dist/runner/scheduler.js +7 -995
  227. package/packages/client/dist/runner-cli.js +2 -18
  228. package/packages/client/dist/state/invocation-shape.js +1 -13
  229. package/packages/client/dist/state/project-state-snapshot.d.ts +7 -0
  230. package/packages/client/dist/state/project-state-snapshot.js +1 -1731
  231. package/packages/client/dist/state/state-json-repair.js +3 -785
  232. package/packages/client/dist/state/structural-dag-projection.js +1 -118
  233. package/packages/client/dist/telemetry/index.js +1 -5
  234. package/packages/client/dist/telemetry/offline-queue.js +1 -131
  235. package/packages/client/dist/tier/index.js +1 -5
  236. package/packages/client/dist/tier/tier-aware-client.js +1 -405
  237. package/packages/client/dist/types/index.js +1 -38
  238. package/packages/client/dist/version.js +1 -27
  239. package/packages/client/dist/yolo/change-evidence-collector.d.ts +21 -1
  240. package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
  241. package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
  242. package/packages/client/dist/yolo/spec-envelope-collector.js +5 -184
  243. package/packages/client/dist/yoloop/discovery-hook.js +2 -300
  244. package/packages/client/dist/yoloop/index.js +1 -8
  245. package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
  246. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
  247. package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
  248. package/packages/client/dist/yoloop/target-normalization.js +1 -180
  249. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1920
  250. package/packages/shared/dist/invocation/explicit-intent-recovery.d.ts +83 -0
  251. package/packages/shared/dist/invocation/explicit-intent-recovery.js +187 -0
  252. package/packages/shared/dist/invocation/index.d.ts +7 -0
  253. package/packages/shared/dist/invocation/index.js +22 -0
  254. package/packages/shared/dist/yolo/change-evidence.js +1 -1
  255. package/packages/shared/dist/yoloop/epic-terminal-git.js +144 -2
  256. package/targets-stubs/antigravity/gemini.md +1 -1
  257. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  258. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  259. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  260. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  261. package/targets-stubs/claude-code/neocortex.md +2 -2
  262. package/targets-stubs/codex/AGENTS.md +24 -21
  263. package/targets-stubs/codex/README.md +6 -1
  264. package/targets-stubs/codex/neocortex.toml +7 -2
  265. package/targets-stubs/cursor/agent.md +2 -2
  266. package/targets-stubs/gemini-cli/agent.md +2 -2
  267. package/targets-stubs/opencode/neocortex-root.md +16 -1
  268. package/targets-stubs/opencode/neocortex.md +6 -0
  269. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,21 +1,4 @@
1
- /**
2
- * Branchless preparation sandboxes for continuous yoloop children.
3
- *
4
- * A child receives an independent Git index at a detached HEAD, but no branch
5
- * and no Git worktree are created. Only the root applies the validated result
6
- * and creates the single logical story commit on the epic branch.
7
- */
8
- import { execFile, spawn } from 'node:child_process';
9
- import { createHash, randomBytes } from 'node:crypto';
10
- import { lstat, readFile, realpath, stat } from 'node:fs/promises';
11
- import { basename, dirname, isAbsolute, join, relative, resolve } from 'node:path';
12
- import { promisify } from 'node:util';
13
- import { admitPreparedStoryBundle } from './prepared-story-bundle.js';
14
- import { acquireGitLifecyclePhysicalIntegrationLock, assertGitLifecyclePrivateDirectory, assertGitLifecyclePrivateFile, applyGitLifecycleRuntimeOverlay, computeImmutableStoryQaEvidenceDigest, computeP205StoryQaEvidenceDigest, ensureGitLifecyclePrivateChildDirectory, ensureRuntimeEpic, ensureRuntimeStory, gitLifecycleRuntimeDirectory, mutateGitLifecycleRuntime, P205_COMPLETE_COMMAND, readGitLifecycleRuntime, releaseGitLifecyclePhysicalIntegrationLock, removeGitLifecyclePrivateDirectory, verifyAcceptedGitLifecycleStoryCheckpoint, verifyGitLifecyclePhysicalIntegrationLock, } from '../../git/git-lifecycle-store.js';
15
- import { anchoredAtomicWriteFile, anchoredCreateDirectory, anchoredDirectoryIdentity, anchoredExecuteGit, anchoredEnsureDirectory, anchoredRemoveFile, } from '../../git/secure-filesystem-boundary.js';
16
- import { GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID, GIT_LIFECYCLE_REVIEW_PR_STEP_ID, } from '../../git/git-lifecycle-step-ids.js';
17
- const execFileAsync = promisify(execFile);
18
- const ANCHORED_CHILD_HELPER = String.raw `
1
+ import{execFile as st,spawn as Me}from"node:child_process";import{createHash as G,randomBytes as Ke}from"node:crypto";import{lstat as le,readFile as B,realpath as Y,stat as dt}from"node:fs/promises";import{basename as $,dirname as C,isAbsolute as Fe,join as D,relative as ut,resolve as ht}from"node:path";import{promisify as ft}from"node:util";import{admitPreparedStoryBundle as pt}from"./prepared-story-bundle.js";import{acquireGitLifecyclePhysicalIntegrationLock as lt,assertGitLifecyclePrivateDirectory as W,assertGitLifecyclePrivateFile as F,applyGitLifecycleRuntimeOverlay as re,computeImmutableStoryQaEvidenceDigest as yt,computeP205StoryQaEvidenceDigest as wt,ensureGitLifecyclePrivateChildDirectory as be,ensureRuntimeEpic as ye,ensureRuntimeStory as mt,gitLifecycleRuntimeDirectory as gt,mutateGitLifecycleRuntime as X,P205_COMPLETE_COMMAND as St,readGitLifecycleRuntime as V,releaseGitLifecyclePhysicalIntegrationLock as It,removeGitLifecyclePrivateDirectory as oe,verifyAcceptedGitLifecycleStoryCheckpoint as ke,verifyGitLifecyclePhysicalIntegrationLock as xe}from"../../git/git-lifecycle-store.js";import{anchoredAtomicWriteFile as vt,anchoredCreateDirectory as Ee,anchoredDirectoryIdentity as Rt,anchoredExecuteGit as Ae,anchoredEnsureDirectory as bt,anchoredRemoveFile as kt}from"../../git/secure-filesystem-boundary.js";import{GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID as Ve,GIT_LIFECYCLE_REVIEW_PR_STEP_ID as we}from"../../git/git-lifecycle-step-ids.js";const je=ft(st),xt=String.raw`
19
2
  const fs = require('node:fs');
20
3
  const cp = require('node:child_process');
21
4
  const [expectedParentDev, expectedParentIno, name, expectedChildDev, expectedChildIno, encoded, handshake] = process.argv.slice(1);
@@ -63,1613 +46,13 @@ runtime.on('close', (code, signal) => {
63
46
  if (signal) process.kill(process.pid, signal);
64
47
  else process.exit(Number.isInteger(code) ? code : 1);
65
48
  });
66
- `;
67
- /**
68
- * Create the only command runner authorized for a continuous child. The helper
69
- * owns and revalidates the sandbox cwd before launching the runtime, so the
70
- * mutable public pathname is never reused as the runtime's cwd.
71
- */
72
- export function createAnchoredContinuousStoryCommandRunner(lease, hooks = {}) {
73
- return async (command, args, options = {}) => runAnchoredChildCommand(lease, command, args, options, hooks);
74
- }
75
- /** Default continuous-DAG workspace policy. It never creates a Git worktree. */
76
- export function createBranchlessContinuousStoryWorkspaceManager(options = {}) {
77
- let preparationTail = Promise.resolve();
78
- return {
79
- async prepare(input) {
80
- if ((options.platform ?? process.platform) === 'win32') {
81
- return failure('continuous-sandbox-platform-unsupported');
82
- }
83
- if (!/^[a-f0-9]{64}$/.test(input.dispatchId))
84
- return failure('continuous-sandbox-dispatch-invalid');
85
- if (!safeRelativePath(input.targetRef))
86
- return failure('continuous-sandbox-target-invalid');
87
- if (!safeBranch(input.executionBranch))
88
- return failure('continuous-execution-branch-invalid');
89
- if (!/^[a-f0-9]{64}$/.test(input.graphRevision))
90
- return failure('continuous-graph-revision-invalid');
91
- const authorizedWriteSet = normalizeWriteSet(input.authorizedWriteSet);
92
- if (authorizedWriteSet.length === 0 || authorizedWriteSet.length !== input.authorizedWriteSet.length) {
93
- return failure('continuous-authorized-write-set-invalid');
94
- }
95
- const claimRevision = hashCanonical(authorizedWriteSet);
96
- const previousPreparation = preparationTail;
97
- let unlockPreparation = () => undefined;
98
- preparationTail = new Promise((resolvePreparation) => { unlockPreparation = resolvePreparation; });
99
- await previousPreparation;
100
- let acquiredLeasePath;
101
- let acquiredLeaseOwner;
102
- try {
103
- const projectRoot = await canonicalRoot(input.projectRoot);
104
- const baseSha = await git(projectRoot, ['rev-parse', 'HEAD']);
105
- const graphAuthority = await readCurrentGraphAuthoritySnapshot(projectRoot, input.epicId, input.storyId);
106
- const graphAuthorityRevision = graphAuthority.revision;
107
- const runtimeDirectory = await gitLifecycleRuntimeDirectory(projectRoot);
108
- const leasesRoot = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'leases');
109
- const leasePath = join(leasesRoot, input.dispatchId);
110
- try {
111
- await anchoredCreateDirectory(leasesRoot, input.dispatchId);
112
- await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
113
- }
114
- catch (error) {
115
- if (!isNodeError(error, 'EEXIST'))
116
- throw error;
117
- await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
118
- const owner = await readLeaseOwner(leasePath, leasesRoot);
119
- if (owner !== undefined && processExists(owner.pid))
120
- return failure('continuous-sandbox-lease-active');
121
- if (!owner || !(await removeGitLifecyclePrivateDirectory(leasePath, leasesRoot, async (renamed) => sameLeaseOwner(await readLeaseOwner(renamed, leasesRoot), owner))))
122
- return failure('continuous-sandbox-lease-owner-replaced');
123
- await anchoredCreateDirectory(leasesRoot, input.dispatchId);
124
- await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
125
- }
126
- acquiredLeasePath = leasePath;
127
- acquiredLeaseOwner = Object.freeze({
128
- pid: process.pid,
129
- createdAt: new Date().toISOString(),
130
- nonce: randomBytes(16).toString('hex'),
131
- });
132
- await writeOptional(leasePath, 'owner.json', Buffer.from(JSON.stringify(acquiredLeaseOwner)), options.beforeSandboxWriteCommit);
133
- await assertGitLifecyclePrivateFile(join(leasePath, 'owner.json'), leasePath);
134
- const sandboxesRoot = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'sandboxes');
135
- const workspacePath = join(sandboxesRoot, input.dispatchId.slice(0, 20));
136
- const recovered = await readSandboxMetadata(workspacePath, sandboxesRoot);
137
- let contextSnapshots;
138
- let workspaceIdentity;
139
- const preparedAt = recovered?.preparedAt ?? new Date().toISOString();
140
- const workspaceOwnerNonce = recovered?.workspaceOwnerNonce ?? randomBytes(16).toString('hex');
141
- if (recovered) {
142
- if (recovered.projectRoot !== projectRoot || recovered.storyId !== input.storyId
143
- || recovered.targetRef !== input.targetRef || recovered.dispatchId !== input.dispatchId
144
- || recovered.epicId !== input.epicId || recovered.executionBranch !== input.executionBranch
145
- || recovered.graphRevision !== input.graphRevision || recovered.claimRevision !== claimRevision
146
- || recovered.graphAuthorityRevision !== graphAuthorityRevision
147
- || recovered.graphAuthorityEpoch !== graphAuthority.epoch
148
- || recovered.graphAuthorityStoryStatus !== graphAuthority.storyStatus
149
- || !sameStrings(recovered.authorizedWriteSet, authorizedWriteSet))
150
- return failure('continuous-sandbox-recovery-mismatch');
151
- contextSnapshots = recovered.contextSnapshots.map((snapshot) => ({
152
- path: snapshot.path,
153
- ...(snapshot.contentBase64 !== undefined ? { content: Buffer.from(snapshot.contentBase64, 'base64') } : {}),
154
- }));
155
- workspaceIdentity = await anchoredDirectoryIdentity(workspacePath);
156
- if (workspaceIdentity.dev !== recovered.workspaceIdentity.dev
157
- || workspaceIdentity.ino !== recovered.workspaceIdentity.ino) {
158
- return failure('continuous-sandbox-recovery-mismatch');
159
- }
160
- }
161
- else {
162
- await removeGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
163
- workspaceIdentity = await anchoredCreateDirectory(sandboxesRoot, basename(workspacePath));
164
- await assertGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
165
- await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['init', '--quiet']);
166
- await initializeBranchlessRuntimeProjection(projectRoot, workspacePath);
167
- await copyGitIdentity(projectRoot, sandboxesRoot, basename(workspacePath), workspaceIdentity);
168
- await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['remote', 'add', 'neocortex-root', projectRoot]);
169
- await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['fetch', '--quiet', '--no-tags', 'neocortex-root', baseSha]);
170
- await sandboxGitAt(sandboxesRoot, basename(workspacePath), workspaceIdentity, ['checkout', '--quiet', '--detach', 'FETCH_HEAD']);
171
- contextSnapshots = await copyCurrentContext(projectRoot, workspacePath, input.epicId, input.targetRef, options.beforeSandboxWriteCommit);
172
- await writeSandboxMetadata(workspacePath, sandboxesRoot, {
173
- schemaVersion: 1,
174
- projectRoot,
175
- storyId: input.storyId,
176
- targetRef: input.targetRef,
177
- epicId: input.epicId,
178
- executionBranch: input.executionBranch,
179
- graphRevision: input.graphRevision,
180
- graphAuthorityRevision,
181
- graphAuthorityEpoch: graphAuthority.epoch,
182
- graphAuthorityStoryStatus: graphAuthority.storyStatus,
183
- authorizedWriteSet,
184
- claimRevision,
185
- dispatchId: input.dispatchId,
186
- baseSha,
187
- preparedAt,
188
- workspaceOwnerNonce,
189
- workspaceIdentity,
190
- contextSnapshots: contextSnapshots.map((snapshot) => ({
191
- path: snapshot.path,
192
- ...(snapshot.content !== undefined ? { contentBase64: snapshot.content.toString('base64') } : {}),
193
- })),
194
- }, options.beforeSandboxWriteCommit);
195
- }
196
- acquiredLeasePath = undefined;
197
- return {
198
- ok: true,
199
- value: {
200
- projectRoot,
201
- workspacePath,
202
- workspaceStrategy: 'branchless_sandbox',
203
- storyId: input.storyId,
204
- targetRef: input.targetRef,
205
- epicId: input.epicId,
206
- executionBranch: input.executionBranch,
207
- graphRevision: input.graphRevision,
208
- graphAuthorityRevision,
209
- graphAuthorityEpoch: graphAuthority.epoch,
210
- graphAuthorityStoryStatus: graphAuthority.storyStatus,
211
- authorizedWriteSet,
212
- claimRevision,
213
- baseSha: recovered?.baseSha ?? baseSha,
214
- dispatchId: input.dispatchId,
215
- preparedAt,
216
- leasePath,
217
- leaseOwnerNonce: acquiredLeaseOwner.nonce,
218
- workspaceOwnerNonce,
219
- workspaceIdentity,
220
- contextSnapshots,
221
- },
222
- };
223
- }
224
- catch {
225
- if (acquiredLeasePath && acquiredLeaseOwner) {
226
- const cleanupLeasePath = acquiredLeasePath;
227
- const cleanupLeaseOwner = acquiredLeaseOwner;
228
- await removeGitLifecyclePrivateDirectory(cleanupLeasePath, dirname(cleanupLeasePath), async (renamed) => sameLeaseOwner(await readLeaseOwner(renamed, dirname(cleanupLeasePath)), cleanupLeaseOwner)).catch(() => undefined);
229
- }
230
- return failure('continuous-sandbox-prepare-failed');
231
- }
232
- finally {
233
- unlockPreparation();
234
- }
235
- },
236
- async integrate(lease, authority) {
237
- const leaseOwner = await readLeaseOwner(lease.leasePath, dirname(lease.leasePath)).catch(() => undefined);
238
- const sandboxOwner = await readSandboxMetadata(lease.workspacePath, dirname(lease.workspacePath)).catch(() => undefined);
239
- if (!leaseOwner || leaseOwner.nonce !== lease.leaseOwnerNonce
240
- || sandboxOwner?.workspaceOwnerNonce !== lease.workspaceOwnerNonce
241
- || sandboxOwner.dispatchId !== lease.dispatchId || sandboxOwner.storyId !== lease.storyId) {
242
- return failure('continuous-sandbox-owner-mismatch');
243
- }
244
- const lockStartedAt = normalizeEvidenceTime(authority?.nowIso ?? new Date().toISOString());
245
- const physicalLock = await acquireGitLifecyclePhysicalIntegrationLock(lease.projectRoot, {
246
- kind: 'continuous', storyId: lease.storyId, sessionId: lease.dispatchId,
247
- idempotencyKey: lease.dispatchId,
248
- expiresAt: new Date(Date.parse(lockStartedAt) + 30 * 60 * 1000).toISOString(),
249
- persistent: false, createdAt: lockStartedAt,
250
- });
251
- if (!physicalLock.ok)
252
- return failure(physicalLock.reasonCode === 'git-lifecycle-integration-backpressure'
253
- ? 'continuous-integration-backpressure' : 'continuous-integration-lease-failed');
254
- let rootSnapshots = [];
255
- let rootCommitCreated = false;
256
- let rootEffectsStarted = false;
257
- try {
258
- // Preserve the leading porcelain status column: `sandboxGit` trims it
259
- // and would misclassify an ordinary unstaged modification as staged.
260
- const sandboxStatus = (await sandboxGitRaw(lease, ['status', '--porcelain'])).trimEnd();
261
- const childHeadSha = await sandboxGit(lease, ['rev-parse', 'HEAD']);
262
- const currentBranch = await gitOptional(lease.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
263
- if (currentBranch !== lease.executionBranch)
264
- return failure('continuous-execution-branch-mismatch');
265
- const runtimeDirectory = dirname(dirname(lease.leasePath));
266
- const integratedRoot = await ensureGitLifecyclePrivateChildDirectory(runtimeDirectory, 'integrated');
267
- const markerPath = join(integratedRoot, lease.dispatchId);
268
- const marker = await readMarker(markerPath, integratedRoot);
269
- if (marker?.childHeadSha === childHeadSha
270
- && marker.bundle.storyId === lease.storyId
271
- && marker.bundle.epicId === lease.epicId
272
- && marker.bundle.executionBranch === lease.executionBranch
273
- && marker.bundle.graphRevision === lease.graphRevision
274
- && marker.bundle.claimRevision === lease.claimRevision
275
- && sameStrings(marker.bundle.authorizedWriteSet, lease.authorizedWriteSet)
276
- && marker.checkpoint.idempotencyKey === lease.dispatchId
277
- && marker.checkpoint.bundleId === marker.bundle.bundleId
278
- && marker.checkpoint.bundleDigest === marker.bundle.bundleDigest
279
- && marker.checkpoint.graphRevision === lease.graphRevision
280
- && marker.checkpoint.claimRevision === lease.claimRevision
281
- && await gitExitOk(lease.projectRoot, ['merge-base', '--is-ancestor', marker.rootHeadSha, 'HEAD'])
282
- && await checkpointExistsInRootState(lease, marker.checkpoint)) {
283
- return {
284
- ok: true,
285
- value: {
286
- headSha: marker.rootHeadSha,
287
- alreadyIntegrated: true,
288
- bundle: marker.bundle,
289
- checkpoint: marker.checkpoint,
290
- },
291
- };
292
- }
293
- // The delegated child owns only filesystem writes. Any staged path or
294
- // commit is an attempted authority escalation; the root writer alone
295
- // stages, integrates and creates the single logical story commit.
296
- if (childHeadSha !== lease.baseSha) {
297
- return failure('continuous-sandbox-child-git-authority-denied');
298
- }
299
- if (sandboxStatus.length === 0)
300
- return failure('continuous-bundle-empty');
301
- const childStaged = sandboxStatus.split('\n')
302
- .some((line) => line.length > 0 && line[0] !== ' ' && line[0] !== '?');
303
- if (!childStaged)
304
- await sandboxGit(lease, ['add', '-A']);
305
- const changedPaths = splitNull(await sandboxGitRaw(lease, ['diff', '--cached', '--name-only', '-z', lease.baseSha]));
306
- if (changedPaths.length === 0 || changedPaths.some((path) => !safeRelativePath(path))) {
307
- return failure('continuous-integration-write-set-invalid');
308
- }
309
- if (!(await sandboxGitExitOk(lease, ['merge-base', '--is-ancestor', lease.baseSha, childHeadSha]))) {
310
- return failure('continuous-bundle-base-not-ancestor');
311
- }
312
- if (!(await gitExitOk(lease.projectRoot, ['merge-base', '--is-ancestor', lease.baseSha, 'HEAD']))) {
313
- return failure('continuous-root-base-not-ancestor');
314
- }
315
- const nowIso = authority?.nowIso ?? new Date().toISOString();
316
- const receiptRefs = normalizeReceiptRefs(authority?.receiptRefs, lease.dispatchId);
317
- const payload = await sandboxGitRaw(lease, ['diff', '--cached', '--binary', lease.baseSha]);
318
- const bundleBody = {
319
- schemaVersion: 1,
320
- storyId: lease.storyId,
321
- epicId: lease.epicId,
322
- executionBranch: lease.executionBranch,
323
- baseSha: lease.baseSha,
324
- bundleDigest: createHash('sha256').update(payload).digest('hex'),
325
- graphRevision: lease.graphRevision,
326
- claimRevision: lease.claimRevision,
327
- authorizedWriteSet: lease.authorizedWriteSet,
328
- contextDigests: Object.fromEntries(lease.contextSnapshots.map((snapshot) => [
329
- snapshot.path,
330
- createHash('sha256').update(snapshot.content ?? Buffer.alloc(0)).digest('hex'),
331
- ])),
332
- validationRefs: receiptRefs,
333
- createdAt: lease.preparedAt,
334
- expiresAt: new Date(Date.parse(lease.preparedAt) + 24 * 60 * 60 * 1000).toISOString(),
335
- branchless: true,
336
- };
337
- const bundle = Object.freeze({
338
- ...bundleBody,
339
- bundleId: hashCanonical(bundleBody),
340
- });
341
- const recoveredCommit = await findIntegratedDispatchCommit(lease, bundle);
342
- if (recoveredCommit) {
343
- const existingCheckpoint = await readMatchingRootCheckpoint(lease, bundle, recoveredCommit);
344
- if (existingCheckpoint) {
345
- await writeMarker(markerPath, childHeadSha, recoveredCommit.headSha, bundle, existingCheckpoint, options.beforeSandboxWriteCommit);
346
- return {
347
- ok: true,
348
- value: { headSha: recoveredCommit.headSha, alreadyIntegrated: true, bundle, checkpoint: existingCheckpoint },
349
- };
350
- }
351
- }
352
- if (!recoveredCommit
353
- && await readCurrentGraphAuthorityRevision(lease.projectRoot, lease.epicId) !== lease.graphAuthorityRevision) {
354
- return failure('continuous-graph-revision-stale');
355
- }
356
- if (recoveredCommit) {
357
- const evidence = await produceIndependentCheckpointEvidence({
358
- lease, bundle, baseSha: recoveredCommit.baseSha, headSha: recoveredCommit.headSha,
359
- receiptRefs, nowIso, qaRunner: options.storyQaRunner,
360
- });
361
- if (!evidence.ok)
362
- return evidence;
363
- await options.beforeCheckpointPersist?.({
364
- projectRoot: lease.projectRoot, storyId: lease.storyId, headSha: recoveredCommit.headSha,
365
- });
366
- const checkpoint = await persistRootCheckpoint({
367
- lease,
368
- physicalLock,
369
- checkpointAuthority: recoveredCommit.checkpointAuthority,
370
- bundle,
371
- baseSha: recoveredCommit.baseSha,
372
- headSha: recoveredCommit.headSha,
373
- receiptRefs: [...receiptRefs, `bundle:${bundle.bundleId}`, evidence.value.qaReceipt.receiptRef, evidence.value.reviewReceipt.receiptRef],
374
- qaReceipt: evidence.value.qaReceipt,
375
- reviewReceipt: evidence.value.reviewReceipt,
376
- recordedAt: nowIso,
377
- checkpointNow: options.checkpointNow,
378
- insideCheckpointPreCommit: options.insideCheckpointPreCommit,
379
- afterCheckpointPersist: options.afterCheckpointPersist,
380
- });
381
- if (!checkpoint.ok)
382
- return checkpoint;
383
- await writeMarker(markerPath, childHeadSha, recoveredCommit.headSha, bundle, checkpoint.value, options.beforeSandboxWriteCommit);
384
- return { ok: true, value: { headSha: recoveredCommit.headSha, alreadyIntegrated: true, bundle, checkpoint: checkpoint.value } };
385
- }
386
- // A staged index is accepted only as replay input when immutable root
387
- // evidence above proves that this exact bundle was already integrated.
388
- // It can never authorize a fresh root effect.
389
- if (childStaged)
390
- return failure('continuous-sandbox-child-git-authority-denied');
391
- const stagedPaths = splitNull(await gitRaw(lease.projectRoot, ['diff', '--cached', '--name-only', '-z']));
392
- if (stagedPaths.length > 0)
393
- return failure('continuous-integration-root-index-dirty');
394
- const managedPaths = new Set(lease.contextSnapshots.map((snapshot) => snapshot.path));
395
- const unauthorized = changedPaths.filter((path) => !lease.authorizedWriteSet.some((authorized) => writeSetCovers(authorized, path)));
396
- if (unauthorized.length > 0)
397
- return failure('continuous-bundle-write-set-unauthorized');
398
- const patchPaths = changedPaths.filter((path) => !managedPaths.has(path));
399
- const interveningPaths = new Set(splitNull(await gitRaw(lease.projectRoot, ['diff', '--name-only', '-z', `${lease.baseSha}..HEAD`])));
400
- if (patchPaths.some((path) => interveningPaths.has(path)))
401
- return failure('continuous-bundle-intervening-conflict');
402
- const dirtyPaths = new Set([
403
- ...splitNull(await gitRaw(lease.projectRoot, ['diff', '--name-only', '-z'])),
404
- ...splitNull(await gitRaw(lease.projectRoot, ['ls-files', '--others', '--exclude-standard', '-z'])),
405
- ]);
406
- if (patchPaths.some((path) => dirtyPaths.has(path)))
407
- return failure('continuous-integration-root-conflict');
408
- rootSnapshots = await snapshotPaths(lease.projectRoot, [...new Set([...changedPaths, '.neocortex/state.json'])]);
409
- const writer = await acquireRootWriterLease(lease, nowIso);
410
- if (!writer.ok)
411
- return writer;
412
- const admissionErrors = admitPreparedStoryBundle({
413
- bundle,
414
- payload: Buffer.from(payload),
415
- expected: {
416
- epicId: lease.epicId,
417
- storyId: lease.storyId,
418
- executionBranch: lease.executionBranch,
419
- baseSha: lease.baseSha,
420
- graphRevision: lease.graphRevision,
421
- claimRevision: lease.claimRevision,
422
- authorizedWriteSet: lease.authorizedWriteSet,
423
- nowIso,
424
- },
425
- writerLease: writer.value,
426
- });
427
- if (admissionErrors.length > 0) {
428
- await restoreIntegration(lease.projectRoot, rootSnapshots);
429
- return failure(`continuous-bundle-admission-${admissionErrors[0]}`);
430
- }
431
- const rootBaseSha = await git(lease.projectRoot, ['rev-parse', 'HEAD']);
432
- let checkpointAuthority;
433
- await options.beforeRootCommit?.({
434
- projectRoot: lease.projectRoot,
435
- storyId: lease.storyId,
436
- headSha: rootBaseSha,
437
- });
438
- try {
439
- await mutateGitLifecycleRuntime(lease.projectRoot, (document) => {
440
- const currentWriter = asRecordOrUndefined(ensureRuntimeEpic(document, lease.epicId).branch_lease);
441
- if (currentWriter?.ownerStoryId !== lease.storyId
442
- || currentWriter.sessionId !== lease.dispatchId
443
- || currentWriter.idempotencyKey !== lease.dispatchId
444
- || Date.parse(String(currentWriter.expiresAt)) <= Date.now()) {
445
- throw new Error('continuous-checkpoint-writer-lease-lost');
446
- }
447
- }, { preCommit: async (document) => {
448
- const currentAuthority = await readCurrentGraphAuthoritySnapshot(lease.projectRoot, lease.epicId, lease.storyId, document);
449
- if (currentAuthority.revision !== lease.graphAuthorityRevision
450
- || currentAuthority.epoch !== lease.graphAuthorityEpoch
451
- || currentAuthority.storyStatus !== lease.graphAuthorityStoryStatus) {
452
- throw new Error('continuous-graph-revision-stale');
453
- }
454
- if (!(await verifyGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner))) {
455
- throw new Error('continuous-integration-lock-raced');
456
- }
457
- const guardedBranch = await gitOptional(lease.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
458
- const guardedHead = await git(lease.projectRoot, ['rev-parse', 'HEAD']);
459
- if (guardedBranch !== lease.executionBranch || guardedHead !== rootBaseSha) {
460
- throw new Error('continuous-integration-head-raced');
461
- }
462
- const guardedStaged = splitNull(await gitRaw(lease.projectRoot, ['diff', '--cached', '--name-only', '-z']));
463
- const guardedDirty = new Set([
464
- ...splitNull(await gitRaw(lease.projectRoot, ['diff', '--name-only', '-z'])),
465
- ...splitNull(await gitRaw(lease.projectRoot, ['ls-files', '--others', '--exclude-standard', '-z'])),
466
- ]);
467
- if (guardedStaged.length > 0)
468
- throw new Error('continuous-integration-root-index-dirty');
469
- if (patchPaths.some((path) => guardedDirty.has(path)))
470
- throw new Error('continuous-integration-root-conflict');
471
- rootEffectsStarted = true;
472
- if (patchPaths.length > 0) {
473
- const patch = await sandboxGitRaw(lease, ['diff', '--cached', '--binary', lease.baseSha, '--', ...patchPaths]);
474
- if (patch.length > 0 && !(await gitWithInput(lease.projectRoot, ['apply', '--index', '--3way', '--whitespace=nowarn'], patch)))
475
- throw new Error('continuous-integration-conflict');
476
- }
477
- for (const snapshot of lease.contextSnapshots) {
478
- if (!changedPaths.includes(snapshot.path))
479
- continue;
480
- const current = await readOptional(join(lease.projectRoot, snapshot.path));
481
- const child = await sandboxGitIndexBlob(lease, snapshot.path);
482
- const merged = snapshot.path === '.neocortex/state.json'
483
- ? mergeJsonBuffers(snapshot.content, current, filterChildGitState(snapshot.content, child, lease.storyId))
484
- : mergeBuffers(snapshot.content, current, child);
485
- if (!merged.ok)
486
- throw new Error(snapshot.path === '.neocortex/state.json'
487
- ? 'continuous-state-merge-conflict'
488
- : 'continuous-context-merge-conflict');
489
- await writeOptional(lease.projectRoot, snapshot.path, merged.value);
490
- await git(lease.projectRoot, ['add', '-A', '--', snapshot.path]);
491
- }
492
- if (changedPaths.includes('.neocortex/state.json')) {
493
- await git(lease.projectRoot, ['add', '-A', '--', '.neocortex/state.json']);
494
- }
495
- if (await gitExitOk(lease.projectRoot, ['diff', '--cached', '--quiet'])) {
496
- throw new Error('continuous-integration-empty-after-admission');
497
- }
498
- checkpointAuthority = await readCurrentGraphAuthoritySnapshot(lease.projectRoot, lease.epicId, lease.storyId, document);
499
- await git(lease.projectRoot, [
500
- 'commit', '-m', `feat(yoloop): integrate ${lease.storyId}`,
501
- '-m', `Neocortex-Story: ${lease.storyId}`,
502
- '-m', `Neocortex-Epic: ${lease.epicId}`,
503
- '-m', `Neocortex-Execution-Branch: ${lease.executionBranch}`,
504
- '-m', `Neocortex-Prepared-Base: ${lease.baseSha}`,
505
- '-m', `Neocortex-Dispatch: ${lease.dispatchId}`,
506
- '-m', `Neocortex-Bundle: ${bundle.bundleId}`,
507
- '-m', `Neocortex-Bundle-Digest: ${bundle.bundleDigest}`,
508
- '-m', `Neocortex-Graph-Revision: ${lease.graphRevision}`,
509
- '-m', `Neocortex-Claim-Revision: ${lease.claimRevision}`,
510
- '-m', `Neocortex-Checkpoint-Authority: ${checkpointAuthority.revision}`,
511
- '-m', `Neocortex-Checkpoint-Epoch: ${checkpointAuthority.epoch ?? 'null'}`,
512
- '-m', `Neocortex-Checkpoint-Story-Status: ${checkpointAuthority.storyStatus ?? 'null'}`,
513
- ]);
514
- rootCommitCreated = true;
515
- } });
516
- }
517
- catch (error) {
518
- if (rootEffectsStarted && !rootCommitCreated)
519
- await restoreIntegration(lease.projectRoot, rootSnapshots);
520
- const reasonCode = error instanceof Error && /^continuous-/.test(error.message)
521
- ? error.message
522
- : 'continuous-integration-failed';
523
- return failure(reasonCode);
524
- }
525
- const rootHeadSha = await git(lease.projectRoot, ['rev-parse', 'HEAD']);
526
- if (!checkpointAuthority)
527
- return failure('continuous-checkpoint-authority-missing');
528
- await options.afterRootCommit?.({
529
- projectRoot: lease.projectRoot, storyId: lease.storyId, headSha: rootHeadSha,
530
- });
531
- const evidence = await produceIndependentCheckpointEvidence({
532
- lease, bundle, baseSha: rootBaseSha, headSha: rootHeadSha,
533
- receiptRefs, nowIso, qaRunner: options.storyQaRunner,
534
- });
535
- if (!evidence.ok)
536
- return evidence;
537
- await options.beforeCheckpointPersist?.({
538
- projectRoot: lease.projectRoot, storyId: lease.storyId, headSha: rootHeadSha,
539
- });
540
- const checkpoint = await persistRootCheckpoint({
541
- lease,
542
- physicalLock,
543
- checkpointAuthority,
544
- bundle,
545
- baseSha: rootBaseSha,
546
- headSha: rootHeadSha,
547
- receiptRefs: [...receiptRefs, `bundle:${bundle.bundleId}`, evidence.value.qaReceipt.receiptRef, evidence.value.reviewReceipt.receiptRef],
548
- qaReceipt: evidence.value.qaReceipt,
549
- reviewReceipt: evidence.value.reviewReceipt,
550
- recordedAt: nowIso,
551
- checkpointNow: options.checkpointNow,
552
- insideCheckpointPreCommit: options.insideCheckpointPreCommit,
553
- afterCheckpointPersist: options.afterCheckpointPersist,
554
- });
555
- if (!checkpoint.ok)
556
- return checkpoint;
557
- await writeMarker(markerPath, childHeadSha, rootHeadSha, bundle, checkpoint.value, options.beforeSandboxWriteCommit);
558
- return { ok: true, value: { headSha: rootHeadSha, alreadyIntegrated: false, bundle, checkpoint: checkpoint.value } };
559
- }
560
- catch {
561
- if (rootEffectsStarted && !rootCommitCreated && rootSnapshots.length > 0) {
562
- await restoreIntegration(lease.projectRoot, rootSnapshots);
563
- }
564
- return failure('continuous-integration-failed');
565
- }
566
- finally {
567
- await releaseRootWriterLease(lease).catch(() => undefined);
568
- await releaseGitLifecyclePhysicalIntegrationLock(physicalLock.path, physicalLock.owner).catch(() => undefined);
569
- }
570
- },
571
- async release(lease, preserveForRecovery) {
572
- if (!preserveForRecovery) {
573
- await removeGitLifecyclePrivateDirectory(lease.workspacePath, dirname(lease.workspacePath), async (renamed) => {
574
- const metadata = await readSandboxMetadata(renamed, dirname(lease.workspacePath)).catch(() => undefined);
575
- return metadata?.workspaceOwnerNonce === lease.workspaceOwnerNonce
576
- && metadata.dispatchId === lease.dispatchId && metadata.storyId === lease.storyId;
577
- });
578
- }
579
- await removeGitLifecyclePrivateDirectory(lease.leasePath, dirname(lease.leasePath), async (renamed) => {
580
- const owner = await readLeaseOwner(renamed, dirname(lease.leasePath)).catch(() => undefined);
581
- return owner?.nonce === lease.leaseOwnerNonce;
582
- });
583
- },
584
- };
585
- }
586
- async function copyCurrentContext(projectRoot, workspacePath, epicId, targetRef, beforeCommit) {
587
- const paths = [...new Set(['.neocortex/state.json', targetRef, `docs/epics/epic-${safeRef(epicId)}.md`])];
588
- const snapshots = [];
589
- for (const path of paths) {
590
- if (!safeRelativePath(path))
591
- continue;
592
- const content = await readOptional(join(projectRoot, path));
593
- snapshots.push({ path, ...(content !== undefined ? { content } : {}) });
594
- if (content !== undefined)
595
- await writeOptional(workspacePath, path, content, beforeCommit);
596
- }
597
- return snapshots;
598
- }
599
- async function canonicalRoot(projectRoot) {
600
- const root = await git(projectRoot, ['rev-parse', '--show-toplevel']);
601
- const [canonicalGitRoot, canonicalInputRoot] = await Promise.all([realpath(root), realpath(projectRoot)]);
602
- if (canonicalGitRoot !== canonicalInputRoot)
603
- throw new Error('project root mismatch');
604
- return canonicalGitRoot;
605
- }
606
- async function copyGitIdentity(projectRoot, workspaceParent, workspaceName, workspaceIdentity) {
607
- for (const key of ['user.name', 'user.email']) {
608
- const value = await gitOptional(projectRoot, ['config', '--get', key]);
609
- if (value)
610
- await sandboxGitAt(workspaceParent, workspaceName, workspaceIdentity, ['config', key, value]);
611
- }
612
- }
613
- async function initializeBranchlessRuntimeProjection(projectRoot, workspacePath) {
614
- const rootRuntime = await readGitLifecycleRuntime(projectRoot);
615
- await mutateGitLifecycleRuntime(workspacePath, (document) => {
616
- for (const [epicId, epic] of Object.entries(rootRuntime.epics)) {
617
- document.epics[epicId] = {
618
- ...structuredClone(epic),
619
- branch_lease: null,
620
- };
621
- }
622
- for (const [storyId, story] of Object.entries(rootRuntime.stories)) {
623
- document.stories[storyId] = structuredClone(story);
624
- }
625
- });
626
- }
627
- async function sandboxGitAt(workspaceParent, workspaceName, workspaceIdentity, args) {
628
- return (await anchoredExecuteGit(workspaceParent, workspaceName, workspaceIdentity, args)).toString('utf8').trim();
629
- }
630
- async function sandboxGitRaw(lease, args) {
631
- return (await anchoredExecuteGit(dirname(lease.workspacePath), basename(lease.workspacePath), lease.workspaceIdentity, args)).toString('utf8');
632
- }
633
- async function sandboxGit(lease, args) {
634
- return (await sandboxGitRaw(lease, args)).trim();
635
- }
636
- async function sandboxGitExitOk(lease, args) {
637
- try {
638
- await sandboxGit(lease, args);
639
- return true;
640
- }
641
- catch {
642
- return false;
643
- }
644
- }
645
- async function sandboxGitIndexBlob(lease, path) {
646
- try {
647
- return await anchoredExecuteGit(dirname(lease.workspacePath), basename(lease.workspacePath), lease.workspaceIdentity, ['show', `:${path}`]);
648
- }
649
- catch {
650
- return undefined;
651
- }
652
- }
653
- async function runAnchoredChildCommand(lease, command, args, options, hooks) {
654
- const startedAt = Date.now();
655
- const empty = (overrides) => ({
656
- exitCode: null, timedOut: false, durationMs: Date.now() - startedAt,
657
- stdout: '', stderr: '', stdoutBytes: 0, stderrBytes: 0, ...overrides,
658
- });
659
- if (options.signal?.aborted)
660
- return empty({ signal: 'SIGTERM', cancelled: true });
661
- if (!command || command.length > 4096 || command.includes('\0') || args.length > 512
662
- || args.some((arg) => arg.length > 32768 || arg.includes('\0'))) {
663
- return empty({ exitCode: 73, stderr: 'continuous-child-invocation-invalid', stderrBytes: 35 });
664
- }
665
- const parentPath = dirname(lease.workspacePath);
666
- const parentEntry = await lstat(parentPath, { bigint: true });
667
- const parentIdentity = await stat(parentPath, { bigint: true });
668
- if (!parentEntry.isDirectory() || parentEntry.isSymbolicLink() || !parentIdentity.isDirectory()
669
- || parentEntry.dev !== parentIdentity.dev || parentEntry.ino !== parentIdentity.ino) {
670
- return empty({ exitCode: 73, stderr: 'continuous-child-parent-invalid', stderrBytes: 31 });
671
- }
672
- await hooks.beforeHandoff?.();
673
- const encoded = Buffer.from(JSON.stringify({ command, args: [...args] })).toString('base64url');
674
- const maxOutputBytes = options.maxOutputBytes ?? 64_000;
675
- const timeoutMs = Math.max(1, Math.min(options.timeoutMs ?? 10 * 60 * 1000, 30 * 60 * 1000));
676
- return await new Promise((resolveCommand) => {
677
- const child = spawn(process.execPath, [
678
- '-e', ANCHORED_CHILD_HELPER,
679
- String(parentIdentity.dev), String(parentIdentity.ino), basename(lease.workspacePath),
680
- lease.workspaceIdentity.dev, lease.workspaceIdentity.ino, encoded, hooks.afterHandoff ? '1' : '0',
681
- ], { cwd: parentPath, env: options.env, stdio: ['pipe', 'pipe', 'pipe'] });
682
- let stdout = '';
683
- let stderr = '';
684
- let stdoutBytes = 0;
685
- let stderrBytes = 0;
686
- let settled = false;
687
- let timedOut = false;
688
- let cancelled = false;
689
- let handoffStarted = !hooks.afterHandoff;
690
- const finish = (exitCode, signal) => {
691
- if (settled)
692
- return;
693
- settled = true;
694
- clearTimeout(timer);
695
- options.signal?.removeEventListener('abort', abort);
696
- resolveCommand({
697
- exitCode, ...(signal ? { signal } : {}), timedOut, ...(cancelled ? { cancelled: true } : {}),
698
- durationMs: Date.now() - startedAt, stdout, stderr, stdoutBytes, stderrBytes,
699
- });
700
- };
701
- const abort = () => { cancelled = true; child.kill('SIGTERM'); };
702
- options.signal?.addEventListener('abort', abort, { once: true });
703
- const timer = setTimeout(() => { timedOut = true; child.kill('SIGTERM'); }, timeoutMs);
704
- child.stdout.on('data', (chunk) => {
705
- stdoutBytes += chunk.length;
706
- if (stdoutBytes + stderrBytes > maxOutputBytes)
707
- child.kill('SIGTERM');
708
- else
709
- stdout += chunk.toString('utf8');
710
- });
711
- child.stderr.on('data', (chunk) => {
712
- stderrBytes += chunk.length;
713
- if (stdoutBytes + stderrBytes > maxOutputBytes)
714
- child.kill('SIGTERM');
715
- else
716
- stderr += chunk.toString('utf8');
717
- if (!handoffStarted && stderr.includes('continuous-child-handoff-ready\n')) {
718
- handoffStarted = true;
719
- Promise.resolve(hooks.afterHandoff?.())
720
- .then(() => child.stdin.end())
721
- .catch(() => child.kill('SIGTERM'));
722
- }
723
- });
724
- child.once('error', () => finish(null));
725
- child.once('close', (code, signal) => finish(code, signal));
726
- if (!hooks.afterHandoff)
727
- child.stdin.end();
728
- });
729
- }
730
- async function git(cwd, args) {
731
- return (await gitRaw(cwd, args)).trim();
732
- }
733
- async function gitRaw(cwd, args) {
734
- const result = await execFileAsync('git', args, { cwd, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 });
735
- return String(result.stdout);
736
- }
737
- async function gitOptional(cwd, args) {
738
- try {
739
- return await git(cwd, args);
740
- }
741
- catch (error) {
742
- if (isNodeError(error, 'ENOENT'))
743
- return undefined;
744
- throw error;
745
- }
746
- }
747
- async function gitExitOk(cwd, args) {
748
- try {
749
- await git(cwd, args);
750
- return true;
751
- }
752
- catch {
753
- return false;
754
- }
755
- }
756
- async function gitWithInput(cwd, args, input) {
757
- return await new Promise((resolveProcess) => {
758
- const child = spawn('git', [...args], { cwd, stdio: ['pipe', 'ignore', 'ignore'] });
759
- child.once('error', () => resolveProcess(false));
760
- child.once('close', (code) => resolveProcess(code === 0));
761
- child.stdin.end(input);
762
- });
763
- }
764
- async function gitBlob(cwd, revision, path) {
765
- try {
766
- const result = await execFileAsync('git', ['show', `${revision}:${path}`], { cwd, encoding: 'buffer', maxBuffer: 16 * 1024 * 1024 });
767
- return Buffer.from(result.stdout);
768
- }
769
- catch (error) {
770
- if (isNodeError(error, 'ENOENT'))
771
- return undefined;
772
- throw error;
773
- }
774
- }
775
- async function readOptional(path) {
776
- try {
777
- return await readFile(path);
778
- }
779
- catch (error) {
780
- if (isNodeError(error, 'ENOENT'))
781
- return undefined;
782
- throw error;
783
- }
784
- }
785
- async function writeOptional(boundaryRootInput, relativePathInput, content, beforeCommit) {
786
- const relativePath = normalizeRepositoryPath(relativePathInput);
787
- if (!safeRelativePath(relativePath))
788
- throw new Error('continuous-sandbox-write-path-invalid');
789
- const boundaryRoot = await realpath(boundaryRootInput);
790
- if (boundaryRoot !== resolve(boundaryRootInput))
791
- throw new Error('continuous-sandbox-write-root-symlink');
792
- const parentRelative = dirname(relativePath) === '.' ? '' : dirname(relativePath);
793
- const parentPath = await ensureContainedDirectoryPath(boundaryRoot, parentRelative);
794
- const parentIdentity = await directoryIdentity(parentPath);
795
- const destinationPath = join(parentPath, basename(relativePath));
796
- await assertContainedDestination(destinationPath, boundaryRoot, true);
797
- if (content === undefined) {
798
- await beforeCommit?.({ boundaryRoot, relativePath, destinationPath });
799
- await assertSameDirectoryIdentity(parentPath, boundaryRoot, parentIdentity);
800
- await assertContainedDestination(destinationPath, boundaryRoot, true);
801
- await anchoredRemoveFile(parentPath, basename(relativePath));
802
- return;
803
- }
804
- await beforeCommit?.({ boundaryRoot, relativePath, destinationPath });
805
- await assertSameDirectoryIdentity(parentPath, boundaryRoot, parentIdentity);
806
- await assertContainedDestination(destinationPath, boundaryRoot, true);
807
- await anchoredAtomicWriteFile(parentPath, basename(relativePath), content);
808
- await assertContainedDestination(destinationPath, boundaryRoot, false);
809
- }
810
- async function ensureContainedDirectoryPath(boundaryRoot, relativeDirectory) {
811
- let current = boundaryRoot;
812
- for (const component of relativeDirectory.split('/').filter(Boolean)) {
813
- current = join(current, component);
814
- await anchoredEnsureDirectory(dirname(current), basename(current));
815
- const entry = await lstat(current);
816
- if (!entry.isDirectory() || entry.isSymbolicLink() || await realpath(current) !== current) {
817
- throw new Error('continuous-sandbox-write-component-unsafe');
818
- }
819
- assertPathContained(boundaryRoot, current);
820
- }
821
- return current;
822
- }
823
- async function assertContainedDestination(path, boundaryRoot, allowMissing) {
824
- assertPathContained(boundaryRoot, path);
825
- try {
826
- const entry = await lstat(path);
827
- if (entry.isSymbolicLink() || !entry.isFile())
828
- throw new Error('continuous-sandbox-write-destination-unsafe');
829
- if (await realpath(path) !== path)
830
- throw new Error('continuous-sandbox-write-destination-symlink');
831
- }
832
- catch (error) {
833
- if (allowMissing && isNodeError(error, 'ENOENT'))
834
- return;
835
- throw error;
836
- }
837
- }
838
- function assertPathContained(boundaryRoot, candidate) {
839
- const relation = relative(boundaryRoot, candidate);
840
- if (relation === '' || relation.startsWith('..') || isAbsolute(relation)) {
841
- throw new Error('continuous-sandbox-write-containment-invalid');
842
- }
843
- }
844
- async function directoryIdentity(path) {
845
- const entry = await lstat(path, { bigint: true });
846
- if (!entry.isDirectory() || entry.isSymbolicLink())
847
- throw new Error('continuous-sandbox-write-parent-unsafe');
848
- return { dev: entry.dev, ino: entry.ino };
849
- }
850
- async function sameDirectoryIdentity(path, boundaryRoot, expected) {
851
- try {
852
- if (path !== boundaryRoot)
853
- assertPathContained(boundaryRoot, path);
854
- if (await realpath(path) !== path)
855
- return false;
856
- const current = await directoryIdentity(path);
857
- return current.dev === expected.dev && current.ino === expected.ino;
858
- }
859
- catch {
860
- return false;
861
- }
862
- }
863
- async function assertSameDirectoryIdentity(path, boundaryRoot, expected) {
864
- if (!(await sameDirectoryIdentity(path, boundaryRoot, expected))) {
865
- throw new Error('continuous-sandbox-write-parent-raced');
866
- }
867
- }
868
- async function snapshotPaths(root, paths) {
869
- return await Promise.all(paths.map(async (path) => {
870
- const content = await readOptional(join(root, path));
871
- return { path, ...(content !== undefined ? { content } : {}) };
872
- }));
873
- }
874
- async function restoreIntegration(root, snapshots) {
875
- const paths = snapshots.map((snapshot) => snapshot.path);
876
- if (paths.length > 0)
877
- await gitExitOk(root, ['reset', '--quiet', 'HEAD', '--', ...paths]);
878
- for (const snapshot of snapshots)
879
- await writeOptional(root, snapshot.path, snapshot.content);
880
- }
881
- async function acquireRootWriterLease(lease, nowIso) {
882
- try {
883
- const statePath = join(lease.projectRoot, '.neocortex/state.json');
884
- const tracked = asRecord(JSON.parse((await readFile(statePath)).toString('utf8')));
885
- const legacyEpic = asRecordOrUndefined(asRecordOrUndefined(tracked.epics)?.[lease.epicId]);
886
- const legacyLease = asRecordOrUndefined(legacyEpic?.branch_lease);
887
- const requested = Object.freeze({
888
- schemaVersion: 1,
889
- ownerStoryId: lease.storyId,
890
- sessionId: lease.dispatchId,
891
- idempotencyKey: lease.dispatchId,
892
- acquiredAt: nowIso,
893
- expiresAt: new Date(Date.parse(nowIso) + 10 * 60 * 1000).toISOString(),
894
- });
895
- let blocked = false;
896
- await mutateGitLifecycleRuntime(lease.projectRoot, (document) => {
897
- const epic = ensureRuntimeEpic(document, lease.epicId);
898
- const current = asRecordOrUndefined(epic.branch_lease) ?? legacyLease;
899
- if (current && typeof current.expiresAt === 'string' && current.expiresAt > nowIso
900
- && (current.ownerStoryId !== lease.storyId || current.idempotencyKey !== lease.dispatchId)) {
901
- blocked = true;
902
- return;
903
- }
904
- epic.branch_mode = 'epic';
905
- epic.execution_branch = lease.executionBranch;
906
- epic.branch_lease = requested;
907
- });
908
- if (blocked)
909
- return failure('continuous-epic-checkout-writer-active');
910
- return { ok: true, value: requested };
911
- }
912
- catch {
913
- return failure('continuous-writer-lease-persist-failed');
914
- }
915
- }
916
- async function releaseRootWriterLease(lease) {
917
- await mutateGitLifecycleRuntime(lease.projectRoot, (document) => {
918
- const epic = ensureRuntimeEpic(document, lease.epicId);
919
- const current = asRecordOrUndefined(epic.branch_lease);
920
- if (current?.ownerStoryId === lease.storyId && current.idempotencyKey === lease.dispatchId)
921
- epic.branch_lease = null;
922
- });
923
- }
924
- async function persistRootCheckpoint(input) {
925
- try {
926
- const statePath = join(input.lease.projectRoot, '.neocortex/state.json');
927
- const checkpoint = Object.freeze({
928
- schemaVersion: 1,
929
- storyId: input.lease.storyId,
930
- epicId: input.lease.epicId,
931
- branch: input.lease.executionBranch,
932
- baseSha: input.baseSha,
933
- headSha: input.headSha,
934
- commits: Object.freeze([input.headSha]),
935
- idempotencyKey: input.lease.dispatchId,
936
- dispatchId: input.lease.dispatchId,
937
- bundleId: input.bundle.bundleId,
938
- bundleDigest: input.bundle.bundleDigest,
939
- graphRevision: input.lease.graphRevision,
940
- claimRevision: input.lease.claimRevision,
941
- receiptRefs: Object.freeze([...new Set(input.receiptRefs)]),
942
- qaVerdict: 'passed',
943
- reviewVerdict: 'approved',
944
- qaReceipt: input.qaReceipt,
945
- reviewReceipt: input.reviewReceipt,
946
- recordedAt: input.recordedAt,
947
- });
948
- const tracked = asRecord(JSON.parse((await readFile(statePath)).toString('utf8')));
949
- const trackedStory = asRecordOrUndefined(asRecordOrUndefined(tracked.stories)?.[input.lease.storyId]);
950
- let outcome = 'persisted';
951
- let reused;
952
- let writerAtCas;
953
- let authorityRuntimeAtCas;
954
- let storyAtCasBefore;
955
- let storyAtCasExisted = false;
956
- let epicLeaseAtCasBefore;
957
- const physicalGuard = async (candidate, runtimeDocument, trackedDocument) => {
958
- const currentBranch = await gitOptional(input.lease.projectRoot, ['symbolic-ref', '--quiet', '--short', 'HEAD']);
959
- const currentHead = await git(input.lease.projectRoot, ['rev-parse', 'HEAD']);
960
- if (currentBranch !== input.lease.executionBranch || currentHead !== input.headSha) {
961
- throw new Error('continuous-checkpoint-head-raced');
962
- }
963
- if (candidate.graphRevision !== input.lease.graphRevision
964
- || candidate.claimRevision !== input.lease.claimRevision
965
- || candidate.bundleId !== input.bundle.bundleId
966
- || candidate.bundleDigest !== input.bundle.bundleDigest) {
967
- throw new Error('continuous-checkpoint-graph-raced');
968
- }
969
- const currentTracked = trackedDocument
970
- ?? asRecord(JSON.parse((await readFile(statePath)).toString('utf8')));
971
- const effective = applyGitLifecycleRuntimeOverlay(currentTracked, runtimeDocument ?? await readGitLifecycleRuntime(input.lease.projectRoot));
972
- const currentEpic = asRecordOrUndefined(asRecordOrUndefined(effective.epics)?.[input.lease.epicId]);
973
- const currentStory = asRecordOrUndefined(asRecordOrUndefined(effective.stories)?.[input.lease.storyId]);
974
- const dependencies = Array.isArray(currentStory?.depends_on)
975
- ? currentStory.depends_on.filter((value) => typeof value === 'string')
976
- : [];
977
- const effectiveStories = asRecordOrUndefined(effective.stories);
978
- if (currentEpic?.execution_branch !== input.lease.executionBranch
979
- || dependencies.some((dependencyId) => {
980
- const dependency = asRecordOrUndefined(effectiveStories?.[dependencyId]);
981
- return !dependency || !['done', 'completed', 'merged'].includes(String(dependency.status));
982
- })) {
983
- throw new Error('continuous-checkpoint-dependency-raced');
984
- }
985
- const changedPaths = splitNull(await gitRaw(input.lease.projectRoot, [
986
- 'diff-tree', '--no-commit-id', '--name-only', '-r', '-z', input.headSha,
987
- ]));
988
- if (changedPaths.length === 0
989
- || changedPaths.some((path) => !input.lease.authorizedWriteSet.some((scope) => writeSetCovers(scope, path)))) {
990
- throw new Error('continuous-checkpoint-write-set-raced');
991
- }
992
- if (!(await verifyAcceptedGitLifecycleStoryCheckpoint(input.lease.projectRoot, candidate, input.lease.storyId, input.lease.epicId, input.lease.executionBranch, undefined, input.lease.authorizedWriteSet)))
993
- throw new Error('continuous-checkpoint-receipt-revalidation-failed');
994
- };
995
- const runtimeBefore = await readGitLifecycleRuntime(input.lease.projectRoot, { required: true });
996
- const writerBefore = asRecordOrUndefined(asRecordOrUndefined(runtimeBefore.epics[input.lease.epicId])?.branch_lease);
997
- if (writerBefore?.ownerStoryId !== input.lease.storyId
998
- || writerBefore.idempotencyKey !== input.lease.dispatchId
999
- || writerBefore.sessionId !== input.lease.dispatchId
1000
- || typeof writerBefore.expiresAt !== 'string'
1001
- || Date.parse(writerBefore.expiresAt) <= (input.checkpointNow?.('before-mutation') ?? Date.now())) {
1002
- return failure('continuous-checkpoint-writer-lease-lost');
1003
- }
1004
- if (!(await verifyGitLifecyclePhysicalIntegrationLock(input.physicalLock.path, input.physicalLock.owner))) {
1005
- return failure('continuous-checkpoint-integration-lock-raced');
1006
- }
1007
- const trackedAuthorityBytes = await readFile(statePath);
1008
- const trackedAuthorityDigest = createHash('sha256').update(trackedAuthorityBytes).digest('hex');
1009
- await physicalGuard(checkpoint, runtimeBefore);
1010
- const authorityBefore = currentGraphAuthoritySnapshot(asRecord(JSON.parse(trackedAuthorityBytes.toString('utf8'))), runtimeBefore, input.lease.epicId, input.lease.storyId);
1011
- if (authorityBefore.revision !== input.checkpointAuthority.revision
1012
- || authorityBefore.epoch !== input.checkpointAuthority.epoch
1013
- || authorityBefore.storyStatus !== input.checkpointAuthority.storyStatus) {
1014
- return failure('continuous-graph-revision-stale');
1015
- }
1016
- const persistedMutation = await mutateGitLifecycleRuntime(input.lease.projectRoot, (document) => {
1017
- const epic = ensureRuntimeEpic(document, input.lease.epicId);
1018
- const writer = asRecordOrUndefined(epic.branch_lease);
1019
- writerAtCas = writer === undefined ? undefined : structuredClone(writer);
1020
- authorityRuntimeAtCas = structuredClone(document);
1021
- storyAtCasExisted = document.stories[input.lease.storyId] !== undefined;
1022
- storyAtCasBefore = structuredClone(document.stories[input.lease.storyId] ?? {});
1023
- epicLeaseAtCasBefore = structuredClone(epic.branch_lease);
1024
- const story = ensureRuntimeStory(document, input.lease.storyId);
1025
- const existing = asRecordOrUndefined(story.checkpoint) ?? asRecordOrUndefined(trackedStory?.checkpoint);
1026
- if (existing?.idempotencyKey === input.lease.dispatchId) {
1027
- if (existing.baseSha !== input.baseSha || existing.headSha !== input.headSha
1028
- || existing.bundleId !== input.bundle.bundleId
1029
- || existing.bundleDigest !== input.bundle.bundleDigest
1030
- || existing.graphRevision !== input.lease.graphRevision
1031
- || existing.claimRevision !== input.lease.claimRevision) {
1032
- outcome = 'conflict';
1033
- }
1034
- else {
1035
- outcome = 'reused';
1036
- reused = existing;
1037
- epic.branch_lease = null;
1038
- }
1039
- return;
1040
- }
1041
- if (writer?.ownerStoryId !== input.lease.storyId
1042
- || writer.idempotencyKey !== input.lease.dispatchId
1043
- || writer.sessionId !== input.lease.dispatchId) {
1044
- outcome = 'lease-lost';
1045
- return;
1046
- }
1047
- story.checkpoint = checkpoint;
1048
- story.status = 'done';
1049
- story.last_step = GIT_LIFECYCLE_REVIEW_PR_STEP_ID;
1050
- const steps = Array.isArray(story.steps_completed) ? story.steps_completed.filter((item) => typeof item === 'string') : [];
1051
- story.steps_completed = [...new Set([...steps, GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID, GIT_LIFECYCLE_REVIEW_PR_STEP_ID])];
1052
- epic.branch_lease = null;
1053
- }, {
1054
- expectedRevision: runtimeBefore.revision,
1055
- preCommit: async (document) => {
1056
- if (writerAtCas?.ownerStoryId !== input.lease.storyId
1057
- || writerAtCas.idempotencyKey !== input.lease.dispatchId
1058
- || writerAtCas.sessionId !== input.lease.dispatchId
1059
- || typeof writerAtCas.expiresAt !== 'string'
1060
- || Date.parse(writerAtCas.expiresAt) <= (input.checkpointNow?.('pre-commit') ?? Date.now())) {
1061
- throw new Error('continuous-checkpoint-writer-lease-lost');
1062
- }
1063
- await input.insideCheckpointPreCommit?.({
1064
- projectRoot: input.lease.projectRoot,
1065
- storyId: input.lease.storyId,
1066
- headSha: input.headSha,
1067
- });
1068
- if (!(await verifyGitLifecyclePhysicalIntegrationLock(input.physicalLock.path, input.physicalLock.owner))) {
1069
- throw new Error('continuous-checkpoint-integration-lock-raced');
1070
- }
1071
- await physicalGuard(reused ?? checkpoint, document);
1072
- const finalTrackedBytes = await readFile(statePath);
1073
- if (createHash('sha256').update(finalTrackedBytes).digest('hex') !== trackedAuthorityDigest) {
1074
- throw new Error('continuous-graph-revision-stale');
1075
- }
1076
- if (!authorityRuntimeAtCas)
1077
- throw new Error('continuous-checkpoint-authority-missing');
1078
- const finalTracked = asRecord(JSON.parse(finalTrackedBytes.toString('utf8')));
1079
- const authorityAtCas = currentGraphAuthoritySnapshot(finalTracked, authorityRuntimeAtCas, input.lease.epicId, input.lease.storyId);
1080
- if (authorityAtCas.revision !== input.checkpointAuthority.revision
1081
- || authorityAtCas.epoch !== input.checkpointAuthority.epoch
1082
- || authorityAtCas.storyStatus !== input.checkpointAuthority.storyStatus) {
1083
- throw new Error('continuous-graph-revision-stale');
1084
- }
1085
- if (outcome === 'persisted'
1086
- && !exactPersistedCheckpointProjection(finalTracked, document, input.lease, checkpoint)) {
1087
- throw new Error('continuous-checkpoint-projection-raced');
1088
- }
1089
- },
1090
- });
1091
- // The outcome is assigned inside the serialized mutation callback. TypeScript
1092
- // does not model writes performed by a callback, so re-widen it here.
1093
- const finalOutcome = outcome;
1094
- if (finalOutcome === 'conflict')
1095
- return failure('continuous-checkpoint-idempotency-conflict');
1096
- if (finalOutcome === 'lease-lost')
1097
- return failure('continuous-checkpoint-writer-lease-lost');
1098
- if (finalOutcome === 'reused' && reused) {
1099
- try {
1100
- await physicalGuard(reused);
1101
- return { ok: true, value: reused };
1102
- }
1103
- catch {
1104
- return failure('continuous-checkpoint-reused-evidence-invalid');
1105
- }
1106
- }
1107
- try {
1108
- await input.afterCheckpointPersist?.({
1109
- projectRoot: input.lease.projectRoot,
1110
- storyId: input.lease.storyId,
1111
- headSha: input.headSha,
1112
- });
1113
- const runtimeAfterPersist = await readGitLifecycleRuntime(input.lease.projectRoot, { required: true });
1114
- if (runtimeAfterPersist.revision !== persistedMutation.document.revision) {
1115
- throw new Error('continuous-checkpoint-post-persist-runtime-raced');
1116
- }
1117
- await physicalGuard(checkpoint, runtimeAfterPersist);
1118
- const finalTrackedBytes = await readFile(statePath);
1119
- if (createHash('sha256').update(finalTrackedBytes).digest('hex') !== trackedAuthorityDigest) {
1120
- throw new Error('continuous-checkpoint-post-persist-authority-raced');
1121
- }
1122
- const finalTracked = asRecord(JSON.parse(finalTrackedBytes.toString('utf8')));
1123
- if (!exactPersistedCheckpointProjection(finalTracked, runtimeAfterPersist, input.lease, checkpoint)) {
1124
- throw new Error('continuous-checkpoint-post-persist-projection-raced');
1125
- }
1126
- }
1127
- catch {
1128
- const cleanupTrackedBytes = await readFile(statePath).catch(() => undefined);
1129
- const trackedAuthorityChanged = cleanupTrackedBytes === undefined
1130
- || createHash('sha256').update(cleanupTrackedBytes).digest('hex') !== trackedAuthorityDigest;
1131
- await mutateGitLifecycleRuntime(input.lease.projectRoot, (document) => {
1132
- const epic = asRecordOrUndefined(document.epics[input.lease.epicId]);
1133
- const story = asRecordOrUndefined(document.stories[input.lease.storyId]);
1134
- const cleanupTracked = cleanupTrackedBytes === undefined
1135
- ? undefined
1136
- : asRecord(JSON.parse(cleanupTrackedBytes.toString('utf8')));
1137
- if (!epic || !story || !cleanupTracked
1138
- || !exactPersistedCheckpointProjection(cleanupTracked, document, input.lease, checkpoint)) {
1139
- throw new Error('continuous-checkpoint-cleanup-cas-conflict');
1140
- }
1141
- if (trackedAuthorityChanged) {
1142
- if (storyAtCasExisted)
1143
- restoreRecord(story, storyAtCasBefore ?? {});
1144
- else
1145
- delete document.stories[input.lease.storyId];
1146
- if (epicLeaseAtCasBefore === undefined)
1147
- delete epic.branch_lease;
1148
- else
1149
- epic.branch_lease = structuredClone(epicLeaseAtCasBefore);
1150
- return;
1151
- }
1152
- story.checkpoint = null;
1153
- story.status = 'blocked';
1154
- epic.branch_lease = null;
1155
- }, { expectedRevision: persistedMutation.document.revision }).catch(() => undefined);
1156
- return failure('continuous-checkpoint-post-persist-raced');
1157
- }
1158
- return { ok: true, value: checkpoint };
1159
- }
1160
- catch (error) {
1161
- const reasonCode = error instanceof Error && /^continuous-/.test(error.message)
1162
- ? error.message
1163
- : 'continuous-checkpoint-persist-failed';
1164
- return failure(reasonCode);
1165
- }
1166
- }
1167
- async function produceIndependentCheckpointEvidence(input) {
1168
- try {
1169
- if (await git(input.lease.projectRoot, ['rev-parse', 'HEAD']) !== input.headSha) {
1170
- return failure('continuous-story-evidence-head-raced');
1171
- }
1172
- const manifestRaw = await readFile(join(input.lease.projectRoot, 'config', 'release-gates.v2.json'), 'utf8');
1173
- const manifest = JSON.parse(manifestRaw);
1174
- const gateIds = Array.isArray(manifest.requiredCompleteClasses)
1175
- ? manifest.requiredCompleteClasses.filter((item) => typeof item === 'string' && /^[a-z0-9-]+$/.test(item))
1176
- : [];
1177
- if (manifest.contract !== 'P205-CI-02' || gateIds.length === 0) {
1178
- return failure('continuous-story-qa-manifest-invalid');
1179
- }
1180
- const qaOutput = String((await execFileAsync(process.execPath, ['scripts/test-root.mjs', '--gate', 'complete'], {
1181
- cwd: input.lease.projectRoot,
1182
- encoding: 'utf8',
1183
- maxBuffer: 32 * 1024 * 1024,
1184
- })).stdout);
1185
- await input.qaRunner?.({ projectRoot: input.lease.projectRoot, storyId: input.lease.storyId, headSha: input.headSha });
1186
- if (await git(input.lease.projectRoot, ['rev-parse', 'HEAD']) !== input.headSha) {
1187
- return failure('continuous-story-qa-head-raced');
1188
- }
1189
- const checkedAt = normalizeEvidenceTime(input.nowIso);
1190
- const commitCount = await git(input.lease.projectRoot, ['rev-list', '--count', `${input.baseSha}..${input.headSha}`]);
1191
- const commitBody = await gitRaw(input.lease.projectRoot, ['show', '--no-patch', '--format=%H%n%P%n%B', input.headSha]);
1192
- const changedPaths = splitNull(await gitRaw(input.lease.projectRoot, ['diff', '--name-only', '-z', `${input.baseSha}..${input.headSha}`]));
1193
- const gitEvidenceDigest = computeImmutableStoryQaEvidenceDigest({
1194
- storyId: input.lease.storyId, baseSha: input.baseSha, headSha: input.headSha,
1195
- bundleDigest: input.bundle.bundleDigest, graphRevision: input.lease.graphRevision,
1196
- commitBody, changedPaths,
1197
- });
1198
- const manifestDigest = createHash('sha256').update(manifestRaw).digest('hex');
1199
- const resultDigest = createHash('sha256').update(qaOutput).digest('hex');
1200
- const qaSourceDigest = computeP205StoryQaEvidenceDigest({
1201
- gitEvidenceDigest, headSha: input.headSha, graphRevision: input.lease.graphRevision,
1202
- manifestDigest, gateIds, resultDigest,
1203
- });
1204
- const qaReceiptRef = `story-qa:${qaSourceDigest}`;
1205
- const qaReceipt = Object.freeze({
1206
- schemaVersion: 1, kind: 'story_qa_evidence', producer: 'local-yolo-tdd', evidenceVersion: 'p205-execution-v2',
1207
- storyId: input.lease.storyId, epicId: input.lease.epicId,
1208
- baseSha: input.baseSha, headSha: input.headSha,
1209
- bundleDigest: input.bundle.bundleDigest, graphRevision: input.lease.graphRevision,
1210
- contract: 'P205-CI-02', command: P205_COMPLETE_COMMAND,
1211
- manifestDigest, gateIds: Object.freeze(gateIds), resultDigest,
1212
- sourceEvidenceDigest: qaSourceDigest, verdict: 'passed', checkedAt, receiptRef: qaReceiptRef,
1213
- });
1214
- const trailers = [
1215
- `Neocortex-Story: ${input.lease.storyId}`,
1216
- `Neocortex-Epic: ${input.lease.epicId}`,
1217
- `Neocortex-Bundle-Digest: ${input.bundle.bundleDigest}`,
1218
- `Neocortex-Graph-Revision: ${input.lease.graphRevision}`,
1219
- ];
1220
- if (commitCount !== '1' || !trailers.every((trailer) => commitBody.includes(trailer))
1221
- || changedPaths.length === 0
1222
- || changedPaths.some((path) => !input.lease.authorizedWriteSet.some((authorized) => writeSetCovers(authorized, path)))) {
1223
- return failure('continuous-story-review-evidence-rejected');
1224
- }
1225
- const reviewSourceDigest = createHash('sha256').update([
1226
- 'root-commit-range-review-v1', input.lease.storyId, input.baseSha, input.headSha,
1227
- input.bundle.bundleDigest, input.lease.graphRevision, qaReceiptRef,
1228
- createHash('sha256').update(commitBody).digest('hex'), [...changedPaths].sort().join(','),
1229
- ].join('\0')).digest('hex');
1230
- const reviewReceiptRef = `story-review:${reviewSourceDigest}`;
1231
- const reviewReceipt = Object.freeze({
1232
- schemaVersion: 1, kind: 'story_review_evidence', producer: 'root-commit-range-review',
1233
- storyId: input.lease.storyId, epicId: input.lease.epicId,
1234
- baseSha: input.baseSha, headSha: input.headSha,
1235
- bundleDigest: input.bundle.bundleDigest, graphRevision: input.lease.graphRevision,
1236
- sourceEvidenceDigest: reviewSourceDigest, qaReceiptRef,
1237
- verdict: 'approved', reviewedAt: checkedAt, receiptRef: reviewReceiptRef,
1238
- });
1239
- return { ok: true, value: { qaReceipt, reviewReceipt } };
1240
- }
1241
- catch {
1242
- return failure('continuous-story-evidence-production-failed');
1243
- }
1244
- }
1245
- function normalizeEvidenceTime(value) {
1246
- return Number.isFinite(Date.parse(value)) ? new Date(Date.parse(value)).toISOString() : new Date().toISOString();
1247
- }
1248
- function filterChildGitState(baseContent, childContent, storyId) {
1249
- if (childContent === undefined)
1250
- return undefined;
1251
- try {
1252
- const base = baseContent === undefined ? {} : asRecord(JSON.parse(baseContent.toString('utf8')));
1253
- const untrustedChild = asRecord(JSON.parse(childContent.toString('utf8')));
1254
- const child = structuredClone(base);
1255
- const baseStory = asRecordOrUndefined(asRecordOrUndefined(base.stories)?.[storyId]);
1256
- const untrustedStory = asRecordOrUndefined(asRecordOrUndefined(untrustedChild.stories)?.[storyId]);
1257
- const stories = ensureRecord(child, 'stories');
1258
- const childStory = structuredClone(baseStory ?? {});
1259
- for (const field of [
1260
- 'status', 'last_step', 'steps_completed', 'last_updated', 'blocked_reason',
1261
- 'blocked_at', 'implementation_evidence', 'validation_evidence', 'qa_gate',
1262
- ]) {
1263
- if (untrustedStory && Object.prototype.hasOwnProperty.call(untrustedStory, field)) {
1264
- childStory[field] = structuredClone(untrustedStory[field]);
1265
- }
1266
- }
1267
- stories[storyId] = childStory;
1268
- return Buffer.from(`${JSON.stringify(child, null, 2)}\n`);
1269
- }
1270
- catch {
1271
- return Buffer.from('{invalid-child-state');
1272
- }
1273
- }
1274
- function ensureRecord(parent, key) {
1275
- const current = asRecordOrUndefined(parent[key]);
1276
- if (current)
1277
- return current;
1278
- const created = {};
1279
- parent[key] = created;
1280
- return created;
1281
- }
1282
- function asRecord(value) {
1283
- if (!value || typeof value !== 'object' || Array.isArray(value))
1284
- throw new Error('record expected');
1285
- return value;
1286
- }
1287
- function asRecordOrUndefined(value) {
1288
- return value && typeof value === 'object' && !Array.isArray(value) ? value : undefined;
1289
- }
1290
- function mergeBuffers(base, root, child) {
1291
- if (sameBuffer(child, base) || sameBuffer(root, child))
1292
- return { ok: true, value: root };
1293
- if (sameBuffer(root, base))
1294
- return { ok: true, value: child };
1295
- return failure('continuous-context-merge-conflict');
1296
- }
1297
- function mergeJsonBuffers(base, root, child) {
1298
- try {
1299
- const merged = mergeJsonValue(parseJson(base), parseJson(root), parseJson(child));
1300
- return merged.ok ? { ok: true, value: merged.value === undefined ? undefined : Buffer.from(`${JSON.stringify(merged.value, null, 2)}\n`) } : merged;
1301
- }
1302
- catch {
1303
- return failure('continuous-state-merge-invalid');
1304
- }
1305
- }
1306
- function parseJson(value) {
1307
- return value === undefined ? undefined : JSON.parse(value.toString('utf8'));
1308
- }
1309
- function mergeJsonValue(base, root, child) {
1310
- if (sameJson(child, base) || sameJson(root, child))
1311
- return { ok: true, value: root };
1312
- if (sameJson(root, base))
1313
- return { ok: true, value: child };
1314
- if (isPlainRecord(base) && isPlainRecord(root) && isPlainRecord(child)) {
1315
- const merged = {};
1316
- for (const key of [...new Set([...Object.keys(base), ...Object.keys(root), ...Object.keys(child)])].sort()) {
1317
- const value = mergeJsonValue(base[key], root[key], child[key]);
1318
- if (!value.ok)
1319
- return value;
1320
- if (value.value !== undefined)
1321
- merged[key] = value.value;
1322
- }
1323
- return { ok: true, value: merged };
1324
- }
1325
- if (Array.isArray(base) && Array.isArray(root) && Array.isArray(child) && isJsonPrefix(base, root) && isJsonPrefix(base, child)) {
1326
- const values = [...base, ...root.slice(base.length), ...child.slice(base.length)];
1327
- const seen = new Set();
1328
- return { ok: true, value: values.filter((item) => {
1329
- const key = JSON.stringify(item);
1330
- if (seen.has(key))
1331
- return false;
1332
- seen.add(key);
1333
- return true;
1334
- }) };
1335
- }
1336
- return failure('continuous-state-merge-conflict');
1337
- }
1338
- function isPlainRecord(value) {
1339
- return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
1340
- }
1341
- function isJsonPrefix(prefix, value) {
1342
- return prefix.length <= value.length && prefix.every((item, index) => sameJson(item, value[index]));
1343
- }
1344
- function sameJson(left, right) {
1345
- return JSON.stringify(left) === JSON.stringify(right);
1346
- }
1347
- function sameBuffer(left, right) {
1348
- return left === undefined || right === undefined ? left === right : left.equals(right);
1349
- }
1350
- function splitNull(value) {
1351
- return value.split('\0').filter(Boolean);
1352
- }
1353
- function safeRelativePath(value) {
1354
- const normalized = normalizeRepositoryPath(value);
1355
- return normalized.length > 0 && normalized.length <= 1024 && !isAbsolute(normalized)
1356
- && !/^[A-Za-z]:\//.test(normalized) && !normalized.split('/').includes('..')
1357
- && !normalized.includes('\0') && !normalized.startsWith('/');
1358
- }
1359
- function normalizeRepositoryPath(value) {
1360
- return value.replaceAll('\\', '/').replace(/^\.\//, '').replace(/\/{2,}/g, '/');
1361
- }
1362
- function normalizeWriteSet(values) {
1363
- const normalized = values.map(normalizeRepositoryPath).filter(safeRelativePath);
1364
- return [...new Set(normalized)].sort();
1365
- }
1366
- function writeSetCovers(authorized, changed) {
1367
- const scope = normalizeRepositoryPath(authorized);
1368
- const path = normalizeRepositoryPath(changed);
1369
- return scope === path || scope.endsWith('/') && path.startsWith(scope);
1370
- }
1371
- function safeBranch(value) {
1372
- return value.length > 0 && value.length <= 240 && !value.startsWith('-') && !value.startsWith('/')
1373
- && !value.endsWith('/') && !value.endsWith('.lock') && !value.includes('..') && !value.includes('\\')
1374
- && !value.includes('@{') && !value.includes('//') && /^[A-Za-z0-9._/-]+$/.test(value);
1375
- }
1376
- function sameStrings(left, right) {
1377
- return left.length === right.length && left.every((value, index) => value === right[index]);
1378
- }
1379
- async function readCurrentGraphAuthoritySnapshot(projectRoot, epicId, storyId, runtimeDocument) {
1380
- const tracked = asRecord(JSON.parse(await readFile(join(projectRoot, '.neocortex/state.json'), 'utf8')));
1381
- return currentGraphAuthoritySnapshot(tracked, runtimeDocument ?? await readGitLifecycleRuntime(projectRoot), epicId, storyId);
1382
- }
1383
- function currentGraphAuthoritySnapshot(tracked, runtimeDocument, epicId, storyId) {
1384
- const effective = applyGitLifecycleRuntimeOverlay(tracked, runtimeDocument);
1385
- const epics = asRecordOrUndefined(effective.epics);
1386
- const stories = asRecordOrUndefined(effective.stories);
1387
- const epic = asRecordOrUndefined(epics?.[epicId]) ?? {};
1388
- const authoredStoryIds = (Array.isArray(epic.stories) ? epic.stories : Array.isArray(epic.story_ids) ? epic.story_ids : [])
1389
- .filter((value) => typeof value === 'string');
1390
- const storyIds = authoredStoryIds.length > 0
1391
- ? authoredStoryIds
1392
- : Object.entries(stories ?? {})
1393
- .filter(([storyId, value]) => {
1394
- const story = asRecordOrUndefined(value);
1395
- return story?.epic_id === epicId || storyId.startsWith(`${epicId}.`);
1396
- })
1397
- .map(([storyId]) => storyId)
1398
- .sort();
1399
- const authorityFields = [
1400
- 'status', 'depends_on', 'files_to_modify', 'contracts', 'contract_refs', 'shared_surfaces',
1401
- 'steps_completed', 'last_step', 'branch_name', 'physicalMergeStatus', 'merged', 'checkpoint',
1402
- 'planning', 'attempts', 'retry_count', 'rollback_receipt', 'cancelled_at',
1403
- ];
1404
- const storyAuthority = Object.fromEntries(storyIds.map((storyId) => {
1405
- const story = asRecordOrUndefined(stories?.[storyId]) ?? {};
1406
- return [storyId, Object.fromEntries(authorityFields
1407
- .filter((field) => Object.prototype.hasOwnProperty.call(story, field))
1408
- .map((field) => [field, story[field]]))];
1409
- }));
1410
- return {
1411
- revision: hashCanonical({
1412
- epicId,
1413
- epic: {
1414
- stories: storyIds,
1415
- status: epic.status ?? null,
1416
- branch_mode: epic.branch_mode ?? null,
1417
- execution_branch: epic.execution_branch ?? null,
1418
- graph_revision: epic.graph_revision ?? null,
1419
- depends_on: epic.depends_on ?? null,
1420
- planning: epic.planning ?? null,
1421
- execution_plan: epic.execution_plan ?? null,
1422
- waves: epic.waves ?? null,
1423
- current_wave: epic.current_wave ?? null,
1424
- replan: epic.replan ?? null,
1425
- replan_revision: epic.replan_revision ?? null,
1426
- dependency_graph: epic.dependency_graph ?? null,
1427
- scheduler: epic.scheduler ?? null,
1428
- attempts: epic.attempts ?? null,
1429
- retry_count: epic.retry_count ?? null,
1430
- },
1431
- stories: storyAuthority,
1432
- }),
1433
- epoch: typeof epic.graph_revision === 'string' ? epic.graph_revision : null,
1434
- storyStatus: typeof asRecordOrUndefined(stories?.[storyId])?.status === 'string'
1435
- ? String(asRecordOrUndefined(stories?.[storyId])?.status)
1436
- : null,
1437
- };
1438
- }
1439
- function exactPersistedCheckpointProjection(tracked, runtimeDocument, lease, checkpoint) {
1440
- const effective = applyGitLifecycleRuntimeOverlay(tracked, runtimeDocument);
1441
- const epic = asRecordOrUndefined(asRecordOrUndefined(effective.epics)?.[lease.epicId]);
1442
- const story = asRecordOrUndefined(asRecordOrUndefined(effective.stories)?.[lease.storyId]);
1443
- const steps = Array.isArray(story?.steps_completed)
1444
- ? story.steps_completed.filter((value) => typeof value === 'string')
1445
- : [];
1446
- return Boolean(epic && story
1447
- && epic.branch_lease === null
1448
- && story.status === 'done'
1449
- && story.last_step === GIT_LIFECYCLE_REVIEW_PR_STEP_ID
1450
- && steps.includes(GIT_LIFECYCLE_COMMIT_PUSH_STEP_ID)
1451
- && steps.includes(GIT_LIFECYCLE_REVIEW_PR_STEP_ID)
1452
- && canonicalJson(story.checkpoint) === canonicalJson(checkpoint));
1453
- }
1454
- function restoreRecord(target, previous) {
1455
- for (const key of Object.keys(target))
1456
- delete target[key];
1457
- Object.assign(target, structuredClone(previous));
1458
- }
1459
- async function readCurrentGraphAuthorityRevision(projectRoot, epicId) {
1460
- return (await readCurrentGraphAuthoritySnapshot(projectRoot, epicId, '')).revision;
1461
- }
1462
- function hashCanonical(value) {
1463
- return createHash('sha256').update(canonicalJson(value)).digest('hex');
1464
- }
1465
- function canonicalJson(value) {
1466
- if (value === null || typeof value !== 'object')
1467
- return JSON.stringify(value);
1468
- if (Array.isArray(value))
1469
- return `[${value.map(canonicalJson).join(',')}]`;
1470
- return `{${Object.entries(value).sort(([left], [right]) => left.localeCompare(right)).map(([key, child]) => `${JSON.stringify(key)}:${canonicalJson(child)}`).join(',')}}`;
1471
- }
1472
- function normalizeReceiptRefs(values, dispatchId) {
1473
- const safe = (values ?? []).filter((value) => /^[A-Za-z0-9._/:@#-]{1,200}$/.test(value) && !value.includes('..'));
1474
- return Object.freeze([...new Set(safe.length > 0 ? safe : [`dispatch:${dispatchId}`])].sort());
1475
- }
1476
- function safeRef(value) {
1477
- return value.replace(/[^A-Za-z0-9._-]/g, '-').slice(0, 80);
1478
- }
1479
- function failure(reasonCode) {
1480
- return { ok: false, reasonCode };
1481
- }
1482
- function isNodeError(error, code) {
1483
- return error instanceof Error && 'code' in error && error.code === code;
1484
- }
1485
- async function readLeaseOwner(leasePath, leasesRoot) {
1486
- try {
1487
- await assertGitLifecyclePrivateDirectory(leasePath, leasesRoot);
1488
- const ownerPath = join(leasePath, 'owner.json');
1489
- await assertGitLifecyclePrivateFile(ownerPath, leasePath);
1490
- const parsed = JSON.parse(await readFile(ownerPath, 'utf8'));
1491
- if (!Number.isSafeInteger(parsed.pid) || Number(parsed.pid) <= 0
1492
- || typeof parsed.createdAt !== 'string' || !Number.isFinite(Date.parse(parsed.createdAt))
1493
- || typeof parsed.nonce !== 'string' || !/^[a-f0-9]{32}$/.test(parsed.nonce)) {
1494
- throw new Error('continuous-sandbox-lease-owner-invalid');
1495
- }
1496
- return { pid: Number(parsed.pid), createdAt: parsed.createdAt, nonce: parsed.nonce };
1497
- }
1498
- catch (error) {
1499
- if (isNodeError(error, 'ENOENT'))
1500
- return undefined;
1501
- throw error;
1502
- }
1503
- }
1504
- function sameLeaseOwner(left, right) {
1505
- return left?.pid === right.pid && left.createdAt === right.createdAt && left.nonce === right.nonce;
1506
- }
1507
- function processExists(pid) {
1508
- try {
1509
- process.kill(pid, 0);
1510
- return true;
1511
- }
1512
- catch (error) {
1513
- return isNodeError(error, 'EPERM');
1514
- }
1515
- }
1516
- async function readSandboxMetadata(workspacePath, sandboxesRoot) {
1517
- try {
1518
- await assertGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
1519
- const gitDirectory = join(workspacePath, '.git');
1520
- await assertGitLifecyclePrivateDirectory(gitDirectory, workspacePath);
1521
- const metadataPath = join(gitDirectory, 'neocortex-sandbox.json');
1522
- await assertGitLifecyclePrivateFile(metadataPath, gitDirectory);
1523
- const parsed = JSON.parse(await readFile(metadataPath, 'utf8'));
1524
- if (parsed.schemaVersion !== 1 || typeof parsed.workspaceOwnerNonce !== 'string'
1525
- || !/^[a-f0-9]{32}$/.test(parsed.workspaceOwnerNonce)
1526
- || !/^[a-f0-9]{64}$/.test(parsed.graphAuthorityRevision)
1527
- || !(parsed.graphAuthorityEpoch === null || /^[a-f0-9]{64}$/.test(parsed.graphAuthorityEpoch))
1528
- || !(parsed.graphAuthorityStoryStatus === null
1529
- || typeof parsed.graphAuthorityStoryStatus === 'string' && parsed.graphAuthorityStoryStatus.length <= 80)
1530
- || typeof parsed.workspaceIdentity?.dev !== 'string' || !/^[0-9]+$/.test(parsed.workspaceIdentity.dev)
1531
- || typeof parsed.workspaceIdentity?.ino !== 'string' || !/^[0-9]+$/.test(parsed.workspaceIdentity.ino)) {
1532
- throw new Error('continuous-sandbox-metadata-invalid');
1533
- }
1534
- return parsed;
1535
- }
1536
- catch (error) {
1537
- if (isNodeError(error, 'ENOENT'))
1538
- return undefined;
1539
- throw error;
1540
- }
1541
- }
1542
- async function writeSandboxMetadata(workspacePath, sandboxesRoot, metadata, beforeCommit) {
1543
- await assertGitLifecyclePrivateDirectory(workspacePath, sandboxesRoot);
1544
- const gitDirectory = join(workspacePath, '.git');
1545
- await assertGitLifecyclePrivateDirectory(gitDirectory, workspacePath);
1546
- const metadataPath = join(gitDirectory, 'neocortex-sandbox.json');
1547
- await writeOptional(workspacePath, '.git/neocortex-sandbox.json', Buffer.from(`${JSON.stringify(metadata, null, 2)}\n`), beforeCommit);
1548
- await assertGitLifecyclePrivateFile(metadataPath, gitDirectory);
1549
- }
1550
- async function readMarker(markerPath, integratedRoot) {
1551
- try {
1552
- await assertGitLifecyclePrivateFile(markerPath, integratedRoot);
1553
- const parsed = JSON.parse(await readFile(markerPath, 'utf8'));
1554
- return typeof parsed.childHeadSha === 'string' && typeof parsed.rootHeadSha === 'string'
1555
- && /^[a-f0-9]{40,64}$/.test(parsed.childHeadSha) && /^[a-f0-9]{40,64}$/.test(parsed.rootHeadSha)
1556
- && parsed.bundle?.schemaVersion === 1 && parsed.checkpoint?.schemaVersion === 1
1557
- ? parsed
1558
- : undefined;
1559
- }
1560
- catch (error) {
1561
- if (isNodeError(error, 'ENOENT'))
1562
- return undefined;
1563
- throw error;
1564
- }
1565
- }
1566
- async function checkpointExistsInRootState(lease, checkpoint) {
1567
- try {
1568
- const tracked = asRecord(JSON.parse(await readFile(join(lease.projectRoot, '.neocortex/state.json'), 'utf8')));
1569
- const state = applyGitLifecycleRuntimeOverlay(tracked, await readGitLifecycleRuntime(lease.projectRoot));
1570
- const current = asRecordOrUndefined(asRecordOrUndefined(state.stories)?.[lease.storyId]);
1571
- const persisted = asRecordOrUndefined(current?.checkpoint);
1572
- return persisted?.idempotencyKey === checkpoint.idempotencyKey
1573
- && persisted.headSha === checkpoint.headSha
1574
- && persisted.bundleDigest === checkpoint.bundleDigest
1575
- && asRecordOrUndefined(asRecordOrUndefined(state.epics)?.[lease.epicId])?.branch_lease === null
1576
- && await verifyAcceptedGitLifecycleStoryCheckpoint(lease.projectRoot, persisted, lease.storyId, lease.epicId, lease.executionBranch, undefined, lease.authorizedWriteSet);
1577
- }
1578
- catch {
1579
- return false;
1580
- }
1581
- }
1582
- async function readMatchingRootCheckpoint(lease, bundle, commit) {
1583
- try {
1584
- const tracked = asRecord(JSON.parse(await readFile(join(lease.projectRoot, '.neocortex/state.json'), 'utf8')));
1585
- const state = applyGitLifecycleRuntimeOverlay(tracked, await readGitLifecycleRuntime(lease.projectRoot));
1586
- const story = asRecordOrUndefined(asRecordOrUndefined(state.stories)?.[lease.storyId]);
1587
- const checkpoint = asRecordOrUndefined(story?.checkpoint);
1588
- if (checkpoint?.schemaVersion !== 1
1589
- || checkpoint.storyId !== lease.storyId
1590
- || checkpoint.epicId !== lease.epicId
1591
- || checkpoint.branch !== lease.executionBranch
1592
- || checkpoint.baseSha !== commit.baseSha
1593
- || checkpoint.headSha !== commit.headSha
1594
- || checkpoint.idempotencyKey !== lease.dispatchId
1595
- || checkpoint.dispatchId !== lease.dispatchId
1596
- || checkpoint.bundleId !== bundle.bundleId
1597
- || checkpoint.bundleDigest !== bundle.bundleDigest
1598
- || checkpoint.graphRevision !== lease.graphRevision
1599
- || checkpoint.claimRevision !== lease.claimRevision
1600
- || asRecordOrUndefined(asRecordOrUndefined(state.epics)?.[lease.epicId])?.branch_lease !== null
1601
- || !(await verifyAcceptedGitLifecycleStoryCheckpoint(lease.projectRoot, checkpoint, lease.storyId, lease.epicId, lease.executionBranch, undefined, lease.authorizedWriteSet)))
1602
- return undefined;
1603
- return checkpoint;
1604
- }
1605
- catch {
1606
- return undefined;
1607
- }
1608
- }
1609
- async function findIntegratedDispatchCommit(lease, bundle) {
1610
- const matches = (await gitOptional(lease.projectRoot, [
1611
- 'log', '--format=%H', '--fixed-strings', `--grep=Neocortex-Dispatch: ${lease.dispatchId}`,
1612
- ]))?.split('\n').filter((sha) => /^[a-f0-9]{40,64}$/.test(sha)) ?? [];
1613
- if (matches.length !== 1)
1614
- return undefined;
1615
- const headSha = matches[0];
1616
- if (!(await gitExitOk(lease.projectRoot, ['merge-base', '--is-ancestor', headSha, 'HEAD'])))
1617
- return undefined;
1618
- const message = await git(lease.projectRoot, ['show', '-s', '--format=%B', headSha]);
1619
- const trailers = new Set(message.split('\n').map((line) => line.trim()));
1620
- for (const trailer of [
1621
- `Neocortex-Story: ${lease.storyId}`,
1622
- `Neocortex-Epic: ${lease.epicId}`,
1623
- `Neocortex-Execution-Branch: ${lease.executionBranch}`,
1624
- `Neocortex-Prepared-Base: ${lease.baseSha}`,
1625
- `Neocortex-Dispatch: ${lease.dispatchId}`,
1626
- `Neocortex-Bundle: ${bundle.bundleId}`,
1627
- `Neocortex-Bundle-Digest: ${bundle.bundleDigest}`,
1628
- `Neocortex-Graph-Revision: ${lease.graphRevision}`,
1629
- `Neocortex-Claim-Revision: ${lease.claimRevision}`,
1630
- ])
1631
- if (!trailers.has(trailer))
1632
- return undefined;
1633
- const authorityRevision = readCommitTrailer(message, 'Neocortex-Checkpoint-Authority');
1634
- const authorityEpoch = readCommitTrailer(message, 'Neocortex-Checkpoint-Epoch');
1635
- const authorityStoryStatus = readCommitTrailer(message, 'Neocortex-Checkpoint-Story-Status');
1636
- if (!authorityRevision || !/^[a-f0-9]{64}$/.test(authorityRevision)
1637
- || !authorityEpoch || !(authorityEpoch === 'null' || /^[a-f0-9]{64}$/.test(authorityEpoch))
1638
- || !authorityStoryStatus || authorityStoryStatus.length > 80)
1639
- return undefined;
1640
- const parentSha = await gitOptional(lease.projectRoot, ['rev-parse', `${headSha}^`]);
1641
- if (!parentSha || !/^[a-f0-9]{40,64}$/.test(parentSha))
1642
- return undefined;
1643
- const committedPaths = splitNull(await gitRaw(lease.projectRoot, [
1644
- 'diff-tree', '--no-commit-id', '--name-only', '-r', '-z', headSha,
1645
- ]));
1646
- if (committedPaths.length === 0 || committedPaths.some((path) => !bundle.authorizedWriteSet.some((scope) => writeSetCovers(scope, path))))
1647
- return undefined;
1648
- return {
1649
- baseSha: parentSha,
1650
- headSha,
1651
- checkpointAuthority: {
1652
- revision: authorityRevision,
1653
- epoch: authorityEpoch === 'null' ? null : authorityEpoch,
1654
- storyStatus: authorityStoryStatus === 'null' ? null : authorityStoryStatus,
1655
- },
1656
- };
1657
- }
1658
- function readCommitTrailer(message, name) {
1659
- const prefix = `${name}: `;
1660
- const matches = message.split('\n').map((line) => line.trim()).filter((line) => line.startsWith(prefix));
1661
- return matches.length === 1 ? matches[0].slice(prefix.length) : undefined;
1662
- }
1663
- async function writeMarker(markerPath, childHeadSha, rootHeadSha, bundle, checkpoint, beforeCommit) {
1664
- const integratedRoot = dirname(markerPath);
1665
- await assertGitLifecyclePrivateDirectory(integratedRoot, dirname(integratedRoot));
1666
- try {
1667
- await assertGitLifecyclePrivateFile(markerPath, integratedRoot);
1668
- }
1669
- catch (error) {
1670
- if (!isNodeError(error, 'ENOENT'))
1671
- throw error;
1672
- }
1673
- await writeOptional(integratedRoot, basename(markerPath), Buffer.from(`${JSON.stringify({ childHeadSha, rootHeadSha, bundle, checkpoint })}\n`), beforeCommit);
1674
- await assertGitLifecyclePrivateFile(markerPath, integratedRoot);
1675
- }
49
+ `;function ur(e,r={}){return async(t,o,n={})=>Nt(e,t,o,n,r)}function hr(e={}){let r=Promise.resolve();return{async prepare(t){if((e.platform??process.platform)==="win32")return f("continuous-sandbox-platform-unsupported");if(!/^[a-f0-9]{64}$/.test(t.dispatchId))return f("continuous-sandbox-dispatch-invalid");if(!ce(t.targetRef))return f("continuous-sandbox-target-invalid");if(!Jt(t.executionBranch))return f("continuous-execution-branch-invalid");if(!/^[a-f0-9]{64}$/.test(t.graphRevision))return f("continuous-graph-revision-invalid");const o=Ht(t.authorizedWriteSet);if(o.length===0||o.length!==t.authorizedWriteSet.length)return f("continuous-authorized-write-set-invalid");const n=Te(o),a=r;let c=()=>{};r=new Promise(s=>{c=s}),await a;let i,d;try{const s=await At(t.projectRoot),g=await P(s,["rev-parse","HEAD"]),S=await Ie(s,t.epicId,t.storyId),v=S.revision,A=await gt(s),w=await be(A,"leases"),j=D(w,t.dispatchId);try{await Ee(w,t.dispatchId),await W(j,w)}catch(m){if(!q(m,"EEXIST"))throw m;await W(j,w);const l=await ue(j,w);if(l!==void 0&&Qt(l.pid))return f("continuous-sandbox-lease-active");if(!l||!await oe(j,w,async E=>ot(await ue(E,w),l)))return f("continuous-sandbox-lease-owner-replaced");await Ee(w,t.dispatchId),await W(j,w)}i=j,d=Object.freeze({pid:process.pid,createdAt:new Date().toISOString(),nonce:Ke(16).toString("hex")}),await te(j,"owner.json",Buffer.from(JSON.stringify(d)),e.beforeSandboxWriteCommit),await F(D(j,"owner.json"),j);const R=await be(A,"sandboxes"),p=D(R,t.dispatchId.slice(0,20)),I=await Ge(p,R);let b,u;const k=I?.preparedAt??new Date().toISOString(),x=I?.workspaceOwnerNonce??Ke(16).toString("hex");if(I){if(I.projectRoot!==s||I.storyId!==t.storyId||I.targetRef!==t.targetRef||I.dispatchId!==t.dispatchId||I.epicId!==t.epicId||I.executionBranch!==t.executionBranch||I.graphRevision!==t.graphRevision||I.claimRevision!==n||I.graphAuthorityRevision!==v||I.graphAuthorityEpoch!==S.epoch||I.graphAuthorityStoryStatus!==S.storyStatus||!rt(I.authorizedWriteSet,o)||(b=I.contextSnapshots.map(m=>({path:m.path,...m.contentBase64!==void 0?{content:Buffer.from(m.contentBase64,"base64")}:{}})),u=await Rt(p),u.dev!==I.workspaceIdentity.dev||u.ino!==I.workspaceIdentity.ino))return f("continuous-sandbox-recovery-mismatch")}else await oe(p,R),u=await Ee(R,$(p)),await W(p,R),await ne(R,$(p),u,["init","--quiet"]),await Dt(s,p),await jt(s,R,$(p),u),await ne(R,$(p),u,["remote","add","neocortex-root",s]),await ne(R,$(p),u,["fetch","--quiet","--no-tags","neocortex-root",g]),await ne(R,$(p),u,["checkout","--quiet","--detach","FETCH_HEAD"]),b=await Et(s,p,t.epicId,t.targetRef,e.beforeSandboxWriteCommit),await Zt(p,R,{schemaVersion:1,projectRoot:s,storyId:t.storyId,targetRef:t.targetRef,epicId:t.epicId,executionBranch:t.executionBranch,graphRevision:t.graphRevision,graphAuthorityRevision:v,graphAuthorityEpoch:S.epoch,graphAuthorityStoryStatus:S.storyStatus,authorizedWriteSet:o,claimRevision:n,dispatchId:t.dispatchId,baseSha:g,preparedAt:k,workspaceOwnerNonce:x,workspaceIdentity:u,contextSnapshots:b.map(m=>({path:m.path,...m.content!==void 0?{contentBase64:m.content.toString("base64")}:{}}))},e.beforeSandboxWriteCommit);return i=void 0,{ok:!0,value:{projectRoot:s,workspacePath:p,workspaceStrategy:"branchless_sandbox",storyId:t.storyId,targetRef:t.targetRef,epicId:t.epicId,executionBranch:t.executionBranch,graphRevision:t.graphRevision,graphAuthorityRevision:v,graphAuthorityEpoch:S.epoch,graphAuthorityStoryStatus:S.storyStatus,authorizedWriteSet:o,claimRevision:n,baseSha:I?.baseSha??g,dispatchId:t.dispatchId,preparedAt:k,leasePath:j,leaseOwnerNonce:d.nonce,workspaceOwnerNonce:x,workspaceIdentity:u,contextSnapshots:b}}}catch{if(i&&d){const s=i,g=d;await oe(s,C(s),async S=>ot(await ue(S,C(s)),g)).catch(()=>{})}return f("continuous-sandbox-prepare-failed")}finally{c()}},async integrate(t,o){const n=await ue(t.leasePath,C(t.leasePath)).catch(()=>{}),a=await Ge(t.workspacePath,C(t.workspacePath)).catch(()=>{});if(!n||n.nonce!==t.leaseOwnerNonce||a?.workspaceOwnerNonce!==t.workspaceOwnerNonce||a.dispatchId!==t.dispatchId||a.storyId!==t.storyId)return f("continuous-sandbox-owner-mismatch");const c=Xe(o?.nowIso??new Date().toISOString()),i=await lt(t.projectRoot,{kind:"continuous",storyId:t.storyId,sessionId:t.dispatchId,idempotencyKey:t.dispatchId,expiresAt:new Date(Date.parse(c)+1800*1e3).toISOString(),persistent:!1,createdAt:c});if(!i.ok)return f(i.reasonCode==="git-lifecycle-integration-backpressure"?"continuous-integration-backpressure":"continuous-integration-lease-failed");let d=[],s=!1,g=!1;try{const S=(await ie(t,["status","--porcelain"])).trimEnd(),v=await De(t,["rev-parse","HEAD"]);if(await ee(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"])!==t.executionBranch)return f("continuous-execution-branch-mismatch");const w=C(C(t.leasePath)),j=await be(w,"integrated"),R=D(j,t.dispatchId),p=await Ut(R,j);if(p?.childHeadSha===v&&p.bundle.storyId===t.storyId&&p.bundle.epicId===t.epicId&&p.bundle.executionBranch===t.executionBranch&&p.bundle.graphRevision===t.graphRevision&&p.bundle.claimRevision===t.claimRevision&&rt(p.bundle.authorizedWriteSet,t.authorizedWriteSet)&&p.checkpoint.idempotencyKey===t.dispatchId&&p.checkpoint.bundleId===p.bundle.bundleId&&p.checkpoint.bundleDigest===p.bundle.bundleDigest&&p.checkpoint.graphRevision===t.graphRevision&&p.checkpoint.claimRevision===t.claimRevision&&await ae(t.projectRoot,["merge-base","--is-ancestor",p.rootHeadSha,"HEAD"])&&await Yt(t,p.checkpoint))return{ok:!0,value:{headSha:p.rootHeadSha,alreadyIntegrated:!0,bundle:p.bundle,checkpoint:p.checkpoint}};if(v!==t.baseSha)return f("continuous-sandbox-child-git-authority-denied");if(S.length===0)return f("continuous-bundle-empty");const I=S.split(`
50
+ `).some(y=>y.length>0&&y[0]!==" "&&y[0]!=="?");I||await De(t,["add","-A"]);const b=L(await ie(t,["diff","--cached","--name-only","-z",t.baseSha]));if(b.length===0||b.some(y=>!ce(y)))return f("continuous-integration-write-set-invalid");if(!await Ct(t,["merge-base","--is-ancestor",t.baseSha,v]))return f("continuous-bundle-base-not-ancestor");if(!await ae(t.projectRoot,["merge-base","--is-ancestor",t.baseSha,"HEAD"]))return f("continuous-root-base-not-ancestor");const u=o?.nowIso??new Date().toISOString(),k=Ft(o?.receiptRefs,t.dispatchId),x=await ie(t,["diff","--cached","--binary",t.baseSha]),m={schemaVersion:1,storyId:t.storyId,epicId:t.epicId,executionBranch:t.executionBranch,baseSha:t.baseSha,bundleDigest:G("sha256").update(x).digest("hex"),graphRevision:t.graphRevision,claimRevision:t.claimRevision,authorizedWriteSet:t.authorizedWriteSet,contextDigests:Object.fromEntries(t.contextSnapshots.map(y=>[y.path,G("sha256").update(y.content??Buffer.alloc(0)).digest("hex")])),validationRefs:k,createdAt:t.preparedAt,expiresAt:new Date(Date.parse(t.preparedAt)+1440*60*1e3).toISOString(),branchless:!0},l=Object.freeze({...m,bundleId:Te(m)}),E=await er(t,l);if(E){const y=await Xt(t,l,E);if(y)return await We(R,v,E.headSha,l,y,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:E.headSha,alreadyIntegrated:!0,bundle:l,checkpoint:y}}}if(!E&&await Kt(t.projectRoot,t.epicId)!==t.graphAuthorityRevision)return f("continuous-graph-revision-stale");if(E){const y=await Ye({lease:t,bundle:l,baseSha:E.baseSha,headSha:E.headSha,receiptRefs:k,nowIso:u,qaRunner:e.storyQaRunner});if(!y.ok)return y;await e.beforeCheckpointPersist?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:E.headSha});const O=await Ue({lease:t,physicalLock:i,checkpointAuthority:E.checkpointAuthority,bundle:l,baseSha:E.baseSha,headSha:E.headSha,receiptRefs:[...k,`bundle:${l.bundleId}`,y.value.qaReceipt.receiptRef,y.value.reviewReceipt.receiptRef],qaReceipt:y.value.qaReceipt,reviewReceipt:y.value.reviewReceipt,recordedAt:u,checkpointNow:e.checkpointNow,insideCheckpointPreCommit:e.insideCheckpointPreCommit,afterCheckpointPersist:e.afterCheckpointPersist});return O.ok?(await We(R,v,E.headSha,l,O.value,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:E.headSha,alreadyIntegrated:!0,bundle:l,checkpoint:O.value}}):O}if(I)return f("continuous-sandbox-child-git-authority-denied");if(L(await z(t.projectRoot,["diff","--cached","--name-only","-z"])).length>0)return f("continuous-integration-root-index-dirty");const J=new Set(t.contextSnapshots.map(y=>y.path));if(b.filter(y=>!t.authorizedWriteSet.some(O=>Se(O,y))).length>0)return f("continuous-bundle-write-set-unauthorized");const M=b.filter(y=>!J.has(y)),Re=new Set(L(await z(t.projectRoot,["diff","--name-only","-z",`${t.baseSha}..HEAD`])));if(M.some(y=>Re.has(y)))return f("continuous-bundle-intervening-conflict");const he=new Set([...L(await z(t.projectRoot,["diff","--name-only","-z"])),...L(await z(t.projectRoot,["ls-files","--others","--exclude-standard","-z"]))]);if(M.some(y=>he.has(y)))return f("continuous-integration-root-conflict");d=await $t(t.projectRoot,[...new Set([...b,".neocortex/state.json"])]);const H=await zt(t,u);if(!H.ok)return H;const K=pt({bundle:l,payload:Buffer.from(x),expected:{epicId:t.epicId,storyId:t.storyId,executionBranch:t.executionBranch,baseSha:t.baseSha,graphRevision:t.graphRevision,claimRevision:t.claimRevision,authorizedWriteSet:t.authorizedWriteSet,nowIso:u},writerLease:H.value});if(K.length>0)return await Ne(t.projectRoot,d),f(`continuous-bundle-admission-${K[0]}`);const fe=await P(t.projectRoot,["rev-parse","HEAD"]);let Q;await e.beforeRootCommit?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:fe});try{await X(t.projectRoot,y=>{const O=h(ye(y,t.epicId).branch_lease);if(O?.ownerStoryId!==t.storyId||O.sessionId!==t.dispatchId||O.idempotencyKey!==t.dispatchId||Date.parse(String(O.expiresAt))<=Date.now())throw new Error("continuous-checkpoint-writer-lease-lost")},{preCommit:async y=>{const O=await Ie(t.projectRoot,t.epicId,t.storyId,y);if(O.revision!==t.graphAuthorityRevision||O.epoch!==t.graphAuthorityEpoch||O.storyStatus!==t.graphAuthorityStoryStatus)throw new Error("continuous-graph-revision-stale");if(!await xe(i.path,i.owner))throw new Error("continuous-integration-lock-raced");const nt=await ee(t.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),it=await P(t.projectRoot,["rev-parse","HEAD"]);if(nt!==t.executionBranch||it!==fe)throw new Error("continuous-integration-head-raced");const at=L(await z(t.projectRoot,["diff","--cached","--name-only","-z"])),ct=new Set([...L(await z(t.projectRoot,["diff","--name-only","-z"])),...L(await z(t.projectRoot,["ls-files","--others","--exclude-standard","-z"]))]);if(at.length>0)throw new Error("continuous-integration-root-index-dirty");if(M.some(_=>ct.has(_)))throw new Error("continuous-integration-root-conflict");if(g=!0,M.length>0){const _=await ie(t,["diff","--cached","--binary",t.baseSha,"--",...M]);if(_.length>0&&!await _t(t.projectRoot,["apply","--index","--3way","--whitespace=nowarn"],_))throw new Error("continuous-integration-conflict")}for(const _ of t.contextSnapshots){if(!b.includes(_.path))continue;const qe=await Ce(D(t.projectRoot,_.path)),He=await Ot(t,_.path),Je=_.path===".neocortex/state.json"?qt(_.content,qe,Gt(_.content,He,t.storyId)):Wt(_.content,qe,He);if(!Je.ok)throw new Error(_.path===".neocortex/state.json"?"continuous-state-merge-conflict":"continuous-context-merge-conflict");await te(t.projectRoot,_.path,Je.value),await P(t.projectRoot,["add","-A","--",_.path])}if(b.includes(".neocortex/state.json")&&await P(t.projectRoot,["add","-A","--",".neocortex/state.json"]),await ae(t.projectRoot,["diff","--cached","--quiet"]))throw new Error("continuous-integration-empty-after-admission");Q=await Ie(t.projectRoot,t.epicId,t.storyId,y),await P(t.projectRoot,["commit","-m",`feat(yoloop): integrate ${t.storyId}`,"-m",`Neocortex-Story: ${t.storyId}`,"-m",`Neocortex-Epic: ${t.epicId}`,"-m",`Neocortex-Execution-Branch: ${t.executionBranch}`,"-m",`Neocortex-Prepared-Base: ${t.baseSha}`,"-m",`Neocortex-Dispatch: ${t.dispatchId}`,"-m",`Neocortex-Bundle: ${l.bundleId}`,"-m",`Neocortex-Bundle-Digest: ${l.bundleDigest}`,"-m",`Neocortex-Graph-Revision: ${t.graphRevision}`,"-m",`Neocortex-Claim-Revision: ${t.claimRevision}`,"-m",`Neocortex-Checkpoint-Authority: ${Q.revision}`,"-m",`Neocortex-Checkpoint-Epoch: ${Q.epoch??"null"}`,"-m",`Neocortex-Checkpoint-Story-Status: ${Q.storyStatus??"null"}`]),s=!0}})}catch(y){g&&!s&&await Ne(t.projectRoot,d);const O=y instanceof Error&&/^continuous-/.test(y.message)?y.message:"continuous-integration-failed";return f(O)}const Z=await P(t.projectRoot,["rev-parse","HEAD"]);if(!Q)return f("continuous-checkpoint-authority-missing");await e.afterRootCommit?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:Z});const U=await Ye({lease:t,bundle:l,baseSha:fe,headSha:Z,receiptRefs:k,nowIso:u,qaRunner:e.storyQaRunner});if(!U.ok)return U;await e.beforeCheckpointPersist?.({projectRoot:t.projectRoot,storyId:t.storyId,headSha:Z});const pe=await Ue({lease:t,physicalLock:i,checkpointAuthority:Q,bundle:l,baseSha:fe,headSha:Z,receiptRefs:[...k,`bundle:${l.bundleId}`,U.value.qaReceipt.receiptRef,U.value.reviewReceipt.receiptRef],qaReceipt:U.value.qaReceipt,reviewReceipt:U.value.reviewReceipt,recordedAt:u,checkpointNow:e.checkpointNow,insideCheckpointPreCommit:e.insideCheckpointPreCommit,afterCheckpointPersist:e.afterCheckpointPersist});return pe.ok?(await We(R,v,Z,l,pe.value,e.beforeSandboxWriteCommit),{ok:!0,value:{headSha:Z,alreadyIntegrated:!1,bundle:l,checkpoint:pe.value}}):pe}catch{return g&&!s&&d.length>0&&await Ne(t.projectRoot,d),f("continuous-integration-failed")}finally{await Tt(t).catch(()=>{}),await It(i.path,i.owner).catch(()=>{})}},async release(t,o){o||await oe(t.workspacePath,C(t.workspacePath),async n=>{const a=await Ge(n,C(t.workspacePath)).catch(()=>{});return a?.workspaceOwnerNonce===t.workspaceOwnerNonce&&a.dispatchId===t.dispatchId&&a.storyId===t.storyId}),await oe(t.leasePath,C(t.leasePath),async n=>(await ue(n,C(t.leasePath)).catch(()=>{}))?.nonce===t.leaseOwnerNonce)}}}async function Et(e,r,t,o,n){const a=[...new Set([".neocortex/state.json",o,`docs/epics/epic-${Vt(t)}.md`])],c=[];for(const i of a){if(!ce(i))continue;const d=await Ce(D(e,i));c.push({path:i,...d!==void 0?{content:d}:{}}),d!==void 0&&await te(r,i,d,n)}return c}async function At(e){const r=await P(e,["rev-parse","--show-toplevel"]),[t,o]=await Promise.all([Y(r),Y(e)]);if(t!==o)throw new Error("project root mismatch");return t}async function jt(e,r,t,o){for(const n of["user.name","user.email"]){const a=await ee(e,["config","--get",n]);a&&await ne(r,t,o,["config",n,a])}}async function Dt(e,r){const t=await V(e);await X(r,o=>{for(const[n,a]of Object.entries(t.epics))o.epics[n]={...structuredClone(a),branch_lease:null};for(const[n,a]of Object.entries(t.stories))o.stories[n]=structuredClone(a)})}async function ne(e,r,t,o){return(await Ae(e,r,t,o)).toString("utf8").trim()}async function ie(e,r){return(await Ae(C(e.workspacePath),$(e.workspacePath),e.workspaceIdentity,r)).toString("utf8")}async function De(e,r){return(await ie(e,r)).trim()}async function Ct(e,r){try{return await De(e,r),!0}catch{return!1}}async function Ot(e,r){try{return await Ae(C(e.workspacePath),$(e.workspacePath),e.workspaceIdentity,["show",`:${r}`])}catch{return}}async function Nt(e,r,t,o,n){const a=Date.now(),c=A=>({exitCode:null,timedOut:!1,durationMs:Date.now()-a,stdout:"",stderr:"",stdoutBytes:0,stderrBytes:0,...A});if(o.signal?.aborted)return c({signal:"SIGTERM",cancelled:!0});if(!r||r.length>4096||r.includes("\0")||t.length>512||t.some(A=>A.length>32768||A.includes("\0")))return c({exitCode:73,stderr:"continuous-child-invocation-invalid",stderrBytes:35});const i=C(e.workspacePath),d=await le(i,{bigint:!0}),s=await dt(i,{bigint:!0});if(!d.isDirectory()||d.isSymbolicLink()||!s.isDirectory()||d.dev!==s.dev||d.ino!==s.ino)return c({exitCode:73,stderr:"continuous-child-parent-invalid",stderrBytes:31});await n.beforeHandoff?.();const g=Buffer.from(JSON.stringify({command:r,args:[...t]})).toString("base64url"),S=o.maxOutputBytes??64e3,v=Math.max(1,Math.min(o.timeoutMs??600*1e3,1800*1e3));return await new Promise(A=>{const w=Me(process.execPath,["-e",xt,String(s.dev),String(s.ino),$(e.workspacePath),e.workspaceIdentity.dev,e.workspaceIdentity.ino,g,n.afterHandoff?"1":"0"],{cwd:i,env:o.env,stdio:["pipe","pipe","pipe"]});let j="",R="",p=0,I=0,b=!1,u=!1,k=!1,x=!n.afterHandoff;const m=(N,J)=>{b||(b=!0,clearTimeout(E),o.signal?.removeEventListener("abort",l),A({exitCode:N,...J?{signal:J}:{},timedOut:u,...k?{cancelled:!0}:{},durationMs:Date.now()-a,stdout:j,stderr:R,stdoutBytes:p,stderrBytes:I}))},l=()=>{k=!0,w.kill("SIGTERM")};o.signal?.addEventListener("abort",l,{once:!0});const E=setTimeout(()=>{u=!0,w.kill("SIGTERM")},v);w.stdout.on("data",N=>{p+=N.length,p+I>S?w.kill("SIGTERM"):j+=N.toString("utf8")}),w.stderr.on("data",N=>{I+=N.length,p+I>S?w.kill("SIGTERM"):R+=N.toString("utf8"),!x&&R.includes(`continuous-child-handoff-ready
51
+ `)&&(x=!0,Promise.resolve(n.afterHandoff?.()).then(()=>w.stdin.end()).catch(()=>w.kill("SIGTERM")))}),w.once("error",()=>m(null)),w.once("close",(N,J)=>m(N,J)),n.afterHandoff||w.stdin.end()})}async function P(e,r){return(await z(e,r)).trim()}async function z(e,r){const t=await je("git",r,{cwd:e,encoding:"utf8",maxBuffer:16777216});return String(t.stdout)}async function ee(e,r){try{return await P(e,r)}catch(t){if(q(t,"ENOENT"))return;throw t}}async function ae(e,r){try{return await P(e,r),!0}catch{return!1}}async function _t(e,r,t){return await new Promise(o=>{const n=Me("git",[...r],{cwd:e,stdio:["pipe","ignore","ignore"]});n.once("error",()=>o(!1)),n.once("close",a=>o(a===0)),n.stdin.end(t)})}async function fr(e,r,t){try{const o=await je("git",["show",`${r}:${t}`],{cwd:e,encoding:"buffer",maxBuffer:16777216});return Buffer.from(o.stdout)}catch(o){if(q(o,"ENOENT"))return;throw o}}async function Ce(e){try{return await B(e)}catch(r){if(q(r,"ENOENT"))return;throw r}}async function te(e,r,t,o){const n=se(r);if(!ce(n))throw new Error("continuous-sandbox-write-path-invalid");const a=await Y(e);if(a!==ht(e))throw new Error("continuous-sandbox-write-root-symlink");const c=C(n)==="."?"":C(n),i=await Bt(a,c),d=await Qe(i),s=D(i,$(n));if(await me(s,a,!0),t===void 0){await o?.({boundaryRoot:a,relativePath:n,destinationPath:s}),await Ze(i,a,d),await me(s,a,!0),await kt(i,$(n));return}await o?.({boundaryRoot:a,relativePath:n,destinationPath:s}),await Ze(i,a,d),await me(s,a,!0),await vt(i,$(n),t),await me(s,a,!1)}async function Bt(e,r){let t=e;for(const o of r.split("/").filter(Boolean)){t=D(t,o),await bt(C(t),$(t));const n=await le(t);if(!n.isDirectory()||n.isSymbolicLink()||await Y(t)!==t)throw new Error("continuous-sandbox-write-component-unsafe");Oe(e,t)}return t}async function me(e,r,t){Oe(r,e);try{const o=await le(e);if(o.isSymbolicLink()||!o.isFile())throw new Error("continuous-sandbox-write-destination-unsafe");if(await Y(e)!==e)throw new Error("continuous-sandbox-write-destination-symlink")}catch(o){if(t&&q(o,"ENOENT"))return;throw o}}function Oe(e,r){const t=ut(e,r);if(t===""||t.startsWith("..")||Fe(t))throw new Error("continuous-sandbox-write-containment-invalid")}async function Qe(e){const r=await le(e,{bigint:!0});if(!r.isDirectory()||r.isSymbolicLink())throw new Error("continuous-sandbox-write-parent-unsafe");return{dev:r.dev,ino:r.ino}}async function Pt(e,r,t){try{if(e!==r&&Oe(r,e),await Y(e)!==e)return!1;const o=await Qe(e);return o.dev===t.dev&&o.ino===t.ino}catch{return!1}}async function Ze(e,r,t){if(!await Pt(e,r,t))throw new Error("continuous-sandbox-write-parent-raced")}async function $t(e,r){return await Promise.all(r.map(async t=>{const o=await Ce(D(e,t));return{path:t,...o!==void 0?{content:o}:{}}}))}async function Ne(e,r){const t=r.map(o=>o.path);t.length>0&&await ae(e,["reset","--quiet","HEAD","--",...t]);for(const o of r)await te(e,o.path,o.content)}async function zt(e,r){try{const t=D(e.projectRoot,".neocortex/state.json"),o=T(JSON.parse((await B(t)).toString("utf8"))),n=h(h(o.epics)?.[e.epicId]),a=h(n?.branch_lease),c=Object.freeze({schemaVersion:1,ownerStoryId:e.storyId,sessionId:e.dispatchId,idempotencyKey:e.dispatchId,acquiredAt:r,expiresAt:new Date(Date.parse(r)+600*1e3).toISOString()});let i=!1;return await X(e.projectRoot,d=>{const s=ye(d,e.epicId),g=h(s.branch_lease)??a;if(g&&typeof g.expiresAt=="string"&&g.expiresAt>r&&(g.ownerStoryId!==e.storyId||g.idempotencyKey!==e.dispatchId)){i=!0;return}s.branch_mode="epic",s.execution_branch=e.executionBranch,s.branch_lease=c}),i?f("continuous-epic-checkout-writer-active"):{ok:!0,value:c}}catch{return f("continuous-writer-lease-persist-failed")}}async function Tt(e){await X(e.projectRoot,r=>{const t=ye(r,e.epicId),o=h(t.branch_lease);o?.ownerStoryId===e.storyId&&o.idempotencyKey===e.dispatchId&&(t.branch_lease=null)})}async function Ue(e){try{const r=D(e.lease.projectRoot,".neocortex/state.json"),t=Object.freeze({schemaVersion:1,storyId:e.lease.storyId,epicId:e.lease.epicId,branch:e.lease.executionBranch,baseSha:e.baseSha,headSha:e.headSha,commits:Object.freeze([e.headSha]),idempotencyKey:e.lease.dispatchId,dispatchId:e.lease.dispatchId,bundleId:e.bundle.bundleId,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,claimRevision:e.lease.claimRevision,receiptRefs:Object.freeze([...new Set(e.receiptRefs)]),qaVerdict:"passed",reviewVerdict:"approved",qaReceipt:e.qaReceipt,reviewReceipt:e.reviewReceipt,recordedAt:e.recordedAt}),o=T(JSON.parse((await B(r)).toString("utf8"))),n=h(h(o.stories)?.[e.lease.storyId]);let a="persisted",c,i,d,s,g=!1,S;const v=async(u,k,x)=>{const m=await ee(e.lease.projectRoot,["symbolic-ref","--quiet","--short","HEAD"]),l=await P(e.lease.projectRoot,["rev-parse","HEAD"]);if(m!==e.lease.executionBranch||l!==e.headSha)throw new Error("continuous-checkpoint-head-raced");if(u.graphRevision!==e.lease.graphRevision||u.claimRevision!==e.lease.claimRevision||u.bundleId!==e.bundle.bundleId||u.bundleDigest!==e.bundle.bundleDigest)throw new Error("continuous-checkpoint-graph-raced");const E=x??T(JSON.parse((await B(r)).toString("utf8"))),N=re(E,k??await V(e.lease.projectRoot)),J=h(h(N.epics)?.[e.lease.epicId]),ve=h(h(N.stories)?.[e.lease.storyId]),M=Array.isArray(ve?.depends_on)?ve.depends_on.filter(H=>typeof H=="string"):[],Re=h(N.stories);if(J?.execution_branch!==e.lease.executionBranch||M.some(H=>{const K=h(Re?.[H]);return!K||!["done","completed","merged"].includes(String(K.status))}))throw new Error("continuous-checkpoint-dependency-raced");const he=L(await z(e.lease.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",e.headSha]));if(he.length===0||he.some(H=>!e.lease.authorizedWriteSet.some(K=>Se(K,H))))throw new Error("continuous-checkpoint-write-set-raced");if(!await ke(e.lease.projectRoot,u,e.lease.storyId,e.lease.epicId,e.lease.executionBranch,void 0,e.lease.authorizedWriteSet))throw new Error("continuous-checkpoint-receipt-revalidation-failed")},A=await V(e.lease.projectRoot,{required:!0}),w=h(h(A.epics[e.lease.epicId])?.branch_lease);if(w?.ownerStoryId!==e.lease.storyId||w.idempotencyKey!==e.lease.dispatchId||w.sessionId!==e.lease.dispatchId||typeof w.expiresAt!="string"||Date.parse(w.expiresAt)<=(e.checkpointNow?.("before-mutation")??Date.now()))return f("continuous-checkpoint-writer-lease-lost");if(!await xe(e.physicalLock.path,e.physicalLock.owner))return f("continuous-checkpoint-integration-lock-raced");const j=await B(r),R=G("sha256").update(j).digest("hex");await v(t,A);const p=$e(T(JSON.parse(j.toString("utf8"))),A,e.lease.epicId,e.lease.storyId);if(p.revision!==e.checkpointAuthority.revision||p.epoch!==e.checkpointAuthority.epoch||p.storyStatus!==e.checkpointAuthority.storyStatus)return f("continuous-graph-revision-stale");const I=await X(e.lease.projectRoot,u=>{const k=ye(u,e.lease.epicId),x=h(k.branch_lease);i=x===void 0?void 0:structuredClone(x),d=structuredClone(u),g=u.stories[e.lease.storyId]!==void 0,s=structuredClone(u.stories[e.lease.storyId]??{}),S=structuredClone(k.branch_lease);const m=mt(u,e.lease.storyId),l=h(m.checkpoint)??h(n?.checkpoint);if(l?.idempotencyKey===e.lease.dispatchId){l.baseSha!==e.baseSha||l.headSha!==e.headSha||l.bundleId!==e.bundle.bundleId||l.bundleDigest!==e.bundle.bundleDigest||l.graphRevision!==e.lease.graphRevision||l.claimRevision!==e.lease.claimRevision?a="conflict":(a="reused",c=l,k.branch_lease=null);return}if(x?.ownerStoryId!==e.lease.storyId||x.idempotencyKey!==e.lease.dispatchId||x.sessionId!==e.lease.dispatchId){a="lease-lost";return}m.checkpoint=t,m.status="done",m.last_step=we;const E=Array.isArray(m.steps_completed)?m.steps_completed.filter(N=>typeof N=="string"):[];m.steps_completed=[...new Set([...E,Ve,we])],k.branch_lease=null},{expectedRevision:A.revision,preCommit:async u=>{if(i?.ownerStoryId!==e.lease.storyId||i.idempotencyKey!==e.lease.dispatchId||i.sessionId!==e.lease.dispatchId||typeof i.expiresAt!="string"||Date.parse(i.expiresAt)<=(e.checkpointNow?.("pre-commit")??Date.now()))throw new Error("continuous-checkpoint-writer-lease-lost");if(await e.insideCheckpointPreCommit?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha}),!await xe(e.physicalLock.path,e.physicalLock.owner))throw new Error("continuous-checkpoint-integration-lock-raced");await v(c??t,u);const k=await B(r);if(G("sha256").update(k).digest("hex")!==R)throw new Error("continuous-graph-revision-stale");if(!d)throw new Error("continuous-checkpoint-authority-missing");const x=T(JSON.parse(k.toString("utf8"))),m=$e(x,d,e.lease.epicId,e.lease.storyId);if(m.revision!==e.checkpointAuthority.revision||m.epoch!==e.checkpointAuthority.epoch||m.storyStatus!==e.checkpointAuthority.storyStatus)throw new Error("continuous-graph-revision-stale");if(a==="persisted"&&!ze(x,u,e.lease,t))throw new Error("continuous-checkpoint-projection-raced")}}),b=a;if(b==="conflict")return f("continuous-checkpoint-idempotency-conflict");if(b==="lease-lost")return f("continuous-checkpoint-writer-lease-lost");if(b==="reused"&&c)try{return await v(c),{ok:!0,value:c}}catch{return f("continuous-checkpoint-reused-evidence-invalid")}try{await e.afterCheckpointPersist?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha});const u=await V(e.lease.projectRoot,{required:!0});if(u.revision!==I.document.revision)throw new Error("continuous-checkpoint-post-persist-runtime-raced");await v(t,u);const k=await B(r);if(G("sha256").update(k).digest("hex")!==R)throw new Error("continuous-checkpoint-post-persist-authority-raced");const x=T(JSON.parse(k.toString("utf8")));if(!ze(x,u,e.lease,t))throw new Error("continuous-checkpoint-post-persist-projection-raced")}catch{const u=await B(r).catch(()=>{}),k=u===void 0||G("sha256").update(u).digest("hex")!==R;return await X(e.lease.projectRoot,x=>{const m=h(x.epics[e.lease.epicId]),l=h(x.stories[e.lease.storyId]),E=u===void 0?void 0:T(JSON.parse(u.toString("utf8")));if(!m||!l||!E||!ze(E,x,e.lease,t))throw new Error("continuous-checkpoint-cleanup-cas-conflict");if(k){g?Mt(l,s??{}):delete x.stories[e.lease.storyId],S===void 0?delete m.branch_lease:m.branch_lease=structuredClone(S);return}l.checkpoint=null,l.status="blocked",m.branch_lease=null},{expectedRevision:I.document.revision}).catch(()=>{}),f("continuous-checkpoint-post-persist-raced")}return{ok:!0,value:t}}catch(r){const t=r instanceof Error&&/^continuous-/.test(r.message)?r.message:"continuous-checkpoint-persist-failed";return f(t)}}async function Ye(e){try{if(await P(e.lease.projectRoot,["rev-parse","HEAD"])!==e.headSha)return f("continuous-story-evidence-head-raced");const r=await B(D(e.lease.projectRoot,"config","release-gates.v2.json"),"utf8"),t=JSON.parse(r),o=Array.isArray(t.requiredCompleteClasses)?t.requiredCompleteClasses.filter(b=>typeof b=="string"&&/^[a-z0-9-]+$/.test(b)):[];if(t.contract!=="P205-CI-02"||o.length===0)return f("continuous-story-qa-manifest-invalid");const n=String((await je(process.execPath,["scripts/test-root.mjs","--gate","complete"],{cwd:e.lease.projectRoot,encoding:"utf8",maxBuffer:32*1024*1024})).stdout);if(await e.qaRunner?.({projectRoot:e.lease.projectRoot,storyId:e.lease.storyId,headSha:e.headSha}),await P(e.lease.projectRoot,["rev-parse","HEAD"])!==e.headSha)return f("continuous-story-qa-head-raced");const a=Xe(e.nowIso),c=await P(e.lease.projectRoot,["rev-list","--count",`${e.baseSha}..${e.headSha}`]),i=await z(e.lease.projectRoot,["show","--no-patch","--format=%H%n%P%n%B",e.headSha]),d=L(await z(e.lease.projectRoot,["diff","--name-only","-z",`${e.baseSha}..${e.headSha}`])),s=yt({storyId:e.lease.storyId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,commitBody:i,changedPaths:d}),g=G("sha256").update(r).digest("hex"),S=G("sha256").update(n).digest("hex"),v=wt({gitEvidenceDigest:s,headSha:e.headSha,graphRevision:e.lease.graphRevision,manifestDigest:g,gateIds:o,resultDigest:S}),A=`story-qa:${v}`,w=Object.freeze({schemaVersion:1,kind:"story_qa_evidence",producer:"local-yolo-tdd",evidenceVersion:"p205-execution-v2",storyId:e.lease.storyId,epicId:e.lease.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,contract:"P205-CI-02",command:St,manifestDigest:g,gateIds:Object.freeze(o),resultDigest:S,sourceEvidenceDigest:v,verdict:"passed",checkedAt:a,receiptRef:A}),j=[`Neocortex-Story: ${e.lease.storyId}`,`Neocortex-Epic: ${e.lease.epicId}`,`Neocortex-Bundle-Digest: ${e.bundle.bundleDigest}`,`Neocortex-Graph-Revision: ${e.lease.graphRevision}`];if(c!=="1"||!j.every(b=>i.includes(b))||d.length===0||d.some(b=>!e.lease.authorizedWriteSet.some(u=>Se(u,b))))return f("continuous-story-review-evidence-rejected");const R=G("sha256").update(["root-commit-range-review-v1",e.lease.storyId,e.baseSha,e.headSha,e.bundle.bundleDigest,e.lease.graphRevision,A,G("sha256").update(i).digest("hex"),[...d].sort().join(",")].join("\0")).digest("hex"),p=`story-review:${R}`,I=Object.freeze({schemaVersion:1,kind:"story_review_evidence",producer:"root-commit-range-review",storyId:e.lease.storyId,epicId:e.lease.epicId,baseSha:e.baseSha,headSha:e.headSha,bundleDigest:e.bundle.bundleDigest,graphRevision:e.lease.graphRevision,sourceEvidenceDigest:R,qaReceiptRef:A,verdict:"approved",reviewedAt:a,receiptRef:p});return{ok:!0,value:{qaReceipt:w,reviewReceipt:I}}}catch{return f("continuous-story-evidence-production-failed")}}function Xe(e){return Number.isFinite(Date.parse(e))?new Date(Date.parse(e)).toISOString():new Date().toISOString()}function Gt(e,r,t){if(r!==void 0)try{const o=e===void 0?{}:T(JSON.parse(e.toString("utf8"))),n=T(JSON.parse(r.toString("utf8"))),a=structuredClone(o),c=h(h(o.stories)?.[t]),i=h(h(n.stories)?.[t]),d=Lt(a,"stories"),s=structuredClone(c??{});for(const g of["status","last_step","steps_completed","last_updated","blocked_reason","blocked_at","implementation_evidence","validation_evidence","qa_gate"])i&&Object.prototype.hasOwnProperty.call(i,g)&&(s[g]=structuredClone(i[g]));return d[t]=s,Buffer.from(`${JSON.stringify(a,null,2)}
52
+ `)}catch{return Buffer.from("{invalid-child-state")}}function Lt(e,r){const t=h(e[r]);if(t)return t;const o={};return e[r]=o,o}function T(e){if(!e||typeof e!="object"||Array.isArray(e))throw new Error("record expected");return e}function h(e){return e&&typeof e=="object"&&!Array.isArray(e)?e:void 0}function Wt(e,r,t){return Pe(t,e)||Pe(r,t)?{ok:!0,value:r}:Pe(r,e)?{ok:!0,value:t}:f("continuous-context-merge-conflict")}function qt(e,r,t){try{const o=et(_e(e),_e(r),_e(t));return o.ok?{ok:!0,value:o.value===void 0?void 0:Buffer.from(`${JSON.stringify(o.value,null,2)}
53
+ `)}:o}catch{return f("continuous-state-merge-invalid")}}function _e(e){return e===void 0?void 0:JSON.parse(e.toString("utf8"))}function et(e,r,t){if(ge(t,e)||ge(r,t))return{ok:!0,value:r};if(ge(r,e))return{ok:!0,value:t};if(Be(e)&&Be(r)&&Be(t)){const o={};for(const n of[...new Set([...Object.keys(e),...Object.keys(r),...Object.keys(t)])].sort()){const a=et(e[n],r[n],t[n]);if(!a.ok)return a;a.value!==void 0&&(o[n]=a.value)}return{ok:!0,value:o}}if(Array.isArray(e)&&Array.isArray(r)&&Array.isArray(t)&&tt(e,r)&&tt(e,t)){const o=[...e,...r.slice(e.length),...t.slice(e.length)],n=new Set;return{ok:!0,value:o.filter(a=>{const c=JSON.stringify(a);return n.has(c)?!1:(n.add(c),!0)})}}return f("continuous-state-merge-conflict")}function Be(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function tt(e,r){return e.length<=r.length&&e.every((t,o)=>ge(t,r[o]))}function ge(e,r){return JSON.stringify(e)===JSON.stringify(r)}function Pe(e,r){return e===void 0||r===void 0?e===r:e.equals(r)}function L(e){return e.split("\0").filter(Boolean)}function ce(e){const r=se(e);return r.length>0&&r.length<=1024&&!Fe(r)&&!/^[A-Za-z]:\//.test(r)&&!r.split("/").includes("..")&&!r.includes("\0")&&!r.startsWith("/")}function se(e){return e.replaceAll("\\","/").replace(/^\.\//,"").replace(/\/{2,}/g,"/")}function Ht(e){const r=e.map(se).filter(ce);return[...new Set(r)].sort()}function Se(e,r){const t=se(e),o=se(r);return t===o||t.endsWith("/")&&o.startsWith(t)}function Jt(e){return e.length>0&&e.length<=240&&!e.startsWith("-")&&!e.startsWith("/")&&!e.endsWith("/")&&!e.endsWith(".lock")&&!e.includes("..")&&!e.includes("\\")&&!e.includes("@{")&&!e.includes("//")&&/^[A-Za-z0-9._/-]+$/.test(e)}function rt(e,r){return e.length===r.length&&e.every((t,o)=>t===r[o])}async function Ie(e,r,t,o){const n=T(JSON.parse(await B(D(e,".neocortex/state.json"),"utf8")));return $e(n,o??await V(e),r,t)}function $e(e,r,t,o){const n=re(e,r),a=h(n.epics),c=h(n.stories),i=h(a?.[t])??{},d=(Array.isArray(i.stories)?i.stories:Array.isArray(i.story_ids)?i.story_ids:[]).filter(v=>typeof v=="string"),s=d.length>0?d:Object.entries(c??{}).filter(([v,A])=>h(A)?.epic_id===t||v.startsWith(`${t}.`)).map(([v])=>v).sort(),g=["status","depends_on","files_to_modify","contracts","contract_refs","shared_surfaces","steps_completed","last_step","branch_name","physicalMergeStatus","merged","checkpoint","planning","attempts","retry_count","rollback_receipt","cancelled_at"],S=Object.fromEntries(s.map(v=>{const A=h(c?.[v])??{};return[v,Object.fromEntries(g.filter(w=>Object.prototype.hasOwnProperty.call(A,w)).map(w=>[w,A[w]]))]}));return{revision:Te({epicId:t,epic:{stories:s,status:i.status??null,branch_mode:i.branch_mode??null,execution_branch:i.execution_branch??null,graph_revision:i.graph_revision??null,depends_on:i.depends_on??null,planning:i.planning??null,execution_plan:i.execution_plan??null,waves:i.waves??null,current_wave:i.current_wave??null,replan:i.replan??null,replan_revision:i.replan_revision??null,dependency_graph:i.dependency_graph??null,scheduler:i.scheduler??null,attempts:i.attempts??null,retry_count:i.retry_count??null},stories:S}),epoch:typeof i.graph_revision=="string"?i.graph_revision:null,storyStatus:typeof h(c?.[o])?.status=="string"?String(h(c?.[o])?.status):null}}function ze(e,r,t,o){const n=re(e,r),a=h(h(n.epics)?.[t.epicId]),c=h(h(n.stories)?.[t.storyId]),i=Array.isArray(c?.steps_completed)?c.steps_completed.filter(d=>typeof d=="string"):[];return!!(a&&c&&a.branch_lease===null&&c.status==="done"&&c.last_step===we&&i.includes(Ve)&&i.includes(we)&&de(c.checkpoint)===de(o))}function Mt(e,r){for(const t of Object.keys(e))delete e[t];Object.assign(e,structuredClone(r))}async function Kt(e,r){return(await Ie(e,r,"")).revision}function Te(e){return G("sha256").update(de(e)).digest("hex")}function de(e){return e===null||typeof e!="object"?JSON.stringify(e):Array.isArray(e)?`[${e.map(de).join(",")}]`:`{${Object.entries(e).sort(([r],[t])=>r.localeCompare(t)).map(([r,t])=>`${JSON.stringify(r)}:${de(t)}`).join(",")}}`}function Ft(e,r){const t=(e??[]).filter(o=>/^[A-Za-z0-9._/:@#-]{1,200}$/.test(o)&&!o.includes(".."));return Object.freeze([...new Set(t.length>0?t:[`dispatch:${r}`])].sort())}function Vt(e){return e.replace(/[^A-Za-z0-9._-]/g,"-").slice(0,80)}function f(e){return{ok:!1,reasonCode:e}}function q(e,r){return e instanceof Error&&"code"in e&&e.code===r}async function ue(e,r){try{await W(e,r);const t=D(e,"owner.json");await F(t,e);const o=JSON.parse(await B(t,"utf8"));if(!Number.isSafeInteger(o.pid)||Number(o.pid)<=0||typeof o.createdAt!="string"||!Number.isFinite(Date.parse(o.createdAt))||typeof o.nonce!="string"||!/^[a-f0-9]{32}$/.test(o.nonce))throw new Error("continuous-sandbox-lease-owner-invalid");return{pid:Number(o.pid),createdAt:o.createdAt,nonce:o.nonce}}catch(t){if(q(t,"ENOENT"))return;throw t}}function ot(e,r){return e?.pid===r.pid&&e.createdAt===r.createdAt&&e.nonce===r.nonce}function Qt(e){try{return process.kill(e,0),!0}catch(r){return q(r,"EPERM")}}async function Ge(e,r){try{await W(e,r);const t=D(e,".git");await W(t,e);const o=D(t,"neocortex-sandbox.json");await F(o,t);const n=JSON.parse(await B(o,"utf8"));if(n.schemaVersion!==1||typeof n.workspaceOwnerNonce!="string"||!/^[a-f0-9]{32}$/.test(n.workspaceOwnerNonce)||!/^[a-f0-9]{64}$/.test(n.graphAuthorityRevision)||!(n.graphAuthorityEpoch===null||/^[a-f0-9]{64}$/.test(n.graphAuthorityEpoch))||!(n.graphAuthorityStoryStatus===null||typeof n.graphAuthorityStoryStatus=="string"&&n.graphAuthorityStoryStatus.length<=80)||typeof n.workspaceIdentity?.dev!="string"||!/^[0-9]+$/.test(n.workspaceIdentity.dev)||typeof n.workspaceIdentity?.ino!="string"||!/^[0-9]+$/.test(n.workspaceIdentity.ino))throw new Error("continuous-sandbox-metadata-invalid");return n}catch(t){if(q(t,"ENOENT"))return;throw t}}async function Zt(e,r,t,o){await W(e,r);const n=D(e,".git");await W(n,e);const a=D(n,"neocortex-sandbox.json");await te(e,".git/neocortex-sandbox.json",Buffer.from(`${JSON.stringify(t,null,2)}
54
+ `),o),await F(a,n)}async function Ut(e,r){try{await F(e,r);const t=JSON.parse(await B(e,"utf8"));return typeof t.childHeadSha=="string"&&typeof t.rootHeadSha=="string"&&/^[a-f0-9]{40,64}$/.test(t.childHeadSha)&&/^[a-f0-9]{40,64}$/.test(t.rootHeadSha)&&t.bundle?.schemaVersion===1&&t.checkpoint?.schemaVersion===1?t:void 0}catch(t){if(q(t,"ENOENT"))return;throw t}}async function Yt(e,r){try{const t=T(JSON.parse(await B(D(e.projectRoot,".neocortex/state.json"),"utf8"))),o=re(t,await V(e.projectRoot)),n=h(h(o.stories)?.[e.storyId]),a=h(n?.checkpoint);return a?.idempotencyKey===r.idempotencyKey&&a.headSha===r.headSha&&a.bundleDigest===r.bundleDigest&&h(h(o.epics)?.[e.epicId])?.branch_lease===null&&await ke(e.projectRoot,a,e.storyId,e.epicId,e.executionBranch,void 0,e.authorizedWriteSet)}catch{return!1}}async function Xt(e,r,t){try{const o=T(JSON.parse(await B(D(e.projectRoot,".neocortex/state.json"),"utf8"))),n=re(o,await V(e.projectRoot)),a=h(h(n.stories)?.[e.storyId]),c=h(a?.checkpoint);return c?.schemaVersion!==1||c.storyId!==e.storyId||c.epicId!==e.epicId||c.branch!==e.executionBranch||c.baseSha!==t.baseSha||c.headSha!==t.headSha||c.idempotencyKey!==e.dispatchId||c.dispatchId!==e.dispatchId||c.bundleId!==r.bundleId||c.bundleDigest!==r.bundleDigest||c.graphRevision!==e.graphRevision||c.claimRevision!==e.claimRevision||h(h(n.epics)?.[e.epicId])?.branch_lease!==null||!await ke(e.projectRoot,c,e.storyId,e.epicId,e.executionBranch,void 0,e.authorizedWriteSet)?void 0:c}catch{return}}async function er(e,r){const t=(await ee(e.projectRoot,["log","--format=%H","--fixed-strings",`--grep=Neocortex-Dispatch: ${e.dispatchId}`]))?.split(`
55
+ `).filter(S=>/^[a-f0-9]{40,64}$/.test(S))??[];if(t.length!==1)return;const o=t[0];if(!await ae(e.projectRoot,["merge-base","--is-ancestor",o,"HEAD"]))return;const n=await P(e.projectRoot,["show","-s","--format=%B",o]),a=new Set(n.split(`
56
+ `).map(S=>S.trim()));for(const S of[`Neocortex-Story: ${e.storyId}`,`Neocortex-Epic: ${e.epicId}`,`Neocortex-Execution-Branch: ${e.executionBranch}`,`Neocortex-Prepared-Base: ${e.baseSha}`,`Neocortex-Dispatch: ${e.dispatchId}`,`Neocortex-Bundle: ${r.bundleId}`,`Neocortex-Bundle-Digest: ${r.bundleDigest}`,`Neocortex-Graph-Revision: ${e.graphRevision}`,`Neocortex-Claim-Revision: ${e.claimRevision}`])if(!a.has(S))return;const c=Le(n,"Neocortex-Checkpoint-Authority"),i=Le(n,"Neocortex-Checkpoint-Epoch"),d=Le(n,"Neocortex-Checkpoint-Story-Status");if(!c||!/^[a-f0-9]{64}$/.test(c)||!i||!(i==="null"||/^[a-f0-9]{64}$/.test(i))||!d||d.length>80)return;const s=await ee(e.projectRoot,["rev-parse",`${o}^`]);if(!s||!/^[a-f0-9]{40,64}$/.test(s))return;const g=L(await z(e.projectRoot,["diff-tree","--no-commit-id","--name-only","-r","-z",o]));if(!(g.length===0||g.some(S=>!r.authorizedWriteSet.some(v=>Se(v,S)))))return{baseSha:s,headSha:o,checkpointAuthority:{revision:c,epoch:i==="null"?null:i,storyStatus:d==="null"?null:d}}}function Le(e,r){const t=`${r}: `,o=e.split(`
57
+ `).map(n=>n.trim()).filter(n=>n.startsWith(t));return o.length===1?o[0].slice(t.length):void 0}async function We(e,r,t,o,n,a){const c=C(e);await W(c,C(c));try{await F(e,c)}catch(i){if(!q(i,"ENOENT"))throw i}await te(c,$(e),Buffer.from(`${JSON.stringify({childHeadSha:r,rootHeadSha:t,bundle:o,checkpoint:n})}
58
+ `),a),await F(e,c)}export{ur as createAnchoredContinuousStoryCommandRunner,hr as createBranchlessContinuousStoryWorkspaceManager};