project-tiny-context-harness 0.2.52 → 0.2.54

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.
@@ -1,11 +1,33 @@
1
1
  import { runDoctor } from "./doctor.js";
2
- import { formatUpgradePlan, runMigrations } from "./migrations.js";
2
+ import { createUpgradePlan, formatUpgradePlan, runMigrations } from "./migrations.js";
3
3
  import { assertSupportedSchema } from "./schema-guard.js";
4
4
  import { runSync } from "./sync-engine.js";
5
+ export class UpgradeBlockedError extends Error {
6
+ lines;
7
+ constructor(lines) {
8
+ super("upgrade completed with blockers");
9
+ this.lines = lines;
10
+ }
11
+ }
5
12
  export async function runUpgrade(projectRoot) {
13
+ const report = await runUpgradeReport(projectRoot);
14
+ if (report.blocked) {
15
+ throw new UpgradeBlockedError(report.lines);
16
+ }
17
+ return report.lines;
18
+ }
19
+ export async function runUpgradeReport(projectRoot) {
6
20
  const lines = [];
7
21
  await assertSupportedSchema(projectRoot, "upgrade");
8
- const migrationReport = await runMigrations(projectRoot);
22
+ const plan = await createUpgradePlan(projectRoot);
23
+ if (plan.blocked.length > 0) {
24
+ lines.push(...formatUpgradePlan(plan));
25
+ lines.push("upgrade blocked: resolve blocked migration items before applying safe migrations or sync.");
26
+ const doctor = await runDoctor(projectRoot);
27
+ lines.push(`doctor warnings=${doctor.warnings.length} errors=${doctor.errors.length}`);
28
+ return { lines, blocked: true };
29
+ }
30
+ const migrationReport = await runMigrations(projectRoot, plan);
9
31
  lines.push(`migrations changed=${migrationReport.changed.length} skipped=${migrationReport.skipped.length} manual_required=${migrationReport.manualRequired.length} blocked=${migrationReport.blocked.length}`);
10
32
  if (migrationReport.manualRequired.length > 0 || migrationReport.blocked.length > 0) {
11
33
  lines.push(...formatUpgradePlan({
@@ -21,11 +43,9 @@ export async function runUpgrade(projectRoot) {
21
43
  }
22
44
  const doctor = await runDoctor(projectRoot);
23
45
  lines.push(`doctor warnings=${doctor.warnings.length} errors=${doctor.errors.length}`);
24
- if (migrationReport.manualRequired.length > 0 ||
46
+ const blocked = migrationReport.manualRequired.length > 0 ||
25
47
  migrationReport.blocked.length > 0 ||
26
48
  syncReport.blocked.length > 0 ||
27
- doctor.errors.length > 0) {
28
- throw new Error("upgrade completed with blockers");
29
- }
30
- return lines;
49
+ doctor.errors.length > 0;
50
+ return { lines, blocked };
31
51
  }
@@ -2,10 +2,12 @@ import path from "node:path";
2
2
  import { readConfig } from "./config.js";
3
3
  import { harnessPath, harnessRoot } from "./harness-root.js";
4
4
  import { listFiles, pathExists, readText } from "./fs.js";
5
+ import { runModularityCheck } from "./modularity.js";
5
6
  import { unsupportedSchemaMessage } from "./schema-guard.js";
6
7
  const VALIDATORS = {
7
8
  "validate-context": validateContext,
8
- "validate-harness": validateContext
9
+ "validate-code-modularity": validateCodeModularity,
10
+ "validate-harness": validateHarness
9
11
  };
10
12
  const GLOBAL_REQUIRED_SECTIONS = [
11
13
  ...sectionSpecs([
@@ -71,12 +73,43 @@ export async function runValidator(projectRoot, gate) {
71
73
  return {
72
74
  info: [],
73
75
  errors: [
74
- `unknown validator: ${gate}. Minimal Context Harness supports validate-context and validate-harness only.`
76
+ `unknown validator: ${gate}. Minimal Context Harness supports validate-context, validate-code-modularity and validate-harness only.`
75
77
  ]
76
78
  };
77
79
  }
78
80
  return validator(projectRoot);
79
81
  }
82
+ async function validateHarness(projectRoot) {
83
+ const contextReport = await validateContext(projectRoot);
84
+ const modularityReport = await validateCodeModularity(projectRoot);
85
+ return {
86
+ info: [...contextReport.info, ...modularityReport.info],
87
+ errors: [...contextReport.errors, ...modularityReport.errors]
88
+ };
89
+ }
90
+ async function validateCodeModularity(projectRoot) {
91
+ const report = await runModularityCheck(projectRoot, { touched: true });
92
+ const info = [
93
+ `code modularity audited=${report.files.length} warning=${report.warnings.length} waived=${report.waivedWarnings.length} limit=${report.limit}`
94
+ ];
95
+ if (report.files.length === 0) {
96
+ info.push("No handwritten source files matched the selected scope.");
97
+ }
98
+ for (const file of report.files) {
99
+ const prefix = file.overLimit && file.waived ? "waived" : file.overLimit ? "over-limit" : "ok";
100
+ info.push(`${prefix}: ${file.relativePath} ${file.lines} lines`);
101
+ }
102
+ for (const waiver of report.waivedWarnings) {
103
+ info.push(`waived: ${waiver}`);
104
+ }
105
+ if (report.errors.length === 0 && report.warnings.length === 0) {
106
+ info.push("Code modularity validation passed");
107
+ }
108
+ return {
109
+ info,
110
+ errors: [...report.errors, ...report.warnings]
111
+ };
112
+ }
80
113
  async function validateContext(projectRoot) {
81
114
  const info = [];
82
115
  const errors = [];
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "project-tiny-context-harness",
3
- "version": "0.2.52",
3
+ "version": "0.2.54",
4
4
  "description": "Minimal project memory and validation harness for AI coding agents.",
5
5
  "license": "MIT",
6
6
  "author": "Seven128",