@ornexus/neocortex 4.60.68 → 4.60.69

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 (232) hide show
  1. package/dist/release-source.json +1 -1
  2. package/dist/sbom.cdx.json +1194 -1194
  3. package/install.ps1 +1 -1
  4. package/install.sh +1 -1
  5. package/package.json +2 -2
  6. package/packages/client/dist/adapters/adapter-registry.js +1 -108
  7. package/packages/client/dist/adapters/antigravity-adapter.js +2 -77
  8. package/packages/client/dist/adapters/claude-code-adapter.js +3 -79
  9. package/packages/client/dist/adapters/codex-adapter.js +2 -80
  10. package/packages/client/dist/adapters/cursor-adapter.js +4 -115
  11. package/packages/client/dist/adapters/gemini-adapter.js +2 -71
  12. package/packages/client/dist/adapters/grok-adapter.js +2 -42
  13. package/packages/client/dist/adapters/index.js +1 -22
  14. package/packages/client/dist/adapters/platform-detector.js +1 -212
  15. package/packages/client/dist/adapters/target-adapter.js +0 -12
  16. package/packages/client/dist/adapters/vscode-adapter.js +2 -72
  17. package/packages/client/dist/agent/refresh-stubs.js +2 -417
  18. package/packages/client/dist/agent/update-agent-yaml.js +1 -102
  19. package/packages/client/dist/agent/update-description.js +1 -251
  20. package/packages/client/dist/cache/crypto-utils.js +1 -78
  21. package/packages/client/dist/cache/encrypted-cache.js +1 -108
  22. package/packages/client/dist/cache/in-memory-asset-cache.js +1 -73
  23. package/packages/client/dist/cache/index.js +1 -13
  24. package/packages/client/dist/cache/protected-pi-boundary.js +1 -44
  25. package/packages/client/dist/checkpoint/checkpoint-client-reader.js +2 -127
  26. package/packages/client/dist/checkpoint/index.js +1 -11
  27. package/packages/client/dist/checkpoint/shared-checkpoint-types.js +1 -32
  28. package/packages/client/dist/cli.js +3 -290
  29. package/packages/client/dist/commands/activate.js +8 -394
  30. package/packages/client/dist/commands/architecture-answers.js +7 -274
  31. package/packages/client/dist/commands/architecture-memory-terminal.js +4 -253
  32. package/packages/client/dist/commands/architecture-non-ui-continuation.js +1 -100
  33. package/packages/client/dist/commands/architecture-root-binding.js +1 -51
  34. package/packages/client/dist/commands/cache-status.js +2 -112
  35. package/packages/client/dist/commands/config.js +1 -88
  36. package/packages/client/dist/commands/doctor.js +2 -635
  37. package/packages/client/dist/commands/invoke.d.ts +6 -0
  38. package/packages/client/dist/commands/invoke.js +142 -7140
  39. package/packages/client/dist/commands/legacy-epic-terminal.js +1 -71
  40. package/packages/client/dist/commands/legacy-story-branch.js +1 -96
  41. package/packages/client/dist/commands/legacy-story-pr.js +1 -276
  42. package/packages/client/dist/commands/mutation-qa-checkpoint.js +5 -285
  43. package/packages/client/dist/commands/mutation-qa-gate.js +1 -54
  44. package/packages/client/dist/commands/mutation-qa-git.js +1 -41
  45. package/packages/client/dist/commands/mutation-qa-policy.js +1 -102
  46. package/packages/client/dist/commands/mutation-qa-run.js +3 -219
  47. package/packages/client/dist/commands/mutation-qa-verdict.js +1 -149
  48. package/packages/client/dist/commands/mutation-qa.js +1 -220
  49. package/packages/client/dist/commands/native-agent.js +2 -136
  50. package/packages/client/dist/commands/planning-diagnosis.js +1 -43
  51. package/packages/client/dist/commands/planning-generation.js +1 -53
  52. package/packages/client/dist/commands/planning-memory.js +1 -40
  53. package/packages/client/dist/commands/planning-research.js +1 -42
  54. package/packages/client/dist/commands/private-session.js +1 -75
  55. package/packages/client/dist/commands/property-qa.js +1 -139
  56. package/packages/client/dist/commands/qa-control.js +1 -16
  57. package/packages/client/dist/commands/qa-scan-browser-launch.js +1 -55
  58. package/packages/client/dist/commands/qa-scan-browser-route.js +1 -28
  59. package/packages/client/dist/commands/qa-scan-capture.js +5 -663
  60. package/packages/client/dist/commands/qa-scan-discovery.js +3 -376
  61. package/packages/client/dist/commands/qa-scan-review.js +5 -826
  62. package/packages/client/dist/commands/qa-synthetic-backend-capture.js +1 -266
  63. package/packages/client/dist/commands/qa-synthetic-backend-review.js +1 -297
  64. package/packages/client/dist/commands/qa-synthetic-backend.js +2 -340
  65. package/packages/client/dist/commands/qa-synthetic-broker-port.js +1 -85
  66. package/packages/client/dist/commands/qa-synthetic-browser.js +1 -39
  67. package/packages/client/dist/commands/refactor-characterization.js +21 -671
  68. package/packages/client/dist/commands/refactor-commit.js +13 -399
  69. package/packages/client/dist/commands/refactor-control.js +3 -142
  70. package/packages/client/dist/commands/refactor-cpp-assertions.js +3 -93
  71. package/packages/client/dist/commands/refactor-review.js +5 -283
  72. package/packages/client/dist/commands/refactor-root.js +7 -588
  73. package/packages/client/dist/commands/refresh-memory.js +3 -156
  74. package/packages/client/dist/commands/shared-architecture-non-ui.js +1 -24
  75. package/packages/client/dist/commands/story-checkpoint.js +1 -171
  76. package/packages/client/dist/config/profile-directory.js +1 -13
  77. package/packages/client/dist/config/resolver-selection.js +1 -278
  78. package/packages/client/dist/config/secure-config.js +12 -281
  79. package/packages/client/dist/config.js +2 -223
  80. package/packages/client/dist/constants.js +1 -25
  81. package/packages/client/dist/context/context-collector.js +2 -222
  82. package/packages/client/dist/context/context-sanitizer.js +1 -145
  83. package/packages/client/dist/continuity/autonomous-governance.js +1 -285
  84. package/packages/client/dist/continuity/continuity-client-state-store.js +1 -1587
  85. package/packages/client/dist/continuity/invoke-hooks.js +1 -129
  86. package/packages/client/dist/continuity/migrations/001-initial-schema.js +2 -12
  87. package/packages/client/dist/continuity/migrations/002-processing-output-summary-indexes.js +2 -12
  88. package/packages/client/dist/continuity/migrations/003-headless-execution-attempts.js +2 -12
  89. package/packages/client/dist/continuity/migrations/004-outbox-delivery-state.js +2 -12
  90. package/packages/client/dist/continuity/migrations/005-bounded-headless-queue.js +2 -12
  91. package/packages/client/dist/continuity/migrations/006-native-agent-dispatches.js +2 -10
  92. package/packages/client/dist/continuity/native-agent-store.js +1 -69
  93. package/packages/client/dist/continuity/native-agent-types.js +1 -90
  94. package/packages/client/dist/continuity/outbox.js +1 -117
  95. package/packages/client/dist/continuity/runner-bootstrap-policy.js +1 -172
  96. package/packages/client/dist/continuity/sqlite-store.js +81 -2536
  97. package/packages/client/dist/effects/invoke-effect-gateways.js +1 -62
  98. package/packages/client/dist/errors/error-messages.js +2 -228
  99. package/packages/client/dist/errors/frontmatter-diagnostics.js +1 -125
  100. package/packages/client/dist/evidence/collector.js +1 -347
  101. package/packages/client/dist/evidence/index.js +1 -1
  102. package/packages/client/dist/evidence/types.js +0 -2
  103. package/packages/client/dist/fs/atomic-state-replace.js +1 -152
  104. package/packages/client/dist/generated/command-registry.generated.js +1 -4076
  105. package/packages/client/dist/generated/public-projections.generated.js +1 -149
  106. package/packages/client/dist/git/direct-yolo-c01-retry.js +4 -138
  107. package/packages/client/dist/git/direct-yolo-checkpoint.js +4 -1234
  108. package/packages/client/dist/git/git-lifecycle-step-ids.js +1 -14
  109. package/packages/client/dist/git/git-lifecycle-store.js +9 -1938
  110. package/packages/client/dist/git/legacy-story-branch-checkpoint.js +9 -259
  111. package/packages/client/dist/git/legacy-story-branch-setup.js +4 -348
  112. package/packages/client/dist/git/legacy-story-pr.js +70 -3538
  113. package/packages/client/dist/git/secure-filesystem-boundary.js +5 -182
  114. package/packages/client/dist/graph-retrieval/pre-command-hook.js +1 -284
  115. package/packages/client/dist/graph-retrieval/shared-graph-retrieval-contract.js +1 -237
  116. package/packages/client/dist/i18n/first-run.js +2 -60
  117. package/packages/client/dist/index.js +1 -47
  118. package/packages/client/dist/invocation/invoke-input.js +1 -24
  119. package/packages/client/dist/license/index.js +1 -5
  120. package/packages/client/dist/license/license-client.js +1 -304
  121. package/packages/client/dist/machine/fingerprint.js +2 -163
  122. package/packages/client/dist/machine/index.js +1 -5
  123. package/packages/client/dist/memory/project-memory-path-scope.js +1 -62
  124. package/packages/client/dist/memory/project-memory-writer.js +40 -1007
  125. package/packages/client/dist/memory/shared-project-memory-types.js +2 -253
  126. package/packages/client/dist/migrations/project-identity-capability.js +1 -50
  127. package/packages/client/dist/migrations/project-identity.js +7 -493
  128. package/packages/client/dist/migrations/state-json.js +4 -344
  129. package/packages/client/dist/policy/architecture-policy.js +2 -184
  130. package/packages/client/dist/policy/index.js +1 -7
  131. package/packages/client/dist/policy/shared-policy-types.js +0 -38
  132. package/packages/client/dist/policy/subagent-approval-policy.js +1 -55
  133. package/packages/client/dist/private-execution/clean-baseline.js +2 -279
  134. package/packages/client/dist/private-execution/codex-executor.js +4 -574
  135. package/packages/client/dist/private-execution/codex-host-runtime.js +1 -137
  136. package/packages/client/dist/private-execution/codex-lifecycle-guard.js +1 -97
  137. package/packages/client/dist/private-execution/codex-scoped-permissions.js +1 -128
  138. package/packages/client/dist/private-execution/delivery.js +13 -410
  139. package/packages/client/dist/private-execution/diagnosis-root-review.js +2 -294
  140. package/packages/client/dist/private-execution/frozen-handoff.js +6 -19
  141. package/packages/client/dist/private-execution/implementation-validation.js +2 -106
  142. package/packages/client/dist/private-execution/isolated-admission.js +23 -1432
  143. package/packages/client/dist/private-execution/isolated-session.js +5 -725
  144. package/packages/client/dist/private-execution/isolated-workspace.js +1 -122
  145. package/packages/client/dist/private-execution/pact-consumer-runtime.js +3 -409
  146. package/packages/client/dist/private-execution/pact-test-source.js +1 -258
  147. package/packages/client/dist/private-execution/pact-toolchain.js +3 -290
  148. package/packages/client/dist/private-execution/pact-write-set.js +1 -172
  149. package/packages/client/dist/private-execution/planning-diagnosis-checkpoint.js +5 -406
  150. package/packages/client/dist/private-execution/planning-generation-checkpoint.js +5 -462
  151. package/packages/client/dist/private-execution/planning-memory-checkpoint.js +3 -139
  152. package/packages/client/dist/private-execution/planning-research-checkpoint.js +4 -325
  153. package/packages/client/dist/private-execution/private-report-store.js +1 -42
  154. package/packages/client/dist/private-execution/property-test-candidate.js +1 -103
  155. package/packages/client/dist/private-execution/property-test-choices.js +3 -147
  156. package/packages/client/dist/private-execution/property-test-plan.js +7 -271
  157. package/packages/client/dist/private-execution/property-test-review.js +4 -258
  158. package/packages/client/dist/private-execution/property-test-runtime.js +9 -372
  159. package/packages/client/dist/private-execution/property-test-source.js +1 -139
  160. package/packages/client/dist/private-execution/root-checkpoint.js +1 -80
  161. package/packages/client/dist/private-execution/root-memory-git-evidence.js +3 -135
  162. package/packages/client/dist/private-execution/root-memory-recovery.js +1 -93
  163. package/packages/client/dist/private-execution/root-memory-request.js +1 -29
  164. package/packages/client/dist/private-execution/root-memory-scope.js +1 -178
  165. package/packages/client/dist/private-execution/root-memory-writer.js +1 -102
  166. package/packages/client/dist/private-execution/session-lease.js +1 -63
  167. package/packages/client/dist/private-execution/shared-private-admission-types.js +1 -50
  168. package/packages/client/dist/private-execution/shared-project-validation.js +1 -66
  169. package/packages/client/dist/private-execution/shared-root-memory-types.js +1 -61
  170. package/packages/client/dist/private-execution/ux-source-validation.js +1 -372
  171. package/packages/client/dist/private-execution/ux-write-set.js +2 -191
  172. package/packages/client/dist/resilience/circuit-breaker.js +1 -170
  173. package/packages/client/dist/resilience/degradation-manager.js +1 -164
  174. package/packages/client/dist/resilience/freshness-indicator.js +1 -100
  175. package/packages/client/dist/resilience/index.js +1 -8
  176. package/packages/client/dist/resilience/recovery-detector.js +1 -74
  177. package/packages/client/dist/resolvers/asset-resolver.js +0 -13
  178. package/packages/client/dist/resolvers/local-resolver.js +8 -255
  179. package/packages/client/dist/resolvers/remote-resolver.js +1 -233
  180. package/packages/client/dist/runner/binary.js +1 -404
  181. package/packages/client/dist/runner/cli.js +17 -1571
  182. package/packages/client/dist/runner/headless/adapters.js +1 -49
  183. package/packages/client/dist/runner/headless/claude-code-adapter.js +1 -79
  184. package/packages/client/dist/runner/headless/continuous-story-workspace.js +11 -1628
  185. package/packages/client/dist/runner/headless/epic-git-reconciliation-inventory.js +1 -69
  186. package/packages/client/dist/runner/headless/epic-merge-candidate-qa.js +2 -110
  187. package/packages/client/dist/runner/headless/epic-terminal-git-cli-adapter.js +8 -1236
  188. package/packages/client/dist/runner/headless/epic-terminal-git-runner.js +2 -318
  189. package/packages/client/dist/runner/headless/fake-adapter.js +1 -62
  190. package/packages/client/dist/runner/headless/managed-profile.js +1 -132
  191. package/packages/client/dist/runner/headless/opencode-adapter.js +2 -145
  192. package/packages/client/dist/runner/headless/prepared-story-bundle.js +1 -43
  193. package/packages/client/dist/runner/headless/resolver.js +1 -231
  194. package/packages/client/dist/runner/headless/run-yolo.js +1 -885
  195. package/packages/client/dist/runner/headless/run-yoloop.js +2 -2574
  196. package/packages/client/dist/runner/headless/types.js +2 -574
  197. package/packages/client/dist/runner/local-console.js +13 -396
  198. package/packages/client/dist/runner/portal-sync-worker.js +1 -1487
  199. package/packages/client/dist/runner/project-identity.js +1 -106
  200. package/packages/client/dist/runner/scheduler.js +7 -995
  201. package/packages/client/dist/runner-cli.js +2 -18
  202. package/packages/client/dist/state/invocation-shape.js +1 -13
  203. package/packages/client/dist/state/project-state-snapshot.js +1 -1677
  204. package/packages/client/dist/state/state-json-repair.js +3 -785
  205. package/packages/client/dist/state/structural-dag-projection.js +1 -118
  206. package/packages/client/dist/telemetry/index.js +1 -5
  207. package/packages/client/dist/telemetry/offline-queue.js +1 -131
  208. package/packages/client/dist/tier/index.js +1 -5
  209. package/packages/client/dist/tier/tier-aware-client.js +1 -405
  210. package/packages/client/dist/types/index.js +1 -38
  211. package/packages/client/dist/version.js +1 -27
  212. package/packages/client/dist/yolo/change-evidence-collector.js +1 -126
  213. package/packages/client/dist/yolo/invoke-envelope-capability.js +1 -62
  214. package/packages/client/dist/yolo/spec-envelope-collector.js +5 -185
  215. package/packages/client/dist/yoloop/discovery-hook.js +2 -300
  216. package/packages/client/dist/yoloop/index.js +1 -8
  217. package/packages/client/dist/yoloop/invoke-hooks.js +12 -669
  218. package/packages/client/dist/yoloop/shared-discover-epics.js +1 -1007
  219. package/packages/client/dist/yoloop/shared-yoloop-types.js +1 -33
  220. package/packages/client/dist/yoloop/target-normalization.js +1 -180
  221. package/packages/client/dist/yoloop/yoloop-client-state-store.js +1 -1723
  222. package/targets-stubs/antigravity/gemini.md +1 -1
  223. package/targets-stubs/antigravity/skill/SKILL.md +1 -1
  224. package/targets-stubs/claude-code/neocortex-root.agent.yaml +1 -1
  225. package/targets-stubs/claude-code/neocortex-root.md +2 -2
  226. package/targets-stubs/claude-code/neocortex.agent.yaml +1 -1
  227. package/targets-stubs/claude-code/neocortex.md +2 -2
  228. package/targets-stubs/codex/AGENTS.md +1 -1
  229. package/targets-stubs/cursor/agent.md +2 -2
  230. package/targets-stubs/gemini-cli/agent.md +2 -2
  231. package/targets-stubs/opencode/neocortex-root.md +1 -1
  232. package/targets-stubs/vscode/neocortex.agent.md +2 -2
