@nimiplatform/nimi-coding 0.1.0 → 0.2.0

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 (121) hide show
  1. package/README.md +19 -20
  2. package/adapters/oh-my-codex/README.md +8 -9
  3. package/cli/commands/audit-sweep.mjs +10 -10
  4. package/cli/commands/classify-spec-tree.mjs +5 -0
  5. package/cli/commands/closeout.mjs +3 -0
  6. package/cli/commands/generate-spec-derived-docs.mjs +20 -0
  7. package/cli/commands/generate-spec-migration-plan.mjs +30 -0
  8. package/cli/commands/start.mjs +5 -1
  9. package/cli/commands/surface-validator-command.mjs +49 -0
  10. package/cli/commands/sweep-design.mjs +295 -0
  11. package/cli/commands/sweep.mjs +22 -0
  12. package/cli/commands/sync.mjs +132 -0
  13. package/cli/commands/topic-formatters.mjs +8 -8
  14. package/cli/commands/validate-ai-governance.mjs +167 -46
  15. package/cli/commands/validate-domain-admission.mjs +5 -0
  16. package/cli/commands/validate-guidance-bodies.mjs +5 -0
  17. package/cli/commands/validate-placement.mjs +5 -0
  18. package/cli/commands/validate-projection-edges.mjs +5 -0
  19. package/cli/commands/validate-spec-audit.mjs +5 -1
  20. package/cli/commands/validate-table-family.mjs +5 -0
  21. package/cli/commands/validate-tracked-output-admission.mjs +5 -0
  22. package/cli/constants.mjs +5 -49
  23. package/cli/help.mjs +33 -11
  24. package/cli/index.mjs +20 -2
  25. package/cli/lib/audit-sweep-runtime/admissions.mjs +38 -29
  26. package/cli/lib/audit-sweep-runtime/audit-validity.mjs +8 -0
  27. package/cli/lib/audit-sweep-runtime/chunks.mjs +11 -11
  28. package/cli/lib/audit-sweep-runtime/closeout.mjs +8 -8
  29. package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +3 -3
  30. package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +10 -10
  31. package/cli/lib/audit-sweep-runtime/common.mjs +7 -7
  32. package/cli/lib/audit-sweep-runtime/format.mjs +3 -3
  33. package/cli/lib/audit-sweep-runtime/ingest.mjs +8 -8
  34. package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +24 -27
  35. package/cli/lib/audit-sweep-runtime/inventory.mjs +58 -18
  36. package/cli/lib/audit-sweep-runtime/ledger.mjs +1 -1
  37. package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +2 -2
  38. package/cli/lib/audit-sweep-runtime/remediation.mjs +6 -6
  39. package/cli/lib/audit-sweep-runtime/rerun.mjs +6 -6
  40. package/cli/lib/audit-sweep-runtime/status.mjs +1 -1
  41. package/cli/lib/audit-sweep-runtime/validators.mjs +2 -2
  42. package/cli/lib/authority-convergence.mjs +397 -2
  43. package/cli/lib/blueprint-audit.mjs +5 -5
  44. package/cli/lib/closeout.mjs +126 -3
  45. package/cli/lib/contracts.mjs +21 -17
  46. package/cli/lib/handoff.mjs +29 -11
  47. package/cli/lib/high-risk-admission.mjs +60 -11
  48. package/cli/lib/high-risk-decision.mjs +31 -2
  49. package/cli/lib/high-risk-ingest.mjs +5 -1
  50. package/cli/lib/high-risk-review.mjs +5 -1
  51. package/cli/lib/internal/contracts-parse.mjs +195 -24
  52. package/cli/lib/internal/contracts-validators.mjs +3 -2
  53. package/cli/lib/internal/doctor-bootstrap-surface.mjs +82 -35
  54. package/cli/lib/internal/doctor-delegated-surface.mjs +1 -1
  55. package/cli/lib/internal/doctor-finalize.mjs +12 -8
  56. package/cli/lib/internal/doctor-inspectors.mjs +34 -1
  57. package/cli/lib/internal/governance/ai/ai-context-budget-core.mjs +74 -12
  58. package/cli/lib/internal/governance/ai/ai-structure-budget-core.mjs +24 -6
  59. package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +18 -23
  60. package/cli/lib/internal/surface-taxonomy-validators.mjs +931 -0
  61. package/cli/lib/internal/validators-spec.mjs +229 -20
  62. package/cli/lib/sweep-design-runtime/common.mjs +246 -0
  63. package/cli/lib/sweep-design-runtime/engine.mjs +733 -0
  64. package/cli/lib/sweep-design-runtime/fix-topic.mjs +414 -0
  65. package/cli/lib/sweep-design-runtime/lifecycle.mjs +54 -0
  66. package/cli/lib/sweep-design-runtime/results.mjs +324 -0
  67. package/cli/lib/sweep-design.mjs +8 -0
  68. package/cli/lib/sync.mjs +143 -0
  69. package/cli/lib/topic-artifacts.mjs +186 -0
  70. package/cli/lib/topic-authority-coverage.mjs +73 -0
  71. package/cli/lib/topic-closeout.mjs +560 -0
  72. package/cli/lib/topic-common.mjs +404 -0
  73. package/cli/lib/topic-decisions.mjs +332 -0
  74. package/cli/lib/topic-draft-packets.mjs +126 -7
  75. package/cli/lib/topic-execution.mjs +515 -0
  76. package/cli/lib/topic-goal.mjs +112 -33
  77. package/cli/lib/topic-ledger.mjs +281 -0
  78. package/cli/lib/topic-lifecycle-artifacts.mjs +173 -0
  79. package/cli/lib/topic-root-validation.mjs +288 -0
  80. package/cli/lib/topic-runner-commands.mjs +174 -0
  81. package/cli/lib/topic-runner-deferral.mjs +532 -0
  82. package/cli/lib/topic-runner-stale-gates.mjs +114 -0
  83. package/cli/lib/topic-runner-validation.mjs +138 -0
  84. package/cli/lib/topic-runner.mjs +109 -154
  85. package/cli/lib/topic-scaffold.mjs +252 -0
  86. package/cli/lib/topic-waves.mjs +403 -0
  87. package/cli/lib/topic.mjs +81 -93
  88. package/cli/lib/value-helpers.mjs +6 -1
  89. package/cli/seeds/bootstrap.mjs +96 -20
  90. package/cli/seeds/seed-policy.yaml +67 -0
  91. package/config/bootstrap.yaml +1 -1
  92. package/config/skill-manifest.yaml +4 -2
  93. package/config/spec-generation-inputs.yaml +41 -19
  94. package/contracts/audit-remediation-map.schema.yaml +1 -0
  95. package/contracts/audit-sweep-result.yaml +4 -0
  96. package/contracts/domain-admission.schema.yaml +56 -0
  97. package/contracts/migration-inventory.schema.yaml +80 -0
  98. package/contracts/negative-fixtures.yaml +91 -0
  99. package/contracts/placement-contract.schema.yaml +163 -0
  100. package/contracts/projection-edge.schema.yaml +130 -0
  101. package/contracts/shared-enums.yaml +68 -0
  102. package/contracts/spec-generation-audit.schema.yaml +19 -4
  103. package/contracts/spec-generation-inputs.schema.yaml +130 -29
  104. package/contracts/spec-reconstruction-result.yaml +9 -5
  105. package/contracts/surface-taxonomy.schema.yaml +201 -0
  106. package/contracts/sweep-design-result.yaml +349 -0
  107. package/contracts/table-family.schema.yaml +114 -0
  108. package/contracts/topic-goal.schema.yaml +10 -1
  109. package/contracts/tracked-output-admission.schema.yaml +70 -0
  110. package/contracts/workflow-consumer.schema.yaml +112 -0
  111. package/methodology/audit-sweep-p0p1-recall.yaml +1 -1
  112. package/methodology/spec-reconstruction.yaml +53 -30
  113. package/package.json +5 -4
  114. package/spec/_meta/command-gating-matrix.yaml +33 -0
  115. package/spec/_meta/generate-drift-migration-checklist.yaml +44 -62
  116. package/spec/_meta/governance-routing-cutover-checklist.yaml +3 -3
  117. package/spec/_meta/phase2-impacted-surface-matrix.yaml +14 -14
  118. package/spec/_meta/spec-authority-cutover-readiness.yaml +3 -5
  119. package/spec/_meta/spec-tree-model.yaml +104 -36
  120. package/spec/bootstrap-state.yaml +36 -36
  121. package/spec/product-scope.yaml +13 -10
