@nimiplatform/nimi-coding 0.1.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.
- package/LICENSE +21 -0
- package/README.md +348 -0
- package/adapters/README.md +25 -0
- package/adapters/claude/README.md +89 -0
- package/adapters/claude/profile.yaml +70 -0
- package/adapters/codex/README.md +53 -0
- package/adapters/codex/profile.yaml +78 -0
- package/adapters/oh-my-codex/README.md +185 -0
- package/adapters/oh-my-codex/profile.yaml +46 -0
- package/bin/nimicoding.mjs +6 -0
- package/cli/commands/admit-high-risk-decision.mjs +108 -0
- package/cli/commands/audit-sweep.mjs +341 -0
- package/cli/commands/blueprint-audit.mjs +91 -0
- package/cli/commands/clear.mjs +168 -0
- package/cli/commands/closeout.mjs +183 -0
- package/cli/commands/decide-high-risk-execution.mjs +124 -0
- package/cli/commands/doctor.mjs +53 -0
- package/cli/commands/generate-spec-derived-docs.mjs +131 -0
- package/cli/commands/handoff.mjs +123 -0
- package/cli/commands/ingest-high-risk-execution.mjs +95 -0
- package/cli/commands/review-high-risk-execution.mjs +95 -0
- package/cli/commands/start.mjs +717 -0
- package/cli/commands/topic-formatters.mjs +382 -0
- package/cli/commands/topic-goal.mjs +33 -0
- package/cli/commands/topic-options-shared.mjs +27 -0
- package/cli/commands/topic-options-workflow.mjs +767 -0
- package/cli/commands/topic-options.mjs +626 -0
- package/cli/commands/topic-runner.mjs +169 -0
- package/cli/commands/topic.mjs +795 -0
- package/cli/commands/validate-acceptance.mjs +5 -0
- package/cli/commands/validate-ai-governance.mjs +214 -0
- package/cli/commands/validate-execution-packet.mjs +5 -0
- package/cli/commands/validate-orchestration-state.mjs +5 -0
- package/cli/commands/validate-prompt.mjs +5 -0
- package/cli/commands/validate-spec-audit.mjs +27 -0
- package/cli/commands/validate-spec-governance.mjs +124 -0
- package/cli/commands/validate-spec-tree.mjs +27 -0
- package/cli/commands/validate-worker-output.mjs +5 -0
- package/cli/constants.mjs +489 -0
- package/cli/help.mjs +134 -0
- package/cli/index.mjs +103 -0
- package/cli/lib/adapter-profiles.mjs +403 -0
- package/cli/lib/audit-execution.mjs +52 -0
- package/cli/lib/audit-sweep-runtime/admissions.mjs +381 -0
- package/cli/lib/audit-sweep-runtime/audit-validity.mjs +333 -0
- package/cli/lib/audit-sweep-runtime/chunks.mjs +697 -0
- package/cli/lib/audit-sweep-runtime/closeout.mjs +144 -0
- package/cli/lib/audit-sweep-runtime/codex-auditor-evidence.mjs +639 -0
- package/cli/lib/audit-sweep-runtime/codex-auditor.mjs +515 -0
- package/cli/lib/audit-sweep-runtime/common.mjs +329 -0
- package/cli/lib/audit-sweep-runtime/coverage-quality.mjs +172 -0
- package/cli/lib/audit-sweep-runtime/evidence-assignment.mjs +152 -0
- package/cli/lib/audit-sweep-runtime/format.mjs +57 -0
- package/cli/lib/audit-sweep-runtime/ingest.mjs +486 -0
- package/cli/lib/audit-sweep-runtime/inventory-spec-chunks.mjs +198 -0
- package/cli/lib/audit-sweep-runtime/inventory.mjs +728 -0
- package/cli/lib/audit-sweep-runtime/ledger.mjs +315 -0
- package/cli/lib/audit-sweep-runtime/p0p1-profile.mjs +101 -0
- package/cli/lib/audit-sweep-runtime/remediation.mjs +349 -0
- package/cli/lib/audit-sweep-runtime/rerun.mjs +129 -0
- package/cli/lib/audit-sweep-runtime/risk-budget.mjs +300 -0
- package/cli/lib/audit-sweep-runtime/status.mjs +62 -0
- package/cli/lib/audit-sweep-runtime/validators-ledger.mjs +215 -0
- package/cli/lib/audit-sweep-runtime/validators.mjs +758 -0
- package/cli/lib/audit-sweep.mjs +18 -0
- package/cli/lib/authority-convergence.mjs +309 -0
- package/cli/lib/blueprint-audit.mjs +370 -0
- package/cli/lib/bootstrap.mjs +228 -0
- package/cli/lib/closeout.mjs +623 -0
- package/cli/lib/codex-sdk-runner.mjs +76 -0
- package/cli/lib/contracts.mjs +180 -0
- package/cli/lib/doctor.mjs +18 -0
- package/cli/lib/entrypoints.mjs +274 -0
- package/cli/lib/external-execution.mjs +101 -0
- package/cli/lib/fs-helpers.mjs +33 -0
- package/cli/lib/handoff.mjs +785 -0
- package/cli/lib/high-risk-admission.mjs +442 -0
- package/cli/lib/high-risk-decision.mjs +324 -0
- package/cli/lib/high-risk-ingest.mjs +317 -0
- package/cli/lib/high-risk-review.mjs +263 -0
- package/cli/lib/internal/contracts-loaders.mjs +132 -0
- package/cli/lib/internal/contracts-parse-high-risk.mjs +131 -0
- package/cli/lib/internal/contracts-parse.mjs +457 -0
- package/cli/lib/internal/contracts-validators.mjs +398 -0
- package/cli/lib/internal/doctor-bootstrap-surface.mjs +359 -0
- package/cli/lib/internal/doctor-delegated-surface.mjs +256 -0
- package/cli/lib/internal/doctor-finalize.mjs +385 -0
- package/cli/lib/internal/doctor-format.mjs +286 -0
- package/cli/lib/internal/doctor-inspectors.mjs +294 -0
- package/cli/lib/internal/doctor-state.mjs +205 -0
- package/cli/lib/internal/governance/ai/ai-context-budget-core.mjs +315 -0
- package/cli/lib/internal/governance/ai/ai-structure-budget-core.mjs +358 -0
- package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +155 -0
- package/cli/lib/internal/governance/ai/check-high-risk-doc-metadata-core.mjs +173 -0
- package/cli/lib/internal/governance/config.mjs +150 -0
- package/cli/lib/internal/governance/runner.mjs +35 -0
- package/cli/lib/internal/governance/shared/read-yaml-with-fragments.mjs +49 -0
- package/cli/lib/internal/validators-artifacts.mjs +515 -0
- package/cli/lib/internal/validators-shared.mjs +28 -0
- package/cli/lib/internal/validators-spec-helpers.mjs +186 -0
- package/cli/lib/internal/validators-spec.mjs +410 -0
- package/cli/lib/shared.mjs +83 -0
- package/cli/lib/topic-draft-packets.mjs +48 -0
- package/cli/lib/topic-goal.mjs +361 -0
- package/cli/lib/topic-runner.mjs +772 -0
- package/cli/lib/topic.mjs +93 -0
- package/cli/lib/ui.mjs +178 -0
- package/cli/lib/validators.mjs +78 -0
- package/cli/lib/value-helpers.mjs +24 -0
- package/cli/lib/yaml-helpers.mjs +133 -0
- package/cli/nimicoding.mjs +1 -0
- package/cli/seeds/bootstrap.mjs +47 -0
- package/config/audit-execution-artifacts.yaml +20 -0
- package/config/bootstrap.yaml +6 -0
- package/config/external-execution-artifacts.yaml +16 -0
- package/config/host-adapter.yaml +30 -0
- package/config/host-profile.yaml +29 -0
- package/config/installer-evidence.yaml +31 -0
- package/config/skill-installer.yaml +23 -0
- package/config/skill-manifest.yaml +46 -0
- package/config/skills.yaml +30 -0
- package/config/spec-generation-inputs.yaml +25 -0
- package/contracts/acceptance.schema.yaml +16 -0
- package/contracts/admission-checklist.schema.yaml +15 -0
- package/contracts/audit-chunk.schema.yaml +110 -0
- package/contracts/audit-closeout.schema.yaml +51 -0
- package/contracts/audit-finding.schema.yaml +61 -0
- package/contracts/audit-ledger.schema.yaml +138 -0
- package/contracts/audit-plan.schema.yaml +123 -0
- package/contracts/audit-remediation-map.schema.yaml +51 -0
- package/contracts/audit-rerun.schema.yaml +31 -0
- package/contracts/audit-sweep-result.yaml +49 -0
- package/contracts/authority-convergence-audit.schema.yaml +19 -0
- package/contracts/closeout.schema.yaml +25 -0
- package/contracts/decision-review.schema.yaml +16 -0
- package/contracts/doc-spec-audit-result.yaml +19 -0
- package/contracts/execution-packet.schema.yaml +49 -0
- package/contracts/external-host-compatibility.yaml +22 -0
- package/contracts/forbidden-shortcuts.catalog.yaml +23 -0
- package/contracts/high-risk-admission.schema.yaml +23 -0
- package/contracts/high-risk-execution-result.yaml +20 -0
- package/contracts/orchestration-state.schema.yaml +41 -0
- package/contracts/overflow-continuation.schema.yaml +12 -0
- package/contracts/packet.schema.yaml +30 -0
- package/contracts/pending-note.schema.yaml +17 -0
- package/contracts/prompt.schema.yaml +12 -0
- package/contracts/remediation.schema.yaml +16 -0
- package/contracts/result.schema.yaml +24 -0
- package/contracts/spec-generation-audit.schema.yaml +31 -0
- package/contracts/spec-generation-inputs.schema.yaml +39 -0
- package/contracts/spec-reconstruction-result.yaml +37 -0
- package/contracts/topic-goal.schema.yaml +78 -0
- package/contracts/topic-run-ledger.schema.yaml +72 -0
- package/contracts/topic-step-decision.schema.yaml +45 -0
- package/contracts/topic.schema.yaml +65 -0
- package/contracts/true-close.schema.yaml +15 -0
- package/contracts/wave.schema.yaml +29 -0
- package/contracts/worker-output.schema.yaml +15 -0
- package/methodology/audit-sweep-p0p1-recall.yaml +45 -0
- package/methodology/authority-convergence-policy.yaml +42 -0
- package/methodology/core.yaml +25 -0
- package/methodology/four-closure-policy.yaml +28 -0
- package/methodology/overflow-continuation-policy.yaml +14 -0
- package/methodology/role-separation-policy.yaml +28 -0
- package/methodology/skill-exchange-projection.yaml +114 -0
- package/methodology/skill-handoff.yaml +34 -0
- package/methodology/skill-installer-result.yaml +27 -0
- package/methodology/skill-installer-summary-projection.yaml +181 -0
- package/methodology/skill-runtime.yaml +23 -0
- package/methodology/spec-reconstruction.yaml +63 -0
- package/methodology/spec-target-truth-profile.yaml +53 -0
- package/methodology/topic-lifecycle-report.yaml +144 -0
- package/methodology/topic-lifecycle.yaml +37 -0
- package/methodology/topic-naming-ontology.yaml +21 -0
- package/methodology/topic-ontology.yaml +38 -0
- package/methodology/topic-validation-policy.yaml +9 -0
- package/methodology/wave-dag-policy.yaml +14 -0
- package/package.json +50 -0
- package/spec/_meta/command-gating-matrix.yaml +110 -0
- package/spec/_meta/generate-drift-migration-checklist.yaml +155 -0
- package/spec/_meta/governance-routing-cutover-checklist.yaml +35 -0
- package/spec/_meta/phase2-impacted-surface-matrix.yaml +44 -0
- package/spec/_meta/spec-authority-cutover-readiness.yaml +104 -0
- package/spec/_meta/spec-tree-model.yaml +72 -0
- package/spec/bootstrap-state.yaml +99 -0
- package/spec/product-scope.yaml +56 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
import { localize } from "../lib/ui.mjs";
|
|
2
|
+
import { loadGovernanceConfig, requireProfile } from "../lib/internal/governance/config.mjs";
|
|
3
|
+
import { evaluateAiContextBudget, formatBytes } from "../lib/internal/governance/ai/ai-context-budget-core.mjs";
|
|
4
|
+
import { evaluateAiStructureBudget } from "../lib/internal/governance/ai/ai-structure-budget-core.mjs";
|
|
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";
|
|
7
|
+
|
|
8
|
+
const SCOPES = new Set([
|
|
9
|
+
"agents-freshness",
|
|
10
|
+
"context-budget",
|
|
11
|
+
"structure-budget",
|
|
12
|
+
"high-risk-doc-metadata",
|
|
13
|
+
]);
|
|
14
|
+
|
|
15
|
+
function parseOptions(args) {
|
|
16
|
+
const options = {
|
|
17
|
+
profile: null,
|
|
18
|
+
scope: "all",
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
22
|
+
const arg = args[index];
|
|
23
|
+
|
|
24
|
+
if (arg === "--profile") {
|
|
25
|
+
const value = args[index + 1];
|
|
26
|
+
if (!value || value.startsWith("--")) {
|
|
27
|
+
return { ok: false, error: "nimicoding validate-ai-governance refused: --profile requires a value.\n" };
|
|
28
|
+
}
|
|
29
|
+
options.profile = value;
|
|
30
|
+
index += 1;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
if (arg === "--scope") {
|
|
35
|
+
const value = args[index + 1];
|
|
36
|
+
if (!value || value.startsWith("--")) {
|
|
37
|
+
return { ok: false, error: "nimicoding validate-ai-governance refused: --scope requires a value.\n" };
|
|
38
|
+
}
|
|
39
|
+
options.scope = value;
|
|
40
|
+
index += 1;
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
return {
|
|
45
|
+
ok: false,
|
|
46
|
+
error: `nimicoding validate-ai-governance refused: unknown option ${arg}.\n`,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
if (options.scope !== "all" && !SCOPES.has(options.scope)) {
|
|
51
|
+
return {
|
|
52
|
+
ok: false,
|
|
53
|
+
error: `nimicoding validate-ai-governance refused: unsupported --scope value ${options.scope}.\n`,
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
return { ok: true, options };
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function formatStructureRow(row) {
|
|
61
|
+
if (row.check === "depth") {
|
|
62
|
+
return `${row.file} [rule=${row.ruleId}] depth=${row.depth} base=${row.depthBase} subject=${row.depthSubject} (threshold warn>=${row.warningDepth} error>=${row.errorDepth})`;
|
|
63
|
+
}
|
|
64
|
+
return `${row.file} [rule=${row.ruleId}] basename=${row.basename} (forwarding shell outside allowed basename set)`;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
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
|
+
});
|
|
73
|
+
|
|
74
|
+
process.stdout.write(`ai-context-budget: config=${report.configPath}\n`);
|
|
75
|
+
process.stdout.write(`ai-context-budget: tracked=${report.totalTrackedFiles}, analyzed=${report.analyzedFiles}\n`);
|
|
76
|
+
|
|
77
|
+
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
|
+
);
|
|
81
|
+
}
|
|
82
|
+
for (const row of report.waivedErrors) {
|
|
83
|
+
const until = row.waiver?.until ? row.waiver.until.toISOString().slice(0, 10) : "n/a";
|
|
84
|
+
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
|
+
);
|
|
88
|
+
}
|
|
89
|
+
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`);
|
|
91
|
+
}
|
|
92
|
+
for (const row of report.invalidWaivers) {
|
|
93
|
+
process.stderr.write(`ERROR: invalid waiver for ${row.file}: ${row.detail}\n`);
|
|
94
|
+
}
|
|
95
|
+
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
|
+
);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
if (report.invalidWaivers.length > 0 || report.expiredWaivers.length > 0 || report.errors.length > 0) {
|
|
102
|
+
return 1;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
process.stdout.write("ai-context-budget: OK\n");
|
|
106
|
+
return 0;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
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
|
+
});
|
|
115
|
+
|
|
116
|
+
process.stdout.write(`ai-structure-budget: config=${report.configPath}\n`);
|
|
117
|
+
process.stdout.write(`ai-structure-budget: tracked=${report.totalTrackedFiles}, analyzed=${report.analyzedFiles}\n`);
|
|
118
|
+
for (const row of report.warnings) {
|
|
119
|
+
process.stderr.write(`WARN: ${formatStructureRow(row)}\n`);
|
|
120
|
+
}
|
|
121
|
+
for (const row of report.waivedErrors) {
|
|
122
|
+
const until = row.waiver?.untilDate ? row.waiver.untilDate.toISOString().slice(0, 10) : "n/a";
|
|
123
|
+
const reason = row.waiver?.reason || "no reason";
|
|
124
|
+
process.stderr.write(`WARN: WAIVED error for ${formatStructureRow(row)} until=${until} reason=${reason}\n`);
|
|
125
|
+
}
|
|
126
|
+
for (const row of report.expiredWaivers) {
|
|
127
|
+
process.stderr.write(`ERROR: expired waiver for ${formatStructureRow(row)}\n`);
|
|
128
|
+
}
|
|
129
|
+
for (const row of report.errors) {
|
|
130
|
+
process.stderr.write(`ERROR: ${formatStructureRow(row)}\n`);
|
|
131
|
+
}
|
|
132
|
+
if (report.errors.length > 0 || report.expiredWaivers.length > 0) {
|
|
133
|
+
return 1;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
process.stdout.write("ai-structure-budget: OK\n");
|
|
137
|
+
return 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
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
|
+
});
|
|
151
|
+
|
|
152
|
+
if (report.failures.length > 0) {
|
|
153
|
+
process.stderr.write("high-risk doc metadata check failed:\n");
|
|
154
|
+
for (const failure of report.failures) {
|
|
155
|
+
process.stderr.write(`- ${failure}\n`);
|
|
156
|
+
}
|
|
157
|
+
return 1;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
process.stdout.write(`high-risk doc metadata check passed (${report.scanned.length} file(s) scanned)\n`);
|
|
161
|
+
return 0;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
export async function runValidateAiGovernance(args) {
|
|
165
|
+
const parsed = parseOptions(args);
|
|
166
|
+
if (!parsed.ok) {
|
|
167
|
+
process.stderr.write(localize(parsed.error, parsed.error));
|
|
168
|
+
return 2;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
const governance = await loadGovernanceConfig(process.cwd());
|
|
172
|
+
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
|
+
));
|
|
177
|
+
return 2;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const profileCheck = requireProfile(governance.config, parsed.options.profile);
|
|
181
|
+
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
|
+
));
|
|
186
|
+
return 2;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
const scopes = parsed.options.scope === "all"
|
|
190
|
+
? ["agents-freshness", "context-budget", "structure-budget", "high-risk-doc-metadata"]
|
|
191
|
+
: [parsed.options.scope];
|
|
192
|
+
|
|
193
|
+
for (const scope of scopes) {
|
|
194
|
+
let exitCode = 0;
|
|
195
|
+
if (scope === "agents-freshness") {
|
|
196
|
+
exitCode = runAgentsFreshnessCheck({
|
|
197
|
+
projectRoot: process.cwd(),
|
|
198
|
+
config: governance.config.aiGovernance.agentsFreshness,
|
|
199
|
+
});
|
|
200
|
+
} else if (scope === "context-budget") {
|
|
201
|
+
exitCode = await runContextBudget(governance.config);
|
|
202
|
+
} else if (scope === "structure-budget") {
|
|
203
|
+
exitCode = await runStructureBudget(governance.config);
|
|
204
|
+
} else if (scope === "high-risk-doc-metadata") {
|
|
205
|
+
exitCode = await runHighRiskDocMetadata(governance.config);
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
if (exitCode !== 0) {
|
|
209
|
+
return exitCode;
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
return 0;
|
|
214
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { validateSpecAudit, buildValidatorCliReport } from "../lib/validators.mjs";
|
|
4
|
+
import { localize } from "../lib/ui.mjs";
|
|
5
|
+
|
|
6
|
+
export async function runValidateSpecAudit(args) {
|
|
7
|
+
const normalized = args[0] === "--" ? args.slice(1) : args;
|
|
8
|
+
let targetPath = ".nimi/spec/_meta/spec-generation-audit.yaml";
|
|
9
|
+
|
|
10
|
+
if (normalized.length > 1) {
|
|
11
|
+
process.stderr.write(localize(
|
|
12
|
+
"nimicoding validate-spec-audit refused: expected zero or one path argument.\n",
|
|
13
|
+
"nimicoding validate-spec-audit 已拒绝:期望零个或一个路径参数。\n",
|
|
14
|
+
));
|
|
15
|
+
return 2;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (normalized.length === 1) {
|
|
19
|
+
targetPath = normalized[0];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const absolutePath = path.resolve(process.cwd(), targetPath);
|
|
23
|
+
const report = await validateSpecAudit(absolutePath, { projectRoot: process.cwd() });
|
|
24
|
+
const cliReport = buildValidatorCliReport("validate-spec-audit", absolutePath, report);
|
|
25
|
+
process.stdout.write(`${JSON.stringify(cliReport, null, 2)}\n`);
|
|
26
|
+
return report.ok ? 0 : 1;
|
|
27
|
+
}
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
import { localize } from "../lib/ui.mjs";
|
|
2
|
+
import { loadGovernanceConfig, requireProfile } from "../lib/internal/governance/config.mjs";
|
|
3
|
+
import { runCommand } from "../lib/internal/governance/runner.mjs";
|
|
4
|
+
|
|
5
|
+
function parseOptions(args) {
|
|
6
|
+
const options = {
|
|
7
|
+
profile: null,
|
|
8
|
+
scope: "all",
|
|
9
|
+
};
|
|
10
|
+
|
|
11
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
12
|
+
const arg = args[index];
|
|
13
|
+
|
|
14
|
+
if (arg === "--profile") {
|
|
15
|
+
const value = args[index + 1];
|
|
16
|
+
if (!value || value.startsWith("--")) {
|
|
17
|
+
return { ok: false, error: "nimicoding validate-spec-governance refused: --profile requires a value.\n" };
|
|
18
|
+
}
|
|
19
|
+
options.profile = value;
|
|
20
|
+
index += 1;
|
|
21
|
+
continue;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
if (arg === "--scope") {
|
|
25
|
+
const value = args[index + 1];
|
|
26
|
+
if (!value || value.startsWith("--")) {
|
|
27
|
+
return { ok: false, error: "nimicoding validate-spec-governance refused: --scope requires a value.\n" };
|
|
28
|
+
}
|
|
29
|
+
options.scope = value;
|
|
30
|
+
index += 1;
|
|
31
|
+
continue;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
return {
|
|
35
|
+
ok: false,
|
|
36
|
+
error: `nimicoding validate-spec-governance refused: unknown option ${arg}.\n`,
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return { ok: true, options };
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
function resolveScopes(scope, governanceConfig) {
|
|
44
|
+
const configuredScopes = Object.keys(governanceConfig.specGovernance.validateCommands || {});
|
|
45
|
+
if (scope === "all") {
|
|
46
|
+
return {
|
|
47
|
+
ok: true,
|
|
48
|
+
scopes: configuredScopes,
|
|
49
|
+
error: null,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
if (!configuredScopes.includes(scope)) {
|
|
53
|
+
return {
|
|
54
|
+
ok: false,
|
|
55
|
+
scopes: [],
|
|
56
|
+
error: `nimicoding validate-spec-governance refused: unsupported --scope value ${scope}.\n`,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
return {
|
|
60
|
+
ok: true,
|
|
61
|
+
scopes: [scope],
|
|
62
|
+
error: null,
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export async function runValidateSpecGovernance(args) {
|
|
67
|
+
const parsed = parseOptions(args);
|
|
68
|
+
if (!parsed.ok) {
|
|
69
|
+
process.stderr.write(localize(parsed.error, parsed.error));
|
|
70
|
+
return 2;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const governance = await loadGovernanceConfig(process.cwd());
|
|
74
|
+
if (!governance.ok) {
|
|
75
|
+
process.stderr.write(localize(
|
|
76
|
+
`nimicoding validate-spec-governance refused: ${governance.reason} at ${governance.path}.\n`,
|
|
77
|
+
`nimicoding validate-spec-governance 已拒绝:${governance.path} 的治理配置不可用。\n`,
|
|
78
|
+
));
|
|
79
|
+
return 2;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
const profileCheck = requireProfile(governance.config, parsed.options.profile);
|
|
83
|
+
if (!profileCheck.ok) {
|
|
84
|
+
process.stderr.write(localize(
|
|
85
|
+
`nimicoding validate-spec-governance refused: ${profileCheck.error}.\n`,
|
|
86
|
+
`nimicoding validate-spec-governance 已拒绝:${profileCheck.error}。\n`,
|
|
87
|
+
));
|
|
88
|
+
return 2;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
const scopeResolution = resolveScopes(parsed.options.scope, governance.config);
|
|
92
|
+
if (!scopeResolution.ok) {
|
|
93
|
+
process.stderr.write(localize(scopeResolution.error, scopeResolution.error));
|
|
94
|
+
return 2;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
let failed = false;
|
|
98
|
+
for (const scope of scopeResolution.scopes) {
|
|
99
|
+
const commands = governance.config.specGovernance.validateCommands[scope] || [];
|
|
100
|
+
if (commands.length === 0) {
|
|
101
|
+
process.stderr.write(localize(
|
|
102
|
+
`nimicoding validate-spec-governance refused: scope ${scope} is not configured in .nimi/config/governance.yaml.\n`,
|
|
103
|
+
`nimicoding validate-spec-governance 已拒绝:.nimi/config/governance.yaml 未配置 ${scope}。\n`,
|
|
104
|
+
));
|
|
105
|
+
return 2;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
for (const command of commands) {
|
|
109
|
+
const result = runCommand(command, { cwd: process.cwd() });
|
|
110
|
+
if (result.stdout) process.stdout.write(result.stdout);
|
|
111
|
+
if (result.stderr) process.stderr.write(result.stderr);
|
|
112
|
+
if (!result.ok) {
|
|
113
|
+
failed = true;
|
|
114
|
+
break;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
if (failed) {
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return failed ? 1 : 0;
|
|
124
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import path from "node:path";
|
|
2
|
+
|
|
3
|
+
import { buildValidatorCliReport, validateSpecTree } from "../lib/validators.mjs";
|
|
4
|
+
import { localize } from "../lib/ui.mjs";
|
|
5
|
+
|
|
6
|
+
export async function runValidateSpecTree(args) {
|
|
7
|
+
const normalized = args[0] === "--" ? args.slice(1) : args;
|
|
8
|
+
let targetRoot = ".nimi/spec";
|
|
9
|
+
|
|
10
|
+
if (normalized.length > 1) {
|
|
11
|
+
process.stderr.write(localize(
|
|
12
|
+
"nimicoding validate-spec-tree refused: expected zero or one path argument.\n",
|
|
13
|
+
"nimicoding validate-spec-tree 已拒绝:期望零个或一个路径参数。\n",
|
|
14
|
+
));
|
|
15
|
+
return 2;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
if (normalized.length === 1) {
|
|
19
|
+
targetRoot = normalized[0];
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const absoluteRoot = path.resolve(process.cwd(), targetRoot);
|
|
23
|
+
const report = await validateSpecTree(absoluteRoot, { projectRoot: process.cwd() });
|
|
24
|
+
const cliReport = buildValidatorCliReport("validate-spec-tree", absoluteRoot, report);
|
|
25
|
+
process.stdout.write(`${JSON.stringify(cliReport, null, 2)}\n`);
|
|
26
|
+
return report.ok ? 0 : 1;
|
|
27
|
+
}
|