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 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
@@ -461,16 +461,28 @@ async function cmdInit(parsedArgs) {
461
461
  }
462
462
  }
463
463
 
464
- // Stale marker detection: if marker exists but CLAUDE.md was deleted externally,
465
- // treat marker as stale and re-run (user clearly wants regeneration).
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
- // Unlink is surfaced as InitError on failure (symmetric with Pass 4
468
- // dropStalePass4Marker). Silently ignoring the error would leave the stale
469
- // marker in place, and the `if (fileExists(pass3Marker))` check below would
470
- // accept it skipping Pass 3 while CLAUDE.md is still missing. That
471
- // silent-skip is the exact bug class this audit round closes.
472
- if (fileExists(pass3Marker) && !fileExists(claudeMdPath)) {
473
- log(" ⚠️ pass3-complete.json exists but CLAUDE.md is missing treating marker as stale, re-running Pass 3");
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "claudeos-core",
3
- "version": "2.0.1",
3
+ "version": "2.0.2",
4
4
  "description": "Auto-generate Claude Code documentation from your actual source code — Standards, Rules, Skills, and Guides tailored to your project",
5
5
  "main": "bin/cli.js",
6
6
  "bin": {