@@ -0,0 +1,132 @@
1
+ import { runSeedSync, SYNC_MODE, SYNC_RESULT_STATUS } from "../lib/sync.mjs";
2
+ import { localize } from "../lib/ui.mjs";
3
+
4
+ function parseSyncOptions(args) {
5
+ const options = {
6
+ mode: SYNC_MODE.DRY_RUN,
7
+ json: false,
8
+ };
9
+ let modeSet = false;
10
+
11
+ for (const arg of args) {
12
+ if (arg === "--apply") {
13
+ if (modeSet) {
14
+ return {
15
+ ok: false,
16
+ error: localize(
17
+ "nimicoding sync refused: --apply, --check, and --dry-run are mutually exclusive.\n",
18
+ "nimicoding sync 拒绝执行:--apply、--check、--dry-run 互斥。\n",
19
+ ),
20
+ };
21
+ }
22
+ options.mode = SYNC_MODE.APPLY;
23
+ modeSet = true;
24
+ continue;
25
+ }
26
+ if (arg === "--check") {
27
+ if (modeSet) {
28
+ return {
29
+ ok: false,
30
+ error: localize(
31
+ "nimicoding sync refused: --apply, --check, and --dry-run are mutually exclusive.\n",
32
+ "nimicoding sync 拒绝执行:--apply、--check、--dry-run 互斥。\n",
33
+ ),
34
+ };
35
+ }
36
+ options.mode = SYNC_MODE.CHECK;
37
+ modeSet = true;
38
+ continue;
39
+ }
40
+ if (arg === "--dry-run") {
41
+ if (modeSet) {
42
+ return {
43
+ ok: false,
44
+ error: localize(
45
+ "nimicoding sync refused: --apply, --check, and --dry-run are mutually exclusive.\n",
46
+ "nimicoding sync 拒绝执行:--apply、--check、--dry-run 互斥。\n",
47
+ ),
48
+ };
49
+ }
50
+ options.mode = SYNC_MODE.DRY_RUN;
51
+ modeSet = true;
52
+ continue;
53
+ }
54
+ if (arg === "--json") {
55
+ options.json = true;
56
+ continue;
57
+ }
58
+ return {
59
+ ok: false,
60
+ error: localize(
61
+ `nimicoding sync refused: unknown option ${arg}.\n`,
62
+ `nimicoding sync 拒绝执行:未知选项 ${arg}。\n`,
63
+ ),
64
+ };
65
+ }
66
+
67
+ return { ok: true, options };
68
+ }
69
+
70
+ function formatHumanReport(result) {
71
+ const lines = [];
72
+ lines.push(localize(
73
+ `nimicoding sync (${result.mode})`,
74
+ `nimicoding sync (${result.mode})`,
75
+ ));
76
+ lines.push("");
77
+ lines.push(localize("Summary:", "概览:"));
78
+ lines.push(` total: ${result.summary.total}`);
79
+ lines.push(` in_sync: ${result.summary.in_sync}`);
80
+ if (result.mode === SYNC_MODE.APPLY) {
81
+ lines.push(` created: ${result.summary.created}`);
82
+ lines.push(` updated: ${result.summary.updated}`);
83
+ } else {
84
+ lines.push(` would_create: ${result.summary.would_create}`);
85
+ lines.push(` would_update: ${result.summary.would_update}`);
86
+ }
87
+ lines.push(` drifted_preserved (host-owned seed): ${result.summary.drifted_preserved}`);
88
+ if (result.mode === SYNC_MODE.CHECK) {
89
+ lines.push(` missing_package_canonical: ${result.summary.missing_package_canonical}`);
90
+ lines.push(` missing_host_state_seed: ${result.summary.missing_host_state_seed}`);
91
+ lines.push(` drifted_package_canonical: ${result.summary.drifted_package_canonical}`);
92
+ }
93
+
94
+ const noteworthy = result.results.filter((entry) => entry.status !== SYNC_RESULT_STATUS.IN_SYNC);
95
+ if (noteworthy.length > 0) {
96
+ lines.push("");
97
+ lines.push(localize("Per-file status:", "逐文件状态:"));
98
+ for (const entry of noteworthy) {
99
+ lines.push(` [${entry.status}] (${entry.ownership}) ${entry.outputRelativePath}`);
100
+ }
101
+ }
102
+
103
+ if (result.mode === SYNC_MODE.CHECK && !result.ok) {
104
+ lines.push("");
105
+ lines.push(localize(
106
+ "FAIL: package_canonical drift or missing seed detected; run `nimicoding sync --apply` to refresh.",
107
+ "FAIL:检测到 package_canonical drift 或缺失 seed;执行 `nimicoding sync --apply` 以刷新。",
108
+ ));
109
+ }
110
+
111
+ return `${lines.join("\n")}\n`;
112
+ }
113
+
114
+ export async function runSync(args) {
115
+ const parsed = parseSyncOptions(args);
116
+ if (!parsed.ok) {
117
+ process.stderr.write(parsed.error);
118
+ return 2;
119
+ }
120
+
121
+ const result = await runSeedSync(process.cwd(), parsed.options.mode);
122
+
123
+ if (parsed.options.json) {
124
+ process.stdout.write(`${JSON.stringify(result, null, 2)}\n`);
125
+ } else {
126
+ process.stdout.write(formatHumanReport(result));
127
+ }
128
+
129
+ return result.ok ? 0 : 1;
130
+ }
131
+
132
+ export { parseSyncOptions };
@@ -62,16 +62,16 @@ export function formatTopicStatus(report) {
62
62
  ...Object.entries(report.featureFlags).map(([key, value]) => `- ${key}: ${value ? "true" : "false"}`),
63
63
  );