@@ -1,493 +1,7 @@
1
- import { createHash, randomUUID } from 'node:crypto';
2
- import { existsSync, linkSync, lstatSync, mkdirSync, readFileSync, realpathSync, statSync, unlinkSync, } from 'node:fs';
3
- import { dirname, join, relative, resolve } from 'node:path';
4
- import { assertProjectIdentityMigrationReceiptV1, PROJECT_ID_PATTERN, } from '../../../shared/dist/invocation/index.js';
5
- import { atomicReplaceUtf8, durableCreateUtf8, fsyncDirectoryBestEffort, recoverAtomicReplaceUtf8, } from '../fs/atomic-state-replace.js';
6
- const MIGRATION_SCHEMA_VERSION = 1;
7
- const STATE_RELATIVE_PATH = join('.neocortex', 'state.json');
8
- const MIGRATION_RELATIVE_PATH = join('.neocortex', 'project-identity-migration.json');
9
- const LOCK_RELATIVE_PATH = join('.neocortex', 'project-identity-migration.lock');
10
- const BACKUP_PATH_PATTERN = /^\.neocortex[\\/]state\.json\.project-identity-backup-(?:\d{8}T\d{9}Z-)?mig_[a-f0-9]{32}$/;
11
- export class ProjectIdentityMigrationError extends Error {
12
- code;
13
- constructor(code, message = code) {
14
- super(message);
15
- this.code = code;
16
- this.name = 'ProjectIdentityMigrationError';
17
- }
18
- }
19
- const sha256 = (value) => createHash('sha256').update(value).digest('hex');
20
- function projectId() {
21
- return `prj_${randomUUID().replaceAll('-', '')}`;
22
- }
23
- function operationId() {
24
- return `mig_${randomUUID().replaceAll('-', '')}`;
25
- }
26
- function backupTimestamp(date) {
27
- return date.toISOString().replace(/[-:.]/g, '');
28
- }
29
- function assertSafeProjectRoot(projectRoot) {
30
- const resolved = resolve(projectRoot);
31
- let canonical;
32
- try {
33
- canonical = realpathSync(resolved);
34
- }
35
- catch {
36
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_ROOT_INVALID');
37
- }
38
- if (!statSync(canonical).isDirectory()) {
39
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_ROOT_INVALID');
40
- }
41
- const ncPath = join(canonical, '.neocortex');
42
- if (existsSync(ncPath) && lstatSync(ncPath).isSymbolicLink()) {
43
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_SYMLINK_REJECTED');
44
- }
45
- const statePath = join(canonical, STATE_RELATIVE_PATH);
46
- if (existsSync(statePath)) {
47
- const stateStat = lstatSync(statePath);
48
- if (stateStat.isSymbolicLink() || !stateStat.isFile()) {
49
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_SYMLINK_REJECTED');
50
- }
51
- }
52
- const migrationPath = join(canonical, MIGRATION_RELATIVE_PATH);
53
- if (existsSync(migrationPath)) {
54
- const migrationStat = lstatSync(migrationPath);
55
- if (migrationStat.isSymbolicLink() || !migrationStat.isFile()) {
56
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_SYMLINK_REJECTED');
57
- }
58
- }
59
- return canonical;
60
- }
61
- function withMigrationLock(root, operation) {
62
- const lockPath = join(root, LOCK_RELATIVE_PATH);
63
- mkdirSync(dirname(lockPath), { recursive: true, mode: 0o700 });
64
- const claimLock = () => {
65
- const ownerPath = `${lockPath}.${process.pid}.${randomUUID()}.owner`;
66
- durableCreateUtf8(ownerPath, `${process.pid}\n`);
67
- try {
68
- // The hard link is an atomic no-overwrite claim. Because its source was
69
- // fsynced first, a canonical lock can never exist with empty metadata.
70
- linkSync(ownerPath, lockPath);
71
- fsyncDirectoryBestEffort(dirname(lockPath));
72
- }
73
- finally {
74
- try {
75
- unlinkSync(ownerPath);
76
- }
77
- catch { /* orphan owner files do not grant the lock */ }
78
- fsyncDirectoryBestEffort(dirname(lockPath));
79
- }
80
- };
81
- try {
82
- claimLock();
83
- }
84
- catch (error) {
85
- if (error.code !== 'EEXIST') {
86
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_LOCKED');
87
- }
88
- const lockStat = lstatSync(lockPath);
89
- if (lockStat.isSymbolicLink() || !lockStat.isFile()) {
90
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_SYMLINK_REJECTED');
91
- }
92
- const rawOwner = readFileSync(lockPath, 'utf8');
93
- if (!/^[1-9][0-9]*\n$/.test(rawOwner) || rawOwner.length > 24) {
94
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_LOCK_CORRUPT');
95
- }
96
- const ownerPid = Number(rawOwner.trim());
97
- let ownerAlive = true;
98
- try {
99
- process.kill(ownerPid, 0);
100
- }
101
- catch (probeError) {
102
- ownerAlive = probeError.code !== 'ESRCH';
103
- }
104
- if (ownerAlive)
105
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_LOCKED');
106
- try {
107
- unlinkSync(lockPath);
108
- fsyncDirectoryBestEffort(dirname(lockPath));
109
- claimLock();
110
- }
111
- catch {
112
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_LOCKED');
113
- }
114
- }
115
- try {
116
- return operation();
117
- }
118
- finally {
119
- try {
120
- unlinkSync(lockPath);
121
- fsyncDirectoryBestEffort(dirname(lockPath));
122
- }
123
- catch { /* lock cleanup is best effort */ }
124
- }
125
- }
126
- function parseState(raw) {
127
- let parsed;
128
- try {
129
- parsed = JSON.parse(raw);
130
- }
131
- catch {
132
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_STATE_CORRUPT');
133
- }
134
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
135
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_STATE_CORRUPT');
136
- }
137
- return parsed;
138
- }
139
- function readDocument(root) {
140
- const path = join(root, MIGRATION_RELATIVE_PATH);
141
- try {
142
- recoverAtomicReplaceUtf8(path);
143
- recoverAtomicReplaceUtf8(join(root, STATE_RELATIVE_PATH));
144
- }
145
- catch {
146
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_ATOMIC_RECOVERY_FAILED');
147
- }
148
- if (!existsSync(path))
149
- return null;
150
- let parsed;
151
- try {
152
- parsed = JSON.parse(readFileSync(path, 'utf8'));
153
- }
154
- catch {
155
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT');
156
- }
157
- if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) {
158
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT');
159
- }
160
- const document = parsed;
161
- if (document.schemaVersion !== 1
162
- || typeof document.operationId !== 'string'
163
- || !/^mig_[a-f0-9]{32}$/.test(document.operationId)
164
- || typeof document.projectId !== 'string'
165
- || !PROJECT_ID_PATTERN.test(document.projectId)
166
- || !['prepared', 'remote-acknowledged', 'finalized'].includes(String(document.phase))
167
- || !Number.isSafeInteger(document.legacyEpicFloor)
168
- || (document.legacyEpicFloor ?? -1) < 0
169
- || typeof document.originalStateExists !== 'boolean'
170
- || typeof document.originalStateDigest !== 'string'
171
- || !/^[a-f0-9]{64}$/.test(document.originalStateDigest)
172
- || typeof document.preparedStateDigest !== 'string'
173
- || !/^[a-f0-9]{64}$/.test(document.preparedStateDigest)
174
- || (document.backupPath !== null
175
- && (typeof document.backupPath !== 'string' || !BACKUP_PATH_PATTERN.test(document.backupPath)))
176
- || typeof document.createdAt !== 'string'
177
- || typeof document.updatedAt !== 'string') {
178
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT');
179
- }
180
- if (document.receipt !== undefined)
181
- assertProjectIdentityMigrationReceiptV1(document.receipt);
182
- const phaseRequiresReceipt = document.phase === 'remote-acknowledged' || document.phase === 'finalized';
183
- if ((document.phase === 'prepared' && document.receipt !== undefined)
184
- || (phaseRequiresReceipt && document.receipt === undefined)
185
- || (document.receipt !== undefined
186
- && (document.receipt.operationId !== document.operationId
187
- || document.receipt.projectId !== document.projectId
188
- || document.receipt.acceptedLegacyFloor < document.legacyEpicFloor))) {
189
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT');
190
- }
191
- return document;
192
- }
193
- function legacyEpicFloor(state) {
194
- const candidates = [];
195
- if (state.epics && typeof state.epics === 'object' && !Array.isArray(state.epics)) {
196
- candidates.push(...Object.keys(state.epics));
197
- }
198
- const ledger = state.epic_id_ledger;
199
- if (ledger && typeof ledger === 'object' && !Array.isArray(ledger)) {
200
- const ids = ledger.reserved_ids;
201
- if (Array.isArray(ids))
202
- candidates.push(...ids.filter((value) => typeof value === 'string'));
203
- }
204
- return candidates.reduce((floor, candidate) => {
205
- const match = candidate.match(/^P?(\d+)$/i);
206
- if (!match)
207
- return floor;
208
- const value = Number(match[1]);
209
- return Number.isSafeInteger(value) ? Math.max(floor, value) : floor;
210
- }, 0);
211
- }
212
- function requestFor(document) {
213
- return {
214
- version: 1,
215
- operationId: document.operationId,
216
- projectId: document.projectId,
217
- localStateDigest: document.preparedStateDigest,
218
- legacyEpicFloor: document.legacyEpicFloor,
219
- phase: 'seed',
220
- };
221
- }
222
- function stateWithProjectIdentity(raw, identity) {
223
- const state = parseState(raw);
224
- const configKey = projectIdentityContainerKey(state);
225
- const config = (state[configKey] ?? {});
226
- state[configKey] = { ...config, project_id: identity };
227
- if (state.schema_version === undefined)
228
- state.schema_version = 1;
229
- if (!state.stories || typeof state.stories !== 'object' || Array.isArray(state.stories))
230
- state.stories = {};
231
- if (!state.epics || typeof state.epics !== 'object' || Array.isArray(state.epics))
232
- state.epics = {};
233
- return { raw: `${JSON.stringify(state, null, 2)}\n`, state };
234
- }
235
- function projectIdentityContainerKey(state) {
236
- return state.config && typeof state.config === 'object' && !Array.isArray(state.config)
237
- ? 'config'
238
- : state.project && typeof state.project === 'object' && !Array.isArray(state.project)
239
- ? 'project'
240
- : 'config';
241
- }
242
- function projectIdentityFromState(state) {
243
- const container = state[projectIdentityContainerKey(state)];
244
- return container && typeof container === 'object' && !Array.isArray(container)
245
- ? container.project_id
246
- : undefined;
247
- }
248
- function assertFinalizedStateIdentity(statePath, document) {
249
- if (!existsSync(statePath)) {
250
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
251
- }
252
- const state = parseState(readFileSync(statePath, 'utf8'));
253
- if (projectIdentityFromState(state) !== document.projectId) {
254
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
255
- }
256
- }
257
- function reconcileFinalizedStateIdentity(root, statePath, currentRaw, document) {
258
- const state = parseState(currentRaw);
259
- const currentProjectId = projectIdentityFromState(state);
260
- if (currentProjectId === document.projectId)
261
- return;
262
- if (currentProjectId !== undefined) {
263
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
264
- }
265
- const now = new Date();
266
- const recoveryBackup = join(root, '.neocortex', `state.json.project-identity-reconcile-backup-${backupTimestamp(now)}-${operationId()}`);
267
- durableCreateUtf8(recoveryBackup, currentRaw);
268
- atomicReplaceUtf8(statePath, stateWithProjectIdentity(currentRaw, document.projectId).raw);
269
- }
270
- function defaultStateRaw() {
271
- return `${JSON.stringify({
272
- schema_version: 1,
273
- config: { project_name: 'neocortex-project', default_branch: 'main', language: 'pt-BR' },
274
- stories: {},
275
- epics: {},
276
- }, null, 2)}\n`;
277
- }
278
- function verifyBackup(root, document) {
279
- if (!document.originalStateExists)
280
- return;
281
- if (!document.backupPath) {
282
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING');
283
- }
284
- const backup = join(root, document.backupPath);
285
- if (!existsSync(backup)) {
286
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING');
287
- }
288
- const backupStat = lstatSync(backup);
289
- if (backupStat.isSymbolicLink() || !backupStat.isFile()) {
290
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_SYMLINK_REJECTED');
291
- }
292
- if (sha256(readFileSync(backup)) !== document.originalStateDigest) {
293
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_BACKUP_CORRUPT');
294
- }
295
- }
296
- export function prepareProjectIdentityMigration(projectRoot) {
297
- const root = assertSafeProjectRoot(projectRoot);
298
- return withMigrationLock(root, () => {
299
- const existingDocument = readDocument(root);
300
- if (existingDocument) {
301
- const statePath = join(root, STATE_RELATIVE_PATH);
302
- verifyBackup(root, existingDocument);
303
- const stateExists = existsSync(statePath);
304
- const currentRaw = stateExists ? readFileSync(statePath, 'utf8') : null;
305
- const currentDigest = currentRaw === null ? null : sha256(currentRaw);
306
- if (currentDigest === existingDocument.preparedStateDigest) {
307
- return { changed: false, document: existingDocument, request: requestFor(existingDocument) };
308
- }
309
- if (existingDocument.phase === 'finalized' && currentRaw !== null) {
310
- const currentProjectId = projectIdentityFromState(parseState(currentRaw));
311
- if (currentProjectId === existingDocument.projectId) {
312
- return { changed: false, document: existingDocument, request: requestFor(existingDocument) };
313
- }
314
- reconcileFinalizedStateIdentity(root, statePath, currentRaw, existingDocument);
315
- return { changed: true, document: existingDocument, request: requestFor(existingDocument) };
316
- }
317
- const mayResumePrepare = existingDocument.phase === 'prepared'
318
- && ((stateExists && currentDigest === existingDocument.originalStateDigest)
319
- || (!stateExists && !existingDocument.originalStateExists));
320
- if (!mayResumePrepare) {
321
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
322
- }
323
- const originalRaw = stateExists ? readFileSync(statePath, 'utf8') : defaultStateRaw();
324
- const recovered = stateWithProjectIdentity(originalRaw, existingDocument.projectId).raw;
325
- if (sha256(recovered) !== existingDocument.preparedStateDigest) {
326
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
327
- }
328
- atomicReplaceUtf8(statePath, recovered);
329
- return { changed: true, document: existingDocument, request: requestFor(existingDocument) };
330
- }
331
- const statePath = join(root, STATE_RELATIVE_PATH);
332
- const originalStateExists = existsSync(statePath);
333
- const originalRaw = originalStateExists ? readFileSync(statePath, 'utf8') : defaultStateRaw();
334
- const state = parseState(originalRaw);
335
- const configKey = projectIdentityContainerKey(state);
336
- const config = (state[configKey] ?? {});
337
- const currentProjectId = config.project_id;
338
- const nextProjectId = typeof currentProjectId === 'string' && PROJECT_ID_PATTERN.test(currentProjectId)
339
- ? currentProjectId
340
- : projectId();
341
- const preparedState = stateWithProjectIdentity(originalRaw, nextProjectId);
342
- const nextRaw = preparedState.raw;
343
- const nextOperationId = operationId();
344
- const nowDate = new Date();
345
- const backupPath = originalStateExists
346
- ? join('.neocortex', `state.json.project-identity-backup-${backupTimestamp(nowDate)}-${nextOperationId}`)
347
- : null;
348
- if (backupPath) {
349
- durableCreateUtf8(join(root, backupPath), originalRaw);
350
- }
351
- const now = nowDate.toISOString();
352
- const document = {
353
- schemaVersion: 1,
354
- operationId: nextOperationId,
355
- projectId: nextProjectId,
356
- phase: 'prepared',
357
- legacyEpicFloor: legacyEpicFloor(preparedState.state),
358
- originalStateExists,
359
- originalStateDigest: sha256(originalRaw),
360
- preparedStateDigest: sha256(nextRaw),
361
- backupPath,
362
- createdAt: now,
363
- updatedAt: now,
364
- };
365
- // Persist the recovery manifest before replacing state. If the process dies
366
- // in this window, the next prepare deterministically applies the same ID.
367
- atomicReplaceUtf8(join(root, MIGRATION_RELATIVE_PATH), `${JSON.stringify(document, null, 2)}\n`);
368
- atomicReplaceUtf8(statePath, nextRaw);
369
- return { changed: nextRaw !== originalRaw, document, request: requestFor(document) };
370
- });
371
- }
372
- export function finalizeProjectIdentityMigration(projectRoot, receipt) {
373
- assertProjectIdentityMigrationReceiptV1(receipt);
374
- const root = assertSafeProjectRoot(projectRoot);
375
- return withMigrationLock(root, () => {
376
- const document = readDocument(root);
377
- if (!document)
378
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_NOT_PREPARED');
379
- if (document.operationId !== receipt.operationId || document.projectId !== receipt.projectId) {
380
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_RECEIPT_CONFLICT');
381
- }
382
- const statePath = join(root, STATE_RELATIVE_PATH);
383
- if (document.phase === 'finalized') {
384
- if (!document.receipt || document.receipt.receiptDigest !== receipt.receiptDigest) {
385
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_ACK_REQUIRED');
386
- }
387
- assertFinalizedStateIdentity(statePath, document);
388
- return document;
389
- }
390
- if (!existsSync(statePath) || sha256(readFileSync(statePath)) !== document.preparedStateDigest) {
391
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
392
- }
393
- if (document.phase === 'prepared' || !document.receipt
394
- || document.receipt.receiptDigest !== receipt.receiptDigest) {
395
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_ACK_REQUIRED');
396
- }
397
- const next = {
398
- ...document,
399
- phase: 'finalized',
400
- updatedAt: new Date().toISOString(),
401
- receipt,
402
- };
403
- atomicReplaceUtf8(join(root, MIGRATION_RELATIVE_PATH), `${JSON.stringify(next, null, 2)}\n`);
404
- return next;
405
- });
406
- }
407
- /** Persist the authenticated ACK before local finalization so a crash is reconcilable. */
408
- export function acknowledgeProjectIdentityMigration(projectRoot, receipt) {
409
- assertProjectIdentityMigrationReceiptV1(receipt);
410
- const root = assertSafeProjectRoot(projectRoot);
411
- return withMigrationLock(root, () => {
412
- const document = readDocument(root);
413
- if (!document)
414
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_NOT_PREPARED');
415
- if (document.operationId !== receipt.operationId || document.projectId !== receipt.projectId) {
416
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_RECEIPT_CONFLICT');
417
- }
418
- if (document.receipt && document.receipt.receiptDigest !== receipt.receiptDigest) {
419
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_RECEIPT_CONFLICT');
420
- }
421
- const statePath = join(root, STATE_RELATIVE_PATH);
422
- if (document.phase === 'finalized') {
423
- assertFinalizedStateIdentity(statePath, document);
424
- return document;
425
- }
426
- if (!existsSync(statePath) || sha256(readFileSync(statePath)) !== document.preparedStateDigest) {
427
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
428
- }
429
- if (document.phase === 'remote-acknowledged')
430
- return document;
431
- const next = {
432
- ...document,
433
- phase: 'remote-acknowledged',
434
- updatedAt: new Date().toISOString(),
435
- receipt,
436
- };
437
- atomicReplaceUtf8(join(root, MIGRATION_RELATIVE_PATH), `${JSON.stringify(next, null, 2)}\n`);
438
- return next;
439
- });
440
- }
441
- export function rollbackPreparedProjectIdentityMigration(projectRoot) {
442
- const root = assertSafeProjectRoot(projectRoot);
443
- withMigrationLock(root, () => {
444
- const document = readDocument(root);
445
- if (!document)
446
- return;
447
- if (document.phase !== 'prepared' || document.receipt) {
448
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_ROLLBACK_AFTER_ACK_DENIED');
449
- }
450
- const statePath = join(root, STATE_RELATIVE_PATH);
451
- if (!existsSync(statePath) || sha256(readFileSync(statePath)) !== document.preparedStateDigest) {
452
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_STATE_DRIFT');
453
- }
454
- if (document.originalStateExists) {
455
- if (!document.backupPath)
456
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING');
457
- const backup = join(root, document.backupPath);
458
- if (!existsSync(backup))
459
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING');
460
- const backupStat = lstatSync(backup);
461
- if (backupStat.isSymbolicLink() || !backupStat.isFile()) {
462
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_SYMLINK_REJECTED');
463
- }
464
- const originalRaw = readFileSync(backup, 'utf8');
465
- if (sha256(originalRaw) !== document.originalStateDigest) {
466
- throw new ProjectIdentityMigrationError('PROJECT_IDENTITY_MIGRATION_BACKUP_CORRUPT');
467
- }
468
- atomicReplaceUtf8(statePath, originalRaw);
469
- }
470
- else {
471
- unlinkSync(statePath);
472
- fsyncDirectoryBestEffort(dirname(statePath));
473
- }
474
- const migrationPath = join(root, MIGRATION_RELATIVE_PATH);
475
- unlinkSync(migrationPath);
476
- fsyncDirectoryBestEffort(dirname(migrationPath));
477
- });
478
- }
479
- /**
480
- * Read-only admission check used to prevent create-epic from observing the
481
- * locally prepared project ID before its remote floor has been acknowledged.
482
- */
483
- export function readProjectIdentityMigrationPhase(projectRoot) {
484
- const root = assertSafeProjectRoot(projectRoot);
485
- return readDocument(root)?.phase ?? null;
486
- }
487
- export function projectIdentityMigrationRelativePaths(projectRoot) {
488
- const root = assertSafeProjectRoot(projectRoot);
489
- return {
490
- state: relative(root, join(root, STATE_RELATIVE_PATH)),
491
- migration: relative(root, join(root, MIGRATION_RELATIVE_PATH)),
492
- };
493
- }
1
+ import{createHash as tt,randomUUID as M}from"node:crypto";import{existsSync as I,linkSync as et,lstatSync as R,mkdirSync as rt,readFileSync as T,realpathSync as nt,statSync as ot,unlinkSync as w}from"node:fs";import{dirname as f,join as a,relative as V,resolve as it}from"node:path";import{assertProjectIdentityMigrationReceiptV1 as Y,PROJECT_ID_PATTERN as z}from"../../../shared/dist/invocation/index.js";import{atomicReplaceUtf8 as d,durableCreateUtf8 as b,fsyncDirectoryBestEffort as l,recoverAtomicReplaceUtf8 as q}from"../fs/atomic-state-replace.js";const Ot=1,E=a(".neocortex","state.json"),u=a(".neocortex","project-identity-migration.json"),ct=a(".neocortex","project-identity-migration.lock"),at=/^\.neocortex[\\/]state\.json\.project-identity-backup-(?:\d{8}T\d{9}Z-)?mig_[a-f0-9]{32}$/;class o extends Error{code;constructor(r,t=r){super(t),this.code=r,this.name="ProjectIdentityMigrationError"}}const p=n=>tt("sha256").update(n).digest("hex");function st(){return`prj_${M().replaceAll("-","")}`}function H(){return`mig_${M().replaceAll("-","")}`}function Q(n){return n.toISOString().replace(/[-:.]/g,"")}function O(n){const r=it(n);let t;try{t=nt(r)}catch{throw new o("PROJECT_IDENTITY_ROOT_INVALID")}if(!ot(t).isDirectory())throw new o("PROJECT_IDENTITY_ROOT_INVALID");const e=a(t,".neocortex");if(I(e)&&R(e).isSymbolicLink())throw new o("PROJECT_IDENTITY_SYMLINK_REJECTED");const i=a(t,E);if(I(i)){const s=R(i);if(s.isSymbolicLink()||!s.isFile())throw new o("PROJECT_IDENTITY_SYMLINK_REJECTED")}const c=a(t,u);if(I(c)){const s=R(c);if(s.isSymbolicLink()||!s.isFile())throw new o("PROJECT_IDENTITY_SYMLINK_REJECTED")}return t}function S(n,r){const t=a(n,ct);rt(f(t),{recursive:!0,mode:448});const e=()=>{const i=`${t}.${process.pid}.${M()}.owner`;b(i,`${process.pid}
2
+ `);try{et(i,t),l(f(t))}finally{try{w(i)}catch{}l(f(t))}};try{e()}catch(i){if(i.code!=="EEXIST")throw new o("PROJECT_IDENTITY_MIGRATION_LOCKED");const c=R(t);if(c.isSymbolicLink()||!c.isFile())throw new o("PROJECT_IDENTITY_SYMLINK_REJECTED");const s=T(t,"utf8");if(!/^[1-9][0-9]*\n$/.test(s)||s.length>24)throw new o("PROJECT_IDENTITY_MIGRATION_LOCK_CORRUPT");const _=Number(s.trim());let C=!0;try{process.kill(_,0)}catch(g){C=g.code!=="ESRCH"}if(C)throw new o("PROJECT_IDENTITY_MIGRATION_LOCKED");try{w(t),l(f(t)),e()}catch{throw new o("PROJECT_IDENTITY_MIGRATION_LOCKED")}}try{return r()}finally{try{w(t),l(f(t))}catch{}}}function y(n){let r;try{r=JSON.parse(n)}catch{throw new o("PROJECT_IDENTITY_STATE_CORRUPT")}if(!r||typeof r!="object"||Array.isArray(r))throw new o("PROJECT_IDENTITY_STATE_CORRUPT");return r}function A(n){const r=a(n,u);try{q(r),q(a(n,E))}catch{throw new o("PROJECT_IDENTITY_ATOMIC_RECOVERY_FAILED")}if(!I(r))return null;let t;try{t=JSON.parse(T(r,"utf8"))}catch{throw new o("PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT")}if(!t||typeof t!="object"||Array.isArray(t))throw new o("PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT");const e=t;if(e.schemaVersion!==1||typeof e.operationId!="string"||!/^mig_[a-f0-9]{32}$/.test(e.operationId)||typeof e.projectId!="string"||!z.test(e.projectId)||!["prepared","remote-acknowledged","finalized"].includes(String(e.phase))||!Number.isSafeInteger(e.legacyEpicFloor)||(e.legacyEpicFloor??-1)<0||typeof e.originalStateExists!="boolean"||typeof e.originalStateDigest!="string"||!/^[a-f0-9]{64}$/.test(e.originalStateDigest)||typeof e.preparedStateDigest!="string"||!/^[a-f0-9]{64}$/.test(e.preparedStateDigest)||e.backupPath!==null&&(typeof e.backupPath!="string"||!at.test(e.backupPath))||typeof e.createdAt!="string"||typeof e.updatedAt!="string")throw new o("PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT");e.receipt!==void 0&&Y(e.receipt);const i=e.phase==="remote-acknowledged"||e.phase==="finalized";if(e.phase==="prepared"&&e.receipt!==void 0||i&&e.receipt===void 0||e.receipt!==void 0&&(e.receipt.operationId!==e.operationId||e.receipt.projectId!==e.projectId||e.receipt.acceptedLegacyFloor<e.legacyEpicFloor))throw new o("PROJECT_IDENTITY_MIGRATION_STATE_CORRUPT");return e}function It(n){const r=[];n.epics&&typeof n.epics=="object"&&!Array.isArray(n.epics)&&r.push(...Object.keys(n.epics));const t=n.epic_id_ledger;if(t&&typeof t=="object"&&!Array.isArray(t)){const e=t.reserved_ids;Array.isArray(e)&&r.push(...e.filter(i=>typeof i=="string"))}return r.reduce((e,i)=>{const c=i.match(/^P?(\d+)$/i);if(!c)return e;const s=Number(c[1]);return Number.isSafeInteger(s)?Math.max(e,s):e},0)}function N(n){return{version:1,operationId:n.operationId,projectId:n.projectId,localStateDigest:n.preparedStateDigest,legacyEpicFloor:n.legacyEpicFloor,phase:"seed"}}function k(n,r){const t=y(n),e=G(t),i=t[e]??{};return t[e]={...i,project_id:r},t.schema_version===void 0&&(t.schema_version=1),(!t.stories||typeof t.stories!="object"||Array.isArray(t.stories))&&(t.stories={}),(!t.epics||typeof t.epics!="object"||Array.isArray(t.epics))&&(t.epics={}),{raw:`${JSON.stringify(t,null,2)}
3
+ `,state:t}}function G(n){return n.config&&typeof n.config=="object"&&!Array.isArray(n.config)?"config":n.project&&typeof n.project=="object"&&!Array.isArray(n.project)?"project":"config"}function x(n){const r=n[G(n)];return r&&typeof r=="object"&&!Array.isArray(r)?r.project_id:void 0}function W(n,r){if(!I(n))throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");const t=y(T(n,"utf8"));if(x(t)!==r.projectId)throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT")}function Tt(n,r,t,e){const i=y(t),c=x(i);if(c===e.projectId)return;if(c!==void 0)throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");const _=a(n,".neocortex",`state.json.project-identity-reconcile-backup-${Q(new Date)}-${H()}`);b(_,t),d(r,k(t,e.projectId).raw)}function X(){return`${JSON.stringify({schema_version:1,config:{project_name:"neocortex-project",default_branch:"main",language:"pt-BR"},stories:{},epics:{}},null,2)}
4
+ `}function pt(n,r){if(!r.originalStateExists)return;if(!r.backupPath)throw new o("PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING");const t=a(n,r.backupPath);if(!I(t))throw new o("PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING");const e=R(t);if(e.isSymbolicLink()||!e.isFile())throw new o("PROJECT_IDENTITY_SYMLINK_REJECTED");if(p(T(t))!==r.originalStateDigest)throw new o("PROJECT_IDENTITY_MIGRATION_BACKUP_CORRUPT")}function gt(n){const r=O(n);return S(r,()=>{const t=A(r);if(t){const h=a(r,E);pt(r,t);const D=I(h),P=D?T(h,"utf8"):null,v=P===null?null:p(P);if(v===t.preparedStateDigest)return{changed:!1,document:t,request:N(t)};if(t.phase==="finalized"&&P!==null)return x(y(P))===t.projectId?{changed:!1,document:t,request:N(t)}:(Tt(r,h,P,t),{changed:!0,document:t,request:N(t)});if(!(t.phase==="prepared"&&(D&&v===t.originalStateDigest||!D&&!t.originalStateExists)))throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");const Z=D?T(h,"utf8"):X(),B=k(Z,t.projectId).raw;if(p(B)!==t.preparedStateDigest)throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");return d(h,B),{changed:!0,document:t,request:N(t)}}const e=a(r,E),i=I(e),c=i?T(e,"utf8"):X(),s=y(c),_=G(s),g=(s[_]??{}).project_id,F=typeof g=="string"&&z.test(g)?g:st(),L=k(c,F),j=L.raw,K=H(),U=new Date,m=i?a(".neocortex",`state.json.project-identity-backup-${Q(U)}-${K}`):null;m&&b(a(r,m),c);const $=U.toISOString(),J={schemaVersion:1,operationId:K,projectId:F,phase:"prepared",legacyEpicFloor:It(L.state),originalStateExists:i,originalStateDigest:p(c),preparedStateDigest:p(j),backupPath:m,createdAt:$,updatedAt:$};return d(a(r,u),`${JSON.stringify(J,null,2)}
5
+ `),d(e,j),{changed:j!==c,document:J,request:N(J)}})}function ht(n,r){Y(r);const t=O(n);return S(t,()=>{const e=A(t);if(!e)throw new o("PROJECT_IDENTITY_MIGRATION_NOT_PREPARED");if(e.operationId!==r.operationId||e.projectId!==r.projectId)throw new o("PROJECT_IDENTITY_MIGRATION_RECEIPT_CONFLICT");const i=a(t,E);if(e.phase==="finalized"){if(!e.receipt||e.receipt.receiptDigest!==r.receiptDigest)throw new o("PROJECT_IDENTITY_MIGRATION_ACK_REQUIRED");return W(i,e),e}if(!I(i)||p(T(i))!==e.preparedStateDigest)throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");if(e.phase==="prepared"||!e.receipt||e.receipt.receiptDigest!==r.receiptDigest)throw new o("PROJECT_IDENTITY_MIGRATION_ACK_REQUIRED");const c={...e,phase:"finalized",updatedAt:new Date().toISOString(),receipt:r};return d(a(t,u),`${JSON.stringify(c,null,2)}
6
+ `),c})}function Pt(n,r){Y(r);const t=O(n);return S(t,()=>{const e=A(t);if(!e)throw new o("PROJECT_IDENTITY_MIGRATION_NOT_PREPARED");if(e.operationId!==r.operationId||e.projectId!==r.projectId)throw new o("PROJECT_IDENTITY_MIGRATION_RECEIPT_CONFLICT");if(e.receipt&&e.receipt.receiptDigest!==r.receiptDigest)throw new o("PROJECT_IDENTITY_MIGRATION_RECEIPT_CONFLICT");const i=a(t,E);if(e.phase==="finalized")return W(i,e),e;if(!I(i)||p(T(i))!==e.preparedStateDigest)throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");if(e.phase==="remote-acknowledged")return e;const c={...e,phase:"remote-acknowledged",updatedAt:new Date().toISOString(),receipt:r};return d(a(t,u),`${JSON.stringify(c,null,2)}
7
+ `),c})}function wt(n){const r=O(n);S(r,()=>{const t=A(r);if(!t)return;if(t.phase!=="prepared"||t.receipt)throw new o("PROJECT_IDENTITY_MIGRATION_ROLLBACK_AFTER_ACK_DENIED");const e=a(r,E);if(!I(e)||p(T(e))!==t.preparedStateDigest)throw new o("PROJECT_IDENTITY_MIGRATION_STATE_DRIFT");if(t.originalStateExists){if(!t.backupPath)throw new o("PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING");const c=a(r,t.backupPath);if(!I(c))throw new o("PROJECT_IDENTITY_MIGRATION_BACKUP_MISSING");const s=R(c);if(s.isSymbolicLink()||!s.isFile())throw new o("PROJECT_IDENTITY_SYMLINK_REJECTED");const _=T(c,"utf8");if(p(_)!==t.originalStateDigest)throw new o("PROJECT_IDENTITY_MIGRATION_BACKUP_CORRUPT");d(e,_)}else w(e),l(f(e));const i=a(r,u);w(i),l(f(i))})}function yt(n){const r=O(n);return A(r)?.phase??null}function At(n){const r=O(n);return{state:V(r,a(r,E)),migration:V(r,a(r,u))}}export{o as ProjectIdentityMigrationError,Pt as acknowledgeProjectIdentityMigration,ht as finalizeProjectIdentityMigration,gt as prepareProjectIdentityMigration,At as projectIdentityMigrationRelativePaths,yt as readProjectIdentityMigrationPhase,wt as rollbackPreparedProjectIdentityMigration};