claudeos-core 2.0.1 → 2.0.2
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/CHANGELOG.md +10 -0
- package/bin/commands/init.js +47 -9
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## [2.0.2] — 2026-04-20
|
|
4
|
+
|
|
5
|
+
### Fixed
|
|
6
|
+
|
|
7
|
+
- **Upgrade-path silent-skip regression for pre-v2.0.0 projects** — `npx claudeos-core health` permanently reported `content-validator: fail` with 9 × MISSING guide errors on projects that had been initialized on a pre-v2.0.0 release and then upgraded. Pass 3 wrote `pass3-complete.json` before the Pass 3 output-completeness guards (H1/H2) existed, so the marker was valid-looking on disk even though `claudeos-core/guide/` (and sometimes `standard/00.core/01.project-overview.md`, `skills/`, or `plan/`) had never been populated. On subsequent runs, `init.js` observed the marker + an existing CLAUDE.md, skipped Pass 3, and never regenerated the missing outputs — leaving the project in a stuck-fail state that only `--force` (which wipes `.claude/rules/` and loses manual edits) could recover. The Pass 3 stale-marker branch in `bin/commands/init.js` previously only detected externally-deleted CLAUDE.md; it now also drops the marker when any entry in `lib/expected-guides.js` is missing/BOM-aware-empty or when `findMissingOutputs()` (`lib/expected-outputs.js`) flags a missing standard sentinel / `skills/` / `plan/`. Mirrors the existing `dropStalePass4Marker` pattern (symmetric helper `dropStalePass3Marker` added) and reuses the same "unlink failure surfaces as `InitError` with Windows AV/file-lock guidance" contract so the recovery itself can't silently regress. Recovery is one-shot: next `init` re-runs Pass 3, which populates the missing outputs and writes a fresh marker gated by the v2.0.0 H1/H2 guards.
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
|
|
11
|
+
- **`tests/pass3-marker.test.js`** — Six new cases covering the stale-detection branches: (a) missing guide dir → drop, (b) single BOM-only guide file → drop, (c) guides present but `skills/` gone → drop, (d) guides present but standard sentinel missing → drop, (e) complete state preserves marker, (f) `init.js` source-parity tripwire asserting `dropStalePass3Marker` + both `EXPECTED_GUIDE_FILES` and `findMissingOutputs` references appear in the stale-check region (guards against refactors silently regressing to v2.0.1 behavior).
|
|
12
|
+
|
|
3
13
|
## [2.0.1] — 2026-04-19
|
|
4
14
|
|
|
5
15
|
### Fixed
|
package/bin/commands/init.js
CHANGED
|
@@ -461,16 +461,28 @@ async function cmdInit(parsedArgs) {
|
|
|
461
461
|
}
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
-
// Stale marker detection
|
|
465
|
-
//
|
|
464
|
+
// Stale marker detection (Pass 3). Drops the marker and re-runs Pass 3 if
|
|
465
|
+
// any of the following is true:
|
|
466
|
+
// (a) CLAUDE.md was deleted externally (original check),
|
|
467
|
+
// (b) any of EXPECTED_GUIDE_FILES is missing or BOM-aware empty,
|
|
468
|
+
// (c) any entry in expected-outputs (standard sentinel / skills / plan) is
|
|
469
|
+
// missing or empty.
|
|
466
470
|
//
|
|
467
|
-
//
|
|
468
|
-
//
|
|
469
|
-
//
|
|
470
|
-
//
|
|
471
|
-
//
|
|
472
|
-
|
|
473
|
-
|
|
471
|
+
// (b) and (c) were previously only enforced as Pass 3 post-generation Guards
|
|
472
|
+
// 3 (H2/H1), which gate marker *creation* on fresh runs. Projects that were
|
|
473
|
+
// initialized on a pre-v2.0.0 release (before those guards existed) can end
|
|
474
|
+
// up with a marker on disk even though guide/ or standard/skills/plan are
|
|
475
|
+
// empty. Without this stale check, such projects hit a permanent
|
|
476
|
+
// content-validator fail loop because init sees the marker and skips Pass 3
|
|
477
|
+
// forever. This mirrors the Pass 4 dropStalePass4Marker pattern below.
|
|
478
|
+
//
|
|
479
|
+
// Unlink is surfaced as InitError on failure (symmetric with Pass 4).
|
|
480
|
+
// Silently ignoring the error would leave the stale marker in place, and
|
|
481
|
+
// the `if (fileExists(pass3Marker))` check below would accept it — skipping
|
|
482
|
+
// Pass 3 while outputs are still incomplete. That silent-skip is the exact
|
|
483
|
+
// bug class this audit round closes.
|
|
484
|
+
function dropStalePass3Marker(reasonLog) {
|
|
485
|
+
log(reasonLog);
|
|
474
486
|
try { fs.unlinkSync(pass3Marker); } catch (e) {
|
|
475
487
|
log(` ❌ Failed to delete stale pass3-complete.json: ${e.code || e.message}`);
|
|
476
488
|
throw new InitError(
|
|
@@ -480,6 +492,32 @@ async function cmdInit(parsedArgs) {
|
|
|
480
492
|
);
|
|
481
493
|
}
|
|
482
494
|
}
|
|
495
|
+
if (fileExists(pass3Marker)) {
|
|
496
|
+
if (!fileExists(claudeMdPath)) {
|
|
497
|
+
dropStalePass3Marker(" ⚠️ pass3-complete.json exists but CLAUDE.md is missing — treating marker as stale, re-running Pass 3");
|
|
498
|
+
} else {
|
|
499
|
+
const guideDirForStale = path.join(PROJECT_ROOT, "claudeos-core/guide");
|
|
500
|
+
const staleMissingGuides = EXPECTED_GUIDE_FILES.filter(g => {
|
|
501
|
+
const fp = path.join(guideDirForStale, g);
|
|
502
|
+
if (!fileExists(fp)) return true;
|
|
503
|
+
try {
|
|
504
|
+
return fs.readFileSync(fp, "utf-8").replace(/^\uFEFF/, "").trim().length === 0;
|
|
505
|
+
} catch (_e) { return true; }
|
|
506
|
+
});
|
|
507
|
+
if (staleMissingGuides.length > 0) {
|
|
508
|
+
dropStalePass3Marker(
|
|
509
|
+
` ⚠️ pass3-complete.json exists but ${staleMissingGuides.length}/${EXPECTED_GUIDE_FILES.length} guide files are missing or empty — treating marker as stale, re-running Pass 3`
|
|
510
|
+
);
|
|
511
|
+
} else {
|
|
512
|
+
const staleMissingOutputs = findMissingOutputs(PROJECT_ROOT);
|
|
513
|
+
if (staleMissingOutputs.length > 0) {
|
|
514
|
+
dropStalePass3Marker(
|
|
515
|
+
` ⚠️ pass3-complete.json exists but ${staleMissingOutputs.length} required output(s) are missing or empty — treating marker as stale, re-running Pass 3`
|
|
516
|
+
);
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
}
|
|
483
521
|
|
|
484
522
|
if (fileExists(pass3Marker)) {
|
|
485
523
|
log(" ⏭️ pass3-complete.json already exists, skipping");
|
package/package.json
CHANGED