64
64
  }
65
- if (Array.isArray(report.legacyObservedWaves) && report.legacyObservedWaves.length > 0) {
65
+ if (Array.isArray(report.observedWaves) && report.observedWaves.length > 0) {
66
66
  lines.push(
67
67
  "",
68
68
  styleLabel(localize("Observed Waves", "Observed Waves")),
69
- ...report.legacyObservedWaves.slice(0, 8).map((entry) => (
69
+ ...report.observedWaves.slice(0, 8).map((entry) => (
70
70
  `- ${entry.wave_id}: ${entry.observed_lineage} packets=${entry.packets} results=${entry.results} closeouts=${entry.closeouts} exec_packs=${entry.exec_packs}`
71
71
  )),
72
72
  );
73
- if (report.legacyObservedWaves.length > 8) {
74
- lines.push(styleMuted(`- ... ${report.legacyObservedWaves.length - 8} more wave observations`));
73
+ if (report.observedWaves.length > 8) {
74
+ lines.push(styleMuted(`- ... ${report.observedWaves.length - 8} more wave observations`));
75
75
  }
76
76
  }
77
77
  if (report.warnings.length > 0) {
@@ -119,16 +119,16 @@ export function formatTopicValidate(report) {
119
119
  ...Object.entries(report.featureFlags).map(([key, value]) => `- ${key}: ${value ? "true" : "false"}`),
120
120
  );
121
121
  }
122
- if (Array.isArray(report.legacyObservedWaves) && report.legacyObservedWaves.length > 0) {
122
+ if (Array.isArray(report.observedWaves) && report.observedWaves.length > 0) {
123
123
  lines.push(
124
124
  "",
125
125
  styleLabel(localize("Observed Waves", "Observed Waves")),
126
- ...report.legacyObservedWaves.slice(0, 8).map((entry) => (
126
+ ...report.observedWaves.slice(0, 8).map((entry) => (
127
127
  `- ${entry.wave_id}: ${entry.observed_lineage} packets=${entry.packets} results=${entry.results} closeouts=${entry.closeouts} exec_packs=${entry.exec_packs}`
128
128
  )),
129
129
  );
130
- if (report.legacyObservedWaves.length > 8) {
131
- lines.push(styleMuted(`- ... ${report.legacyObservedWaves.length - 8} more wave observations`));
130
+ if (report.observedWaves.length > 8) {
131
+ lines.push(styleMuted(`- ... ${report.observedWaves.length - 8} more wave observations`));
132
132
  }
133
133
  }
134
134
  if (report.warnings.length > 0) {
@@ -3,7 +3,10 @@ import { loadGovernanceConfig, requireProfile } from "../lib/internal/governance
3
3
  import { evaluateAiContextBudget, formatBytes } from "../lib/internal/governance/ai/ai-context-budget-core.mjs";
4
4
  import { evaluateAiStructureBudget } from "../lib/internal/governance/ai/ai-structure-budget-core.mjs";
5
5
  import { evaluateHighRiskDocMetadata } from "../lib/internal/governance/ai/check-high-risk-doc-metadata-core.mjs";
6
- import { runAgentsFreshnessCheck } from "../lib/internal/governance/ai/check-agents-freshness.mjs";
6
+ import {
7
+ evaluateAgentsFreshnessCheck,
8
+ runAgentsFreshnessCheck,
9
+ } from "../lib/internal/governance/ai/check-agents-freshness.mjs";
7
10
 
8
11
  const SCOPES = new Set([
9
12
  "agents-freshness",
@@ -16,6 +19,7 @@ function parseOptions(args) {
16
19
  const options = {
17
20
  profile: null,
18
21
  scope: "all",
22
+ json: false,
19
23
  };
20
24
 
21
25
  for (let index = 0; index < args.length; index += 1) {
@@ -41,6 +45,11 @@ function parseOptions(args) {
41
45
  continue;
42
46
  }
43
47
 
48
+ if (arg === "--json") {
49
+ options.json = true;
50
+ continue;
51
+ }
52
+
44
53
  return {
45
54
  ok: false,
46
55
  error: `nimicoding validate-ai-governance refused: unknown option ${arg}.\n`,
@@ -57,6 +66,63 @@ function parseOptions(args) {
57
66
  return { ok: true, options };
58
67
  }
59
68
 
69
+ function writeJson(payload) {
70
+ process.stdout.write(`${JSON.stringify(payload, null, 2)}\n`);
71
+ }
72
+
73
+ function buildContextBudgetReport(governanceConfig) {
74
+ const report = evaluateAiContextBudget({
75
+ cwd: process.cwd(),
76
+ config: governanceConfig.aiGovernance.contextBudget,
77
+ configPathLabel: ".nimi/config/governance.yaml#ai_governance.context_budget",
78
+ });
79
+ const exitCode = report.invalidWaivers.length > 0 || report.expiredWaivers.length > 0 || report.errors.length > 0
80
+ ? 1
81
+ : 0;
82
+ return { exitCode, report };
83
+ }
84
+
85
+ function buildStructureBudgetReport(governanceConfig) {
86
+ const report = evaluateAiStructureBudget({
87
+ cwd: process.cwd(),
88
+ config: governanceConfig.aiGovernance.structureBudget,
89
+ configPathLabel: ".nimi/config/governance.yaml#ai_governance.structure_budget",
90
+ });
91
+ const exitCode = report.errors.length > 0 || report.expiredWaivers.length > 0 ? 1 : 0;
92
+ return { exitCode, report };
93
+ }
94
+
95
+ function buildHighRiskDocMetadataReport(governanceConfig) {
96
+ const config = governanceConfig.aiGovernance.highRiskDocMetadata;
97
+ const report = evaluateHighRiskDocMetadata({
98
+ repoRoot: process.cwd(),
99
+ docRoots: Array.isArray(config.doc_roots) ? config.doc_roots : [".local"],
100
+ exemptPaths: Array.isArray(config.exempt_paths) ? config.exempt_paths : [],
101
+ namePatterns: Array.isArray(config.name_patterns) ? config.name_patterns : [],
102
+ requiredMetadataKeys: Array.isArray(config.required_metadata_keys)
103
+ ? config.required_metadata_keys
104
+ : [],
105
+ });
106
+ return {
107
+ exitCode: report.failures.length > 0 ? 1 : 0,
108
+ report: {
109
+ ...report,
110
+ exemptPaths: [...report.exemptPaths],
111
+ },
112
+ };
113
+ }
114
+
115
+ function buildAgentsFreshnessReport(governanceConfig) {
116
+ const report = evaluateAgentsFreshnessCheck({
117
+ projectRoot: process.cwd(),
118
+ config: governanceConfig.aiGovernance.agentsFreshness,
119
+ });
120
+ return {
121
+ exitCode: report.failures.length > 0 ? 1 : 0,
122
+ report,
123
+ };
124
+ }
125
+
60
126
  function formatStructureRow(row) {
61
127
  if (row.check === "depth") {
62
128
  return `${row.file} [rule=${row.ruleId}] depth=${row.depth} base=${row.depthBase} subject=${row.depthSubject} (threshold warn>=${row.warningDepth} error>=${row.errorDepth})`;
@@ -64,42 +130,37 @@ function formatStructureRow(row) {
64
130
  return `${row.file} [rule=${row.ruleId}] basename=${row.basename} (forwarding shell outside allowed basename set)`;
65
131
  }
66
132
 
133
+ function formatContextBudgetRow(row, thresholdPrefix) {
134
+ return `${row.file} [${row.profile}] lines=${row.lines} bytes=${formatBytes(row.bytes)} max-line=${formatBytes(row.maxLineBytes)} avg-line=${formatBytes(Math.round(row.averageLineBytes))} `
135
+ + `(${thresholdPrefix} lines>=${row[`${thresholdPrefix}Lines`] ?? "-"} bytes>=${row[`${thresholdPrefix}Bytes`] ?? "-"} max-line>=${row[`${thresholdPrefix}MaxLineBytes`] ?? "-"} avg-line>=${row[`${thresholdPrefix}AverageLineBytes`] ?? "-"})`;
136
+ }
137
+
67
138
  async function runContextBudget(governanceConfig) {
68
- const report = evaluateAiContextBudget({
69
- cwd: process.cwd(),
70
- config: governanceConfig.aiGovernance.contextBudget,
71
- configPathLabel: ".nimi/config/governance.yaml#ai_governance.context_budget",
72
- });
139
+ const { exitCode, report } = buildContextBudgetReport(governanceConfig);
73
140
 
74
141
  process.stdout.write(`ai-context-budget: config=${report.configPath}\n`);
75
142
  process.stdout.write(`ai-context-budget: tracked=${report.totalTrackedFiles}, analyzed=${report.analyzedFiles}\n`);
76
143
 
77
144
  for (const row of report.warnings) {
78
- process.stderr.write(
79
- `WARN: ${row.file} [${row.profile}] lines=${row.lines} bytes=${formatBytes(row.bytes)} (threshold warn lines>=${row.warningLines ?? "-"} bytes>=${row.warningBytes ?? "-"})\n`,
80
- );
145
+ process.stderr.write(`WARN: ${formatContextBudgetRow(row, "warning")}\n`);
81
146
  }
82
147
  for (const row of report.waivedErrors) {
83
148
  const until = row.waiver?.until ? row.waiver.until.toISOString().slice(0, 10) : "n/a";
84
149
  const reason = row.waiver?.reason || "no reason";
85
- process.stderr.write(
86
- `WARN: WAIVED error for ${row.file} [${row.profile}] lines=${row.lines} bytes=${formatBytes(row.bytes)} until=${until} reason=${reason}\n`,
87
- );
150
+ process.stderr.write(`WARN: WAIVED error for ${formatContextBudgetRow(row, "error")} until=${until} reason=${reason}\n`);
88
151
  }
89
152
  for (const row of report.expiredWaivers) {
90
- process.stderr.write(`ERROR: waiver expired for ${row.file} [${row.profile}] (lines=${row.lines} bytes=${formatBytes(row.bytes)})\n`);
153
+ process.stderr.write(`ERROR: waiver expired for ${formatContextBudgetRow(row, "error")}\n`);
91
154
  }
92
155
  for (const row of report.invalidWaivers) {
93
156
  process.stderr.write(`ERROR: invalid waiver for ${row.file}: ${row.detail}\n`);
94
157
  }
95
158
  for (const row of report.errors) {
96
- process.stderr.write(
97
- `ERROR: ${row.file} [${row.profile}] lines=${row.lines} bytes=${formatBytes(row.bytes)} (threshold error lines>=${row.errorLines ?? "-"} bytes>=${row.errorBytes ?? "-"})\n`,
98
- );
159
+ process.stderr.write(`ERROR: ${formatContextBudgetRow(row, "error")}\n`);
99
160
  }
100
161
 
101
- if (report.invalidWaivers.length > 0 || report.expiredWaivers.length > 0 || report.errors.length > 0) {
102
- return 1;
162
+ if (exitCode !== 0) {
163
+ return exitCode;
103
164
  }
104
165
 
105
166
  process.stdout.write("ai-context-budget: OK\n");
@@ -107,11 +168,7 @@ async function runContextBudget(governanceConfig) {
107
168
  }
108
169
 
109
170
  async function runStructureBudget(governanceConfig) {
110
- const report = evaluateAiStructureBudget({
111
- cwd: process.cwd(),
112
- config: governanceConfig.aiGovernance.structureBudget,
113
- configPathLabel: ".nimi/config/governance.yaml#ai_governance.structure_budget",
114
- });
171
+ const { exitCode, report } = buildStructureBudgetReport(governanceConfig);
115
172
 
116
173
  process.stdout.write(`ai-structure-budget: config=${report.configPath}\n`);
117
174
  process.stdout.write(`ai-structure-budget: tracked=${report.totalTrackedFiles}, analyzed=${report.analyzedFiles}\n`);
@@ -129,8 +186,8 @@ async function runStructureBudget(governanceConfig) {
129
186
  for (const row of report.errors) {
130
187
  process.stderr.write(`ERROR: ${formatStructureRow(row)}\n`);
131
188
  }
132
- if (report.errors.length > 0 || report.expiredWaivers.length > 0) {
133
- return 1;
189
+ if (exitCode !== 0) {
190
+ return exitCode;
134
191
  }
135
192
 
136
193
  process.stdout.write("ai-structure-budget: OK\n");
@@ -138,51 +195,90 @@ async function runStructureBudget(governanceConfig) {
138
195
  }
139
196
 
140
197
  async function runHighRiskDocMetadata(governanceConfig) {
141
- const config = governanceConfig.aiGovernance.highRiskDocMetadata;
142
- const report = evaluateHighRiskDocMetadata({
143
- repoRoot: process.cwd(),
144
- docRoots: Array.isArray(config.doc_roots) ? config.doc_roots : [".local"],
145
- exemptPaths: Array.isArray(config.exempt_paths) ? config.exempt_paths : [],
146
- namePatterns: Array.isArray(config.name_patterns) ? config.name_patterns : [],
147
- requiredMetadataKeys: Array.isArray(config.required_metadata_keys)
148
- ? config.required_metadata_keys
149
- : [],
150
- });
198
+ const { exitCode, report } = buildHighRiskDocMetadataReport(governanceConfig);
151
199
 
152
- if (report.failures.length > 0) {
200
+ if (exitCode !== 0) {
153
201
  process.stderr.write("high-risk doc metadata check failed:\n");
154
202
  for (const failure of report.failures) {
155
203
  process.stderr.write(`- ${failure}\n`);
156
204
  }
157
- return 1;
205
+ return exitCode;
158
206
  }
159
207
 
160
208
  process.stdout.write(`high-risk doc metadata check passed (${report.scanned.length} file(s) scanned)\n`);
161
209
  return 0;
162
210
  }
163
211
 
212
+ function runJsonScope(governanceConfig, scope) {
213
+ if (scope === "agents-freshness") {
214
+ return buildAgentsFreshnessReport(governanceConfig);
215
+ }
216
+ if (scope === "context-budget") {
217
+ return buildContextBudgetReport(governanceConfig);
218
+ }
219
+ if (scope === "structure-budget") {
220
+ return buildStructureBudgetReport(governanceConfig);
221
+ }
222
+ if (scope === "high-risk-doc-metadata") {
223
+ return buildHighRiskDocMetadataReport(governanceConfig);
224
+ }
225
+ return {
226
+ exitCode: 2,
227
+ report: { error: `unsupported scope: ${scope}` },
228
+ };
229
+ }
230
+
164
231
  export async function runValidateAiGovernance(args) {
232
+ const wantsJson = args.includes("--json");
165
233
  const parsed = parseOptions(args);
166
234
  if (!parsed.ok) {
167
- process.stderr.write(localize(parsed.error, parsed.error));
235
+ if (wantsJson) {
236
+ writeJson({
237
+ ok: false,
238
+ command: "validate-ai-governance",
239
+ error: parsed.error.trim(),
240
+ });
241
+ } else {
242
+ process.stderr.write(localize(parsed.error, parsed.error));
243
+ }
168
244
  return 2;
169
245
  }
170
246
 
171
247
  const governance = await loadGovernanceConfig(process.cwd());
172
248
  if (!governance.ok) {
173
- process.stderr.write(localize(
174
- `nimicoding validate-ai-governance refused: ${governance.reason} at ${governance.path}.\n`,
175
- `nimicoding validate-ai-governance 已拒绝:${governance.path} 的治理配置不可用。\n`,
176
- ));
249
+ const error = `nimicoding validate-ai-governance refused: ${governance.reason} at ${governance.path}.`;
250
+ if (parsed.options.json) {
251
+ writeJson({
252
+ ok: false,
253
+ command: "validate-ai-governance",
254
+ error,
255
+ governancePath: governance.path,
256
+ });
257
+ } else {
258
+ process.stderr.write(localize(
259
+ `${error}\n`,
260
+ `nimicoding validate-ai-governance 已拒绝:${governance.path} 的治理配置不可用。\n`,
261
+ ));
262
+ }
177
263
  return 2;
178
264
  }
179
265
 
180
266
  const profileCheck = requireProfile(governance.config, parsed.options.profile);
181
267
  if (!profileCheck.ok) {
182
- process.stderr.write(localize(
183
- `nimicoding validate-ai-governance refused: ${profileCheck.error}.\n`,
184
- `nimicoding validate-ai-governance 已拒绝:${profileCheck.error}。\n`,
185
- ));
268
+ const error = `nimicoding validate-ai-governance refused: ${profileCheck.error}.`;
269
+ if (parsed.options.json) {
270
+ writeJson({
271
+ ok: false,
272
+ command: "validate-ai-governance",
273
+ error,
274
+ profile: profileCheck.profile,
275
+ });
276
+ } else {
277
+ process.stderr.write(localize(
278
+ `${error}\n`,
279
+ `nimicoding validate-ai-governance 已拒绝:${profileCheck.error}。\n`,
280
+ ));
281
+ }
186
282
  return 2;
187
283
  }
188
284
 
@@ -190,6 +286,31 @@ export async function runValidateAiGovernance(args) {
190
286
  ? ["agents-freshness", "context-budget", "structure-budget", "high-risk-doc-metadata"]
191
287
  : [parsed.options.scope];
192
288
 
289
+ if (parsed.options.json) {
290
+ const results = [];
291
+ let exitCode = 0;
292
+ for (const scope of scopes) {
293
+ const result = runJsonScope(governance.config, scope);
294
+ if (exitCode === 0 && result.exitCode !== 0) {
295
+ exitCode = result.exitCode;
296
+ }
297
+ results.push({
298
+ scope,
299
+ ok: result.exitCode === 0,
300
+ exitCode: result.exitCode,
301
+ report: result.report,
302
+ });
303
+ }
304
+ writeJson({
305
+ ok: exitCode === 0,
306
+ command: "validate-ai-governance",
307
+ profile: profileCheck.profile,
308
+ scope: parsed.options.scope,
309
+ scopes: results,
310
+ });
311
+ return exitCode;
312
+ }
313
+
193
314
  for (const scope of scopes) {
194
315
  let exitCode = 0;
195
316
  if (scope === "agents-freshness") {
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runValidateDomainAdmission(args) {
4
+ return runSurfaceValidatorCommand(args, "validate-domain-admission");
5
+ }
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runValidateGuidanceBodies(args) {
4
+ return runSurfaceValidatorCommand(args, "validate-guidance-bodies");
5
+ }
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runValidatePlacement(args) {
4
+ return runSurfaceValidatorCommand(args, "validate-placement");
5
+ }
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runValidateProjectionEdges(args) {
4
+ return runSurfaceValidatorCommand(args, "validate-projection-edges");
5
+ }
@@ -1,11 +1,15 @@
1
1
  import path from "node:path";
2
2
 
3
3
  import { validateSpecAudit, buildValidatorCliReport } from "../lib/validators.mjs";
4
+ import { loadSpecGenerationInputsConfig } from "../lib/contracts.mjs";
4
5
  import { localize } from "../lib/ui.mjs";
5
6
 
6
7
  export async function runValidateSpecAudit(args) {
7
8
  const normalized = args[0] === "--" ? args.slice(1) : args;
8
- let targetPath = ".nimi/spec/_meta/spec-generation-audit.yaml";
9
+ const generationInputs = await loadSpecGenerationInputsConfig(process.cwd());
10
+ let targetPath = generationInputs.ok && generationInputs.mode === "class_filtered"
11
+ ? ".nimi/local/state/spec-generation/spec-generation-audit.yaml"
12
+ : ".nimi/spec/_meta/spec-generation-audit.yaml";
9
13
 
10
14
  if (normalized.length > 1) {
11
15
  process.stderr.write(localize(
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runValidateTableFamily(args) {
4
+ return runSurfaceValidatorCommand(args, "validate-table-family");
5
+ }
@@ -0,0 +1,5 @@
1
+ import { runSurfaceValidatorCommand } from "./surface-validator-command.mjs";
2
+
3
+ export function runValidateTrackedOutputAdmission(args) {
4
+ return runSurfaceValidatorCommand(args, "validate-tracked-output-admission");
5
+ }
package/cli/constants.mjs CHANGED
@@ -1,4 +1,4 @@
1
- export const VERSION = "0.1.0";
1
+ export const VERSION = "0.2.0";
2
2
  export const PACKAGE_NAME = "@nimiplatform/nimi-coding";
3
3
  export const BOOTSTRAP_CONTRACT_ID = "nimicoding.bootstrap";
4
4
  export const BOOTSTRAP_CONTRACT_VERSION = 1;
@@ -18,6 +18,8 @@ export const STANDALONE_COMPLETED_SURFACES = [
18
18
  "bootstrap",
19
19
  "doctor",
20
20
  "handoff",
21
+ "sweep_audit",
22
+ "sweep_design",
21
23
  "validators",
22
24
  "topic_lifecycle_report_methodology",
23
25
  "closeout",
@@ -51,6 +53,7 @@ export const CLAUDE_END = "<!-- nimicoding:managed:claude:end -->";
51
53
  export const SPEC_RECONSTRUCTION_RESULT_CONTRACT_REF = ".nimi/contracts/spec-reconstruction-result.yaml";
52
54
  export const DOC_SPEC_AUDIT_RESULT_CONTRACT_REF = ".nimi/contracts/doc-spec-audit-result.yaml";
53
55
  export const AUDIT_SWEEP_RESULT_CONTRACT_REF = ".nimi/contracts/audit-sweep-result.yaml";
56
+ export const SWEEP_DESIGN_RESULT_CONTRACT_REF = ".nimi/contracts/sweep-design-result.yaml";
54
57
  export const AUDIT_PLAN_SCHEMA_REF = ".nimi/contracts/audit-plan.schema.yaml";
55
58
  export const AUDIT_CHUNK_SCHEMA_REF = ".nimi/contracts/audit-chunk.schema.yaml";
56
59
  export const AUDIT_FINDING_SCHEMA_REF = ".nimi/contracts/audit-finding.schema.yaml";
@@ -260,7 +263,7 @@ export const DOC_SPEC_AUDIT_DEFAULT_COMPARED_PATHS = [
260
263
  ];
261
264
 
262
265
  export const SPEC_TREE_MODEL_REF = ".nimi/spec/_meta/spec-tree-model.yaml";
263
- export const BLUEPRINT_REFERENCE_REF = ".nimi/spec/_meta/blueprint-reference.yaml";
266
+ export const BLUEPRINT_REFERENCE_REF = ".nimi/local/state/spec-generation/blueprint-reference.yaml";
264
267
  export const COMMAND_GATING_MATRIX_REF = ".nimi/spec/_meta/command-gating-matrix.yaml";
265
268
  export const GENERATE_DRIFT_MIGRATION_CHECKLIST_REF = ".nimi/spec/_meta/generate-drift-migration-checklist.yaml";
266
269
  export const GOVERNANCE_ROUTING_CUTOVER_CHECKLIST_REF = ".nimi/spec/_meta/governance-routing-cutover-checklist.yaml";
@@ -277,53 +280,6 @@ export const SKILL_RESULT_CONTRACT_REFS = {
277
280
  high_risk_execution: HIGH_RISK_EXECUTION_RESULT_CONTRACT_REF,
278
281
  };
279
282
 
280
- export const REQUIRED_BOOTSTRAP_FILES = [
281
- ".nimi/methodology/core.yaml",
282
- ".nimi/methodology/spec-reconstruction.yaml",
283
- ".nimi/methodology/skill-runtime.yaml",
284
- ".nimi/methodology/skill-installer-result.yaml",
285
- ".nimi/methodology/skill-installer-summary-projection.yaml",
286
- ".nimi/methodology/skill-exchange-projection.yaml",
287
- ".nimi/methodology/skill-handoff.yaml",
288
- SPEC_TREE_MODEL_REF,
289
- COMMAND_GATING_MATRIX_REF,
290
- GENERATE_DRIFT_MIGRATION_CHECKLIST_REF,
291
- GOVERNANCE_ROUTING_CUTOVER_CHECKLIST_REF,
292
- PHASE2_IMPACTED_SURFACE_MATRIX_REF,
293
- ".nimi/spec/product-scope.yaml",
294
- ".nimi/spec/bootstrap-state.yaml",
295
- ".nimi/config/bootstrap.yaml",
296
- ".nimi/config/skills.yaml",
297
- ".nimi/config/skill-manifest.yaml",
298
- SPEC_GENERATION_INPUTS_REF,
299
- ".nimi/config/host-profile.yaml",
300
- HOST_ADAPTER_CONFIG_REF,
301
- EXTERNAL_EXECUTION_ARTIFACTS_CONFIG_REF,
302
- AUDIT_EXECUTION_ARTIFACTS_CONFIG_REF,
303
- ".nimi/config/skill-installer.yaml",
304
- ".nimi/config/installer-evidence.yaml",
305
- SPEC_RECONSTRUCTION_RESULT_CONTRACT_REF,
306
- DOC_SPEC_AUDIT_RESULT_CONTRACT_REF,
307
- AUDIT_SWEEP_RESULT_CONTRACT_REF,
308
- AUDIT_PLAN_SCHEMA_REF,
309
- AUDIT_CHUNK_SCHEMA_REF,
310
- AUDIT_FINDING_SCHEMA_REF,
311
- AUDIT_LEDGER_SCHEMA_REF,
312
- AUDIT_REMEDIATION_MAP_SCHEMA_REF,
313
- AUDIT_RERUN_SCHEMA_REF,
314
- AUDIT_CLOSEOUT_SCHEMA_REF,
315
- HIGH_RISK_EXECUTION_RESULT_CONTRACT_REF,
316
- HIGH_RISK_ADMISSION_CONTRACT_REF,
317
- SPEC_GENERATION_INPUTS_CONTRACT_REF,
318
- SPEC_GENERATION_AUDIT_CONTRACT_REF,
319
- EXTERNAL_HOST_COMPATIBILITY_CONTRACT_REF,
320
- EXECUTION_PACKET_SCHEMA_REF,
321
- ORCHESTRATION_STATE_SCHEMA_REF,
322
- PROMPT_SCHEMA_REF,
323
- WORKER_OUTPUT_SCHEMA_REF,
324
- ACCEPTANCE_SCHEMA_REF,
325
- ];
326
-
327
283
  export const REQUIRED_LOCAL_DIRS = [".nimi/local", ".nimi/cache"];
328
284
 
329
285
  export const REQUIRED_BOOTSTRAP_DIRS = [