@nimiplatform/nimi-coding 0.5.0 → 0.6.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/CHANGELOG.md +7 -0
- package/CONTRIBUTING.md +1 -1
- package/README.md +50 -25
- package/README.zh-CN.md +50 -25
- package/cli/commands/clear.mjs +3 -2
- package/cli/commands/code.mjs +225 -0
- package/cli/commands/start.mjs +3 -2
- package/cli/constants.mjs +2 -1
- package/cli/dev/run-cli-smoke.mjs +6 -0
- package/cli/help.mjs +8 -3
- package/cli/index.mjs +3 -2
- package/cli/lib/authority/diagnostics.mjs +3 -1
- package/cli/lib/code/authority-annotation-response.mjs +43 -0
- package/cli/lib/code/authority-annotation-scan.mjs +162 -0
- package/cli/lib/code/authority-annotations.mjs +293 -0
- package/cli/lib/code/context.mjs +710 -0
- package/cli/lib/code/response.mjs +165 -0
- package/cli/lib/doctor.mjs +3 -2
- package/cli/lib/entrypoints.mjs +12 -5
- package/cli/seeds/seed-policy.yaml +2 -2
- package/methodology/authority-authoring.yaml +67 -52
- package/methodology/core.yaml +6 -4
- package/package.json +5 -3
- package/spec/code-authority-annotations.yaml +42 -0
- package/spec/code-context.yaml +38 -0
- package/spec/product-scope.yaml +8 -3
- package/cli/commands/validate-ai-governance.mjs +0 -335
- package/cli/lib/internal/governance/ai/ai-context-budget-core.mjs +0 -377
- package/cli/lib/internal/governance/ai/ai-structure-budget-core.mjs +0 -376
- package/cli/lib/internal/governance/ai/check-agents-freshness.mjs +0 -155
- package/cli/lib/internal/governance/ai/check-high-risk-doc-metadata-core.mjs +0 -173
- package/cli/lib/internal/governance/config.mjs +0 -114
- package/cli/lib/internal/governance/shared/read-yaml-with-fragments.mjs +0 -49
|
@@ -1,114 +0,0 @@
|
|
|
1
|
-
import path from "node:path";
|
|
2
|
-
|
|
3
|
-
import { readTextIfFile } from "../../fs-helpers.mjs";
|
|
4
|
-
import { parseYamlText } from "../../yaml-helpers.mjs";
|
|
5
|
-
import { isPlainObject } from "../../value-helpers.mjs";
|
|
6
|
-
|
|
7
|
-
const GOVERNANCE_CONFIG_RELATIVE_PATH = ".nimi/config/governance.yaml";
|
|
8
|
-
|
|
9
|
-
function normalizeAgentsTarget(entry) {
|
|
10
|
-
if (!isPlainObject(entry) || typeof entry.rel !== "string") {
|
|
11
|
-
return null;
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
return {
|
|
15
|
-
rel: entry.rel.trim(),
|
|
16
|
-
maxLines: Number(entry.max_lines ?? entry.maxLines ?? 0),
|
|
17
|
-
};
|
|
18
|
-
}
|
|
19
|
-
|
|
20
|
-
function normalizeGovernanceConfig(parsed) {
|
|
21
|
-
if (!isPlainObject(parsed)) {
|
|
22
|
-
return null;
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
const profileId = typeof parsed.profile_id === "string" ? parsed.profile_id.trim() : null;
|
|
26
|
-
const aiGovernance = isPlainObject(parsed.ai_governance) ? parsed.ai_governance : {};
|
|
27
|
-
const agentsFreshness = isPlainObject(aiGovernance.agents_freshness)
|
|
28
|
-
? aiGovernance.agents_freshness
|
|
29
|
-
: {};
|
|
30
|
-
|
|
31
|
-
const normalized = {
|
|
32
|
-
profileId,
|
|
33
|
-
aiGovernance: {
|
|
34
|
-
agentsFreshness: {
|
|
35
|
-
targets: Array.isArray(agentsFreshness.targets)
|
|
36
|
-
? agentsFreshness.targets.map(normalizeAgentsTarget).filter(Boolean)
|
|
37
|
-
: [],
|
|
38
|
-
requiredSections: Array.isArray(agentsFreshness.required_sections)
|
|
39
|
-
? agentsFreshness.required_sections
|
|
40
|
-
.map((entry) => String(entry || "").trim())
|
|
41
|
-
.filter(Boolean)
|
|
42
|
-
: [],
|
|
43
|
-
staleTokens: Array.isArray(agentsFreshness.stale_tokens)
|
|
44
|
-
? agentsFreshness.stale_tokens.map((entry) => String(entry || "").trim()).filter(Boolean)
|
|
45
|
-
: [],
|
|
46
|
-
},
|
|
47
|
-
contextBudget: isPlainObject(aiGovernance.context_budget)
|
|
48
|
-
? aiGovernance.context_budget
|
|
49
|
-
: {},
|
|
50
|
-
structureBudget: isPlainObject(aiGovernance.structure_budget)
|
|
51
|
-
? aiGovernance.structure_budget
|
|
52
|
-
: {},
|
|
53
|
-
highRiskDocMetadata: isPlainObject(aiGovernance.high_risk_doc_metadata)
|
|
54
|
-
? aiGovernance.high_risk_doc_metadata
|
|
55
|
-
: {},
|
|
56
|
-
},
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
if (!normalized.profileId) {
|
|
60
|
-
return null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
return normalized;
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
export async function loadGovernanceConfig(projectRoot = process.cwd()) {
|
|
67
|
-
const configPath = path.join(projectRoot, GOVERNANCE_CONFIG_RELATIVE_PATH);
|
|
68
|
-
const text = await readTextIfFile(configPath);
|
|
69
|
-
|
|
70
|
-
if (text === null) {
|
|
71
|
-
return {
|
|
72
|
-
ok: false,
|
|
73
|
-
path: configPath,
|
|
74
|
-
reason: "missing governance config",
|
|
75
|
-
config: null,
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
const parsed = parseYamlText(text);
|
|
80
|
-
const normalized = normalizeGovernanceConfig(parsed);
|
|
81
|
-
|
|
82
|
-
if (!normalized) {
|
|
83
|
-
return {
|
|
84
|
-
ok: false,
|
|
85
|
-
path: configPath,
|
|
86
|
-
reason: "invalid governance config",
|
|
87
|
-
config: null,
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
return {
|
|
92
|
-
ok: true,
|
|
93
|
-
path: configPath,
|
|
94
|
-
reason: null,
|
|
95
|
-
config: normalized,
|
|
96
|
-
};
|
|
97
|
-
}
|
|
98
|
-
|
|
99
|
-
export function requireProfile(governanceConfig, requestedProfile) {
|
|
100
|
-
const effectiveProfile = requestedProfile || governanceConfig.profileId;
|
|
101
|
-
if (effectiveProfile !== governanceConfig.profileId) {
|
|
102
|
-
return {
|
|
103
|
-
ok: false,
|
|
104
|
-
error: `governance profile mismatch: expected ${governanceConfig.profileId} but received ${effectiveProfile}`,
|
|
105
|
-
profile: effectiveProfile,
|
|
106
|
-
};
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
return {
|
|
110
|
-
ok: true,
|
|
111
|
-
error: null,
|
|
112
|
-
profile: effectiveProfile,
|
|
113
|
-
};
|
|
114
|
-
}
|
|
@@ -1,49 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs';
|
|
2
|
-
import path from 'node:path';
|
|
3
|
-
import YAML from 'yaml';
|
|
4
|
-
|
|
5
|
-
function isRecord(value) {
|
|
6
|
-
return Boolean(value) && typeof value === 'object' && !Array.isArray(value);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
function mergeFragmentValues(key, currentValue, nextValue, sourcePath) {
|
|
10
|
-
if (typeof currentValue === 'undefined') {
|
|
11
|
-
return nextValue;
|
|
12
|
-
}
|
|
13
|
-
if (Array.isArray(currentValue) && Array.isArray(nextValue)) {
|
|
14
|
-
return [...currentValue, ...nextValue];
|
|
15
|
-
}
|
|
16
|
-
if (isRecord(currentValue) && isRecord(nextValue)) {
|
|
17
|
-
return { ...currentValue, ...nextValue };
|
|
18
|
-
}
|
|
19
|
-
throw new Error(`fragment merge type mismatch for ${key} in ${sourcePath}`);
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
export function readYamlWithFragments(filePath) {
|
|
23
|
-
const raw = fs.readFileSync(filePath, 'utf8');
|
|
24
|
-
const parsed = YAML.parse(raw);
|
|
25
|
-
if (!isRecord(parsed) || !isRecord(parsed.fragments)) {
|
|
26
|
-
return parsed;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const resolved = { ...parsed };
|
|
30
|
-
const fragmentEntries = Object.entries(parsed.fragments);
|
|
31
|
-
delete resolved.fragments;
|
|
32
|
-
|
|
33
|
-
for (const [key, fragmentSpec] of fragmentEntries) {
|
|
34
|
-
const refs = Array.isArray(fragmentSpec) ? fragmentSpec : [fragmentSpec];
|
|
35
|
-
let mergedValue;
|
|
36
|
-
for (const ref of refs) {
|
|
37
|
-
const relativeRef = String(ref || '').trim();
|
|
38
|
-
if (!relativeRef) {
|
|
39
|
-
throw new Error(`empty fragment reference for ${key} in ${filePath}`);
|
|
40
|
-
}
|
|
41
|
-
const fragmentPath = path.resolve(path.dirname(filePath), relativeRef);
|
|
42
|
-
const fragmentValue = readYamlWithFragments(fragmentPath);
|
|
43
|
-
mergedValue = mergeFragmentValues(key, mergedValue, fragmentValue, filePath);
|
|
44
|
-
}
|
|
45
|
-
resolved[key] = mergedValue;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
return resolved;
|
|
49
|
-
}
|