genesis-compiler 1.2.21 → 1.2.22
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.
package/package.json
CHANGED
package/src/index/codex-hooks.js
CHANGED
|
@@ -214,6 +214,13 @@ function zeroPaths(buffer) {
|
|
|
214
214
|
return normalizedPaths(buffer.toString('utf8').split('\0'));
|
|
215
215
|
}
|
|
216
216
|
|
|
217
|
+
function projectPathStates(projectRoot, files) {
|
|
218
|
+
return Promise.all(files.map(async (file) => ({
|
|
219
|
+
path: file,
|
|
220
|
+
state: await pathState(path.join(projectRoot, file)),
|
|
221
|
+
})));
|
|
222
|
+
}
|
|
223
|
+
|
|
217
224
|
async function repositorySnapshot(projectRoot) {
|
|
218
225
|
const head = await runGitText(projectRoot, ['rev-parse', '--verify', 'HEAD']).catch(() => null);
|
|
219
226
|
const results = await Promise.all([
|
|
@@ -227,10 +234,7 @@ async function repositorySnapshot(projectRoot) {
|
|
|
227
234
|
.sort();
|
|
228
235
|
return {
|
|
229
236
|
head,
|
|
230
|
-
dirty: await
|
|
231
|
-
path: file,
|
|
232
|
-
state: await pathState(path.join(projectRoot, file)),
|
|
233
|
-
}))),
|
|
237
|
+
dirty: await projectPathStates(projectRoot, dirty),
|
|
234
238
|
};
|
|
235
239
|
}
|
|
236
240
|
|
|
@@ -423,19 +427,27 @@ function changedPathLines(changedPaths) {
|
|
|
423
427
|
}
|
|
424
428
|
|
|
425
429
|
function changedRepositoryLines(repositories) {
|
|
426
|
-
return repositories.flatMap(({ projectRoot, changedPaths }) => [
|
|
430
|
+
return repositories.flatMap(({ projectRoot, changedPaths, driftedPaths = [] }) => [
|
|
427
431
|
`## Repository: \`${projectRoot}\``,
|
|
428
432
|
'',
|
|
429
433
|
...changedPathLines(changedPaths),
|
|
434
|
+
...(driftedPaths.length > 0 ? [
|
|
435
|
+
'',
|
|
436
|
+
'### Concurrent changes excluded from cleanup',
|
|
437
|
+
'',
|
|
438
|
+
'These paths changed after the implementation scope was frozen. Report them, but do not edit them:',
|
|
439
|
+
'',
|
|
440
|
+
...changedPathLines(driftedPaths),
|
|
441
|
+
] : []),
|
|
430
442
|
'',
|
|
431
443
|
]);
|
|
432
444
|
}
|
|
433
445
|
|
|
434
|
-
async function changedRepositories(repositories) {
|
|
446
|
+
async function changedRepositories(repositories, { snapshotField = 'snapshot' } = {}) {
|
|
435
447
|
return (await Promise.all(repositories.map(async (repository) => {
|
|
436
448
|
const currentPaths = await changedProjectPaths(
|
|
437
449
|
repository.projectRoot,
|
|
438
|
-
repository.snapshot,
|
|
450
|
+
repository[snapshotField] || repository.snapshot,
|
|
439
451
|
await repositorySnapshot(repository.projectRoot),
|
|
440
452
|
);
|
|
441
453
|
const changedPaths = normalizedPaths([
|
|
@@ -446,6 +458,47 @@ async function changedRepositories(repositories) {
|
|
|
446
458
|
}))).filter(Boolean);
|
|
447
459
|
}
|
|
448
460
|
|
|
461
|
+
async function freezeChangedRepositories(repositories, { startPostChange = false } = {}) {
|
|
462
|
+
return Promise.all(repositories.map(async (repository) => {
|
|
463
|
+
const changedPaths = normalizedPaths(repository.changedPaths || []).sort();
|
|
464
|
+
const [pathStates, phaseSnapshot] = await Promise.all([
|
|
465
|
+
projectPathStates(repository.projectRoot, changedPaths),
|
|
466
|
+
startPostChange ? repositorySnapshot(repository.projectRoot) : null,
|
|
467
|
+
]);
|
|
468
|
+
const frozen = {
|
|
469
|
+
...repository,
|
|
470
|
+
changedPaths,
|
|
471
|
+
pathStates,
|
|
472
|
+
};
|
|
473
|
+
delete frozen.driftedPaths;
|
|
474
|
+
delete frozen.phaseSnapshot;
|
|
475
|
+
if (phaseSnapshot) frozen.phaseSnapshot = phaseSnapshot;
|
|
476
|
+
return frozen;
|
|
477
|
+
}));
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
async function cleanupScopeRepositories(repositories) {
|
|
481
|
+
return (await Promise.all(repositories.map(async (repository) => {
|
|
482
|
+
const ownedPaths = normalizedPaths(repository.changedPaths || []).sort();
|
|
483
|
+
if (ownedPaths.length === 0) return null;
|
|
484
|
+
const expected = new Map((repository.pathStates || [])
|
|
485
|
+
.map(({ path: file, state }) => [file, state]));
|
|
486
|
+
const changedPaths = [];
|
|
487
|
+
const driftedPaths = [];
|
|
488
|
+
for (const { path: file, state } of await projectPathStates(repository.projectRoot, ownedPaths)) {
|
|
489
|
+
const destination = expected.has(file) && stableJson(expected.get(file)) !== stableJson(state)
|
|
490
|
+
? driftedPaths
|
|
491
|
+
: changedPaths;
|
|
492
|
+
destination.push(file);
|
|
493
|
+
}
|
|
494
|
+
return {
|
|
495
|
+
...repository,
|
|
496
|
+
changedPaths,
|
|
497
|
+
driftedPaths,
|
|
498
|
+
};
|
|
499
|
+
}))).filter(Boolean);
|
|
500
|
+
}
|
|
501
|
+
|
|
449
502
|
async function repositoryContexts(repositories) {
|
|
450
503
|
return Promise.all(repositories.map(async (repository) => {
|
|
451
504
|
const [stack, engineering] = await Promise.all([
|
|
@@ -572,13 +625,14 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
|
|
|
572
625
|
await removeTurnState(statePath, input);
|
|
573
626
|
return {};
|
|
574
627
|
}
|
|
575
|
-
const
|
|
576
|
-
if (
|
|
628
|
+
const changed = await changedRepositories(registeredRepositories(state, root));
|
|
629
|
+
if (changed.length === 0) {
|
|
577
630
|
await removeTurnState(statePath, input);
|
|
578
631
|
return {};
|
|
579
632
|
}
|
|
580
|
-
const contexts = await repositoryContexts(
|
|
633
|
+
const contexts = await repositoryContexts(changed);
|
|
581
634
|
const postChange = contexts.some(({ stack }) => Boolean(stack?.postChange?.trim()));
|
|
635
|
+
const repositories = await freezeChangedRepositories(changed, { startPostChange: postChange });
|
|
582
636
|
await writeTurnState(statePath, {
|
|
583
637
|
...state,
|
|
584
638
|
phase: postChange ? 'post-change' : 'reconcile',
|
|
@@ -598,11 +652,14 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
|
|
|
598
652
|
}
|
|
599
653
|
|
|
600
654
|
if (state.phase === 'post-change') {
|
|
601
|
-
const
|
|
602
|
-
|
|
655
|
+
const changed = await changedRepositories(registeredRepositories(state, root), {
|
|
656
|
+
snapshotField: 'phaseSnapshot',
|
|
657
|
+
});
|
|
658
|
+
if (changed.length === 0) {
|
|
603
659
|
await removeTurnState(statePath, input);
|
|
604
660
|
return {};
|
|
605
661
|
}
|
|
662
|
+
const repositories = await freezeChangedRepositories(changed);
|
|
606
663
|
await writeTurnState(statePath, {
|
|
607
664
|
...state,
|
|
608
665
|
phase: 'reconcile',
|
|
@@ -616,7 +673,7 @@ export async function completeCodexTurn({ input, projectRoot } = {}) {
|
|
|
616
673
|
|
|
617
674
|
if (state.phase === 'reconcile') {
|
|
618
675
|
const registered = registeredRepositories(state, root);
|
|
619
|
-
const repositories = await
|
|
676
|
+
const repositories = await cleanupScopeRepositories(registered);
|
|
620
677
|
if (repositories.length === 0) {
|
|
621
678
|
await refreshProjectIndexes(registered);
|
|
622
679
|
await removeTurnState(statePath, input);
|