@veewo/gitnexus 1.4.11-rc.2 → 1.5.0-rc.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/dist/benchmark/u2-e2e/hydration-policy-repeatability-runner.d.ts +55 -0
- package/dist/benchmark/u2-e2e/hydration-policy-repeatability-runner.js +190 -0
- package/dist/benchmark/u2-e2e/hydration-policy-repeatability-runner.test.js +13 -0
- package/dist/benchmark/u2-e2e/phase1-process-ref-acceptance-runner.d.ts +22 -0
- package/dist/benchmark/u2-e2e/phase1-process-ref-acceptance-runner.js +100 -0
- package/dist/benchmark/u2-e2e/phase1-process-ref-acceptance-runner.test.d.ts +1 -0
- package/dist/benchmark/u2-e2e/phase1-process-ref-acceptance-runner.test.js +13 -0
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.d.ts +27 -0
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.js +118 -0
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.test.d.ts +1 -0
- package/dist/benchmark/u2-e2e/phase2-runtime-claim-acceptance-runner.test.js +16 -0
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.d.ts +60 -0
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.js +331 -0
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.d.ts +1 -0
- package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.js +42 -0
- package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.js +4 -4
- package/dist/benchmark/unity-lazy-context-sampler.d.ts +6 -0
- package/dist/benchmark/unity-lazy-context-sampler.js +49 -13
- package/dist/benchmark/unity-lazy-context-sampler.test.js +4 -0
- package/dist/cli/ai-context.js +6 -1
- package/dist/cli/eval-server.js +0 -3
- package/dist/cli/index.js +8 -0
- package/dist/cli/mcp.js +0 -3
- package/dist/cli/rule-lab.d.ts +42 -0
- package/dist/cli/rule-lab.js +157 -0
- package/dist/cli/rule-lab.test.d.ts +1 -0
- package/dist/cli/rule-lab.test.js +11 -0
- package/dist/cli/tool.d.ts +7 -1
- package/dist/cli/tool.js +6 -0
- package/dist/core/config/unity-config.d.ts +20 -0
- package/dist/core/config/unity-config.js +46 -0
- package/dist/core/graph/types.d.ts +1 -1
- package/dist/core/ingestion/pipeline.js +38 -13
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.d.ts +0 -2
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.js +26 -213
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.test.js +1 -1
- package/dist/core/ingestion/unity-resource-processor.js +87 -22
- package/dist/core/ingestion/unity-resource-processor.test.js +67 -2
- package/dist/core/ingestion/unity-runtime-binding-rules.d.ts +11 -0
- package/dist/core/ingestion/unity-runtime-binding-rules.js +179 -0
- package/dist/core/unity/options.d.ts +4 -0
- package/dist/core/unity/options.js +18 -0
- package/dist/core/unity/options.test.js +11 -1
- package/dist/core/unity/resolver.js +11 -1
- package/dist/core/unity/resolver.test.js +62 -0
- package/dist/core/unity/yaml-object-graph.js +1 -1
- package/dist/core/unity/yaml-object-graph.test.js +16 -0
- package/dist/mcp/local/derived-process-reader.d.ts +2 -0
- package/dist/mcp/local/derived-process-reader.js +15 -0
- package/dist/mcp/local/local-backend.d.ts +56 -0
- package/dist/mcp/local/local-backend.js +1003 -53
- package/dist/mcp/local/local-backend.unity-merge.test.js +1 -1
- package/dist/mcp/local/process-confidence.js +1 -1
- package/dist/mcp/local/process-evidence.d.ts +1 -0
- package/dist/mcp/local/process-evidence.js +22 -0
- package/dist/mcp/local/process-evidence.test.js +11 -1
- package/dist/mcp/local/process-ref.d.ts +24 -0
- package/dist/mcp/local/process-ref.js +33 -0
- package/dist/mcp/local/process-ref.test.d.ts +1 -0
- package/dist/mcp/local/process-ref.test.js +24 -0
- package/dist/mcp/local/runtime-chain-verify.d.ts +15 -1
- package/dist/mcp/local/runtime-chain-verify.js +191 -187
- package/dist/mcp/local/runtime-chain-verify.test.js +546 -19
- package/dist/mcp/local/runtime-claim-rule-registry.d.ts +63 -0
- package/dist/mcp/local/runtime-claim-rule-registry.js +308 -0
- package/dist/mcp/local/runtime-claim-rule-registry.test.d.ts +1 -0
- package/dist/mcp/local/runtime-claim-rule-registry.test.js +215 -0
- package/dist/mcp/local/runtime-claim.d.ts +38 -0
- package/dist/mcp/local/runtime-claim.js +54 -0
- package/dist/mcp/local/runtime-claim.test.d.ts +1 -0
- package/dist/mcp/local/runtime-claim.test.js +27 -0
- package/dist/mcp/local/unity-enrichment.d.ts +1 -0
- package/dist/mcp/local/unity-enrichment.js +1 -1
- package/dist/mcp/local/unity-evidence-view.d.ts +26 -0
- package/dist/mcp/local/unity-evidence-view.js +96 -0
- package/dist/mcp/local/unity-evidence-view.test.d.ts +1 -0
- package/dist/mcp/local/unity-evidence-view.test.js +39 -0
- package/dist/mcp/local/unity-lazy-hydrator.d.ts +2 -2
- package/dist/mcp/local/unity-lazy-hydrator.js +3 -3
- package/dist/mcp/local/unity-lazy-hydrator.test.js +4 -4
- package/dist/mcp/local/unity-parity-cache.js +2 -6
- package/dist/mcp/local/unity-parity-seed-loader.d.ts +1 -0
- package/dist/mcp/local/unity-parity-seed-loader.js +10 -16
- package/dist/mcp/local/unity-parity-seed-loader.test.js +3 -12
- package/dist/mcp/local/unity-runtime-hydration.d.ts +3 -2
- package/dist/mcp/local/unity-runtime-hydration.js +13 -16
- package/dist/mcp/local/unity-runtime-hydration.test.js +15 -1
- package/dist/mcp/resources.js +13 -0
- package/dist/mcp/tools.js +166 -13
- package/dist/rule-lab/analyze.d.ts +12 -0
- package/dist/rule-lab/analyze.js +90 -0
- package/dist/rule-lab/analyze.test.d.ts +1 -0
- package/dist/rule-lab/analyze.test.js +28 -0
- package/dist/rule-lab/compile.d.ts +5 -0
- package/dist/rule-lab/compile.js +51 -0
- package/dist/rule-lab/compiled-bundles.d.ts +30 -0
- package/dist/rule-lab/compiled-bundles.js +36 -0
- package/dist/rule-lab/curate.d.ts +32 -0
- package/dist/rule-lab/curate.js +134 -0
- package/dist/rule-lab/curate.test.d.ts +1 -0
- package/dist/rule-lab/curate.test.js +72 -0
- package/dist/rule-lab/discover.d.ts +13 -0
- package/dist/rule-lab/discover.js +74 -0
- package/dist/rule-lab/discover.test.d.ts +1 -0
- package/dist/rule-lab/discover.test.js +42 -0
- package/dist/rule-lab/paths.d.ts +21 -0
- package/dist/rule-lab/paths.js +37 -0
- package/dist/rule-lab/paths.test.d.ts +1 -0
- package/dist/rule-lab/paths.test.js +46 -0
- package/dist/rule-lab/promote.d.ts +26 -0
- package/dist/rule-lab/promote.js +314 -0
- package/dist/rule-lab/promote.test.d.ts +1 -0
- package/dist/rule-lab/promote.test.js +164 -0
- package/dist/rule-lab/regress.d.ts +60 -0
- package/dist/rule-lab/regress.js +122 -0
- package/dist/rule-lab/regress.test.d.ts +1 -0
- package/dist/rule-lab/regress.test.js +68 -0
- package/dist/rule-lab/review-pack.d.ts +31 -0
- package/dist/rule-lab/review-pack.js +125 -0
- package/dist/rule-lab/review-pack.test.d.ts +1 -0
- package/dist/rule-lab/review-pack.test.js +49 -0
- package/dist/rule-lab/types.d.ts +99 -0
- package/dist/rule-lab/types.js +1 -0
- package/package.json +1 -1
- package/skills/_shared/unity-hydration-contract.md +11 -0
- package/skills/_shared/unity-ui-trace-contract.md +33 -0
- package/skills/gitnexus-cli.md +14 -25
- package/skills/gitnexus-guide.md +2 -0
- package/skills/gitnexus-unity-rule-gen.md +318 -0
- package/dist/core/ingestion/unity-lifecycle-config.d.ts +0 -5
- package/dist/core/ingestion/unity-lifecycle-config.js +0 -25
- package/dist/mcp/local/unity-lazy-config.d.ts +0 -6
- package/dist/mcp/local/unity-lazy-config.js +0 -7
- package/dist/mcp/local/unity-lazy-config.test.js +0 -9
- package/dist/mcp/local/unity-process-confidence-config.d.ts +0 -1
- package/dist/mcp/local/unity-process-confidence-config.js +0 -4
- package/dist/mcp/local/unity-runtime-chain-verify-config.d.ts +0 -1
- package/dist/mcp/local/unity-runtime-chain-verify-config.js +0 -10
- /package/dist/{mcp/local/unity-lazy-config.test.d.ts → benchmark/u2-e2e/hydration-policy-repeatability-runner.test.d.ts} +0 -0
|
@@ -0,0 +1,331 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { discoverRuleLabRun } from '../../rule-lab/discover.js';
|
|
4
|
+
import { analyzeRuleLabSlice } from '../../rule-lab/analyze.js';
|
|
5
|
+
import { buildReviewPack } from '../../rule-lab/review-pack.js';
|
|
6
|
+
import { curateRuleLabSlice } from '../../rule-lab/curate.js';
|
|
7
|
+
import { promoteCuratedRules } from '../../rule-lab/promote.js';
|
|
8
|
+
import { runRuleLabRegress } from '../../rule-lab/regress.js';
|
|
9
|
+
function commandFor(stage, input) {
|
|
10
|
+
switch (stage) {
|
|
11
|
+
case 'discover':
|
|
12
|
+
return 'gitnexus rule-lab discover --scope full';
|
|
13
|
+
case 'analyze':
|
|
14
|
+
return `gitnexus rule-lab analyze --run-id ${input.runId} --slice-id ${input.sliceId}`;
|
|
15
|
+
case 'review-pack':
|
|
16
|
+
return `gitnexus rule-lab review-pack --run-id ${input.runId} --slice-id ${input.sliceId} --max-tokens 6000`;
|
|
17
|
+
case 'curate':
|
|
18
|
+
return `gitnexus rule-lab curate --run-id ${input.runId} --slice-id ${input.sliceId} --input-path ${input.curationInputPath}`;
|
|
19
|
+
case 'promote':
|
|
20
|
+
return `gitnexus rule-lab promote --run-id ${input.runId} --slice-id ${input.sliceId}`;
|
|
21
|
+
case 'regress':
|
|
22
|
+
return `gitnexus rule-lab regress --precision 0.93 --coverage 0.85 --run-id ${input.runId}`;
|
|
23
|
+
default:
|
|
24
|
+
return 'gitnexus rule-lab <unknown>';
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async function mustExist(filePath) {
|
|
28
|
+
await fs.access(filePath);
|
|
29
|
+
}
|
|
30
|
+
function buildFailureTaxonomy(runId) {
|
|
31
|
+
return [
|
|
32
|
+
{
|
|
33
|
+
code: 'rule_not_matched',
|
|
34
|
+
retry_hint: 'confirm trigger_family tokens and rerun discover/analyze/promote',
|
|
35
|
+
repro_command: `gitnexus rule-lab analyze --run-id ${runId} --slice-id <slice_id>`,
|
|
36
|
+
},
|
|
37
|
+
{
|
|
38
|
+
code: 'rule_matched_but_evidence_missing',
|
|
39
|
+
retry_hint: 'add stronger confirmed_chain anchors in curation input and promote again',
|
|
40
|
+
repro_command: `gitnexus rule-lab curate --run-id ${runId} --slice-id <slice_id> --input-path <curation-input.json>`,
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
code: 'precision_below_threshold',
|
|
44
|
+
retry_hint: 'trim noisy rules or tighten curation semantics before regress',
|
|
45
|
+
repro_command: `gitnexus rule-lab regress --precision 0.85 --coverage 0.92 --run-id ${runId}`,
|
|
46
|
+
},
|
|
47
|
+
{
|
|
48
|
+
code: 'coverage_below_threshold',
|
|
49
|
+
retry_hint: 'add additional approved rules/slices and rerun regress',
|
|
50
|
+
repro_command: `gitnexus rule-lab regress --precision 0.95 --coverage 0.70 --run-id ${runId}`,
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
code: 'probe_pass_rate_below_threshold',
|
|
54
|
+
retry_hint: 're-run regress with refreshed probes and inspect replay commands',
|
|
55
|
+
repro_command: `gitnexus rule-lab regress --precision 0.95 --coverage 0.90 --run-id ${runId}`,
|
|
56
|
+
},
|
|
57
|
+
{
|
|
58
|
+
code: 'static_hardcode_detected',
|
|
59
|
+
retry_hint: 'remove project-specific reload fallback constants/branches from runtime verifier',
|
|
60
|
+
repro_command: 'rg -n "RESOURCE_ASSET_PATH|GRAPH_ASSET_PATH|RELOAD_GUID|shouldVerifyReloadChain|verifyReloadRuntimeChain" gitnexus/src/mcp/local/runtime-chain-verify.ts',
|
|
61
|
+
},
|
|
62
|
+
{
|
|
63
|
+
code: 'dsl_lint_failed',
|
|
64
|
+
retry_hint: 'fix promoted DSL placeholders and rerun promote/regress',
|
|
65
|
+
repro_command: `gitnexus rule-lab promote --run-id ${runId} --slice-id <slice_id>`,
|
|
66
|
+
},
|
|
67
|
+
];
|
|
68
|
+
}
|
|
69
|
+
function hasDslPlaceholders(text) {
|
|
70
|
+
return /(^|\s)(unknown|todo|tbd)(\s|$)|<[^>]+>/i.test(text);
|
|
71
|
+
}
|
|
72
|
+
async function buildAuthenticityChecks(input) {
|
|
73
|
+
const verifierPath = path.join(input.repoPath, 'gitnexus', 'src', 'mcp', 'local', 'runtime-chain-verify.ts');
|
|
74
|
+
const verifierRaw = await fs.readFile(verifierPath, 'utf-8');
|
|
75
|
+
const blockedSymbols = [
|
|
76
|
+
'RESOURCE_ASSET_PATH',
|
|
77
|
+
'GRAPH_ASSET_PATH',
|
|
78
|
+
'RELOAD_GUID',
|
|
79
|
+
'shouldVerifyReloadChain',
|
|
80
|
+
'verifyReloadRuntimeChain',
|
|
81
|
+
].filter((token) => verifierRaw.includes(token));
|
|
82
|
+
let dslLintPass = true;
|
|
83
|
+
for (const promotedPath of input.promotedFiles) {
|
|
84
|
+
const raw = await fs.readFile(promotedPath, 'utf-8');
|
|
85
|
+
if (hasDslPlaceholders(raw)) {
|
|
86
|
+
dslLintPass = false;
|
|
87
|
+
break;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return {
|
|
91
|
+
static_no_hardcoded_reload: {
|
|
92
|
+
pass: blockedSymbols.length === 0,
|
|
93
|
+
blocked_symbols: blockedSymbols,
|
|
94
|
+
},
|
|
95
|
+
dsl_lint_pass: dslLintPass,
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
export async function buildPhase5RuleLabAcceptanceReport(input) {
|
|
99
|
+
const repoPath = path.resolve(input.repoPath || process.cwd());
|
|
100
|
+
const stageCoverage = [];
|
|
101
|
+
const discover = await discoverRuleLabRun({ repoPath, scope: 'full', seed: input.seed || 'phase5-acceptance' });
|
|
102
|
+
stageCoverage.push({
|
|
103
|
+
stage: 'discover',
|
|
104
|
+
command: commandFor('discover', {}),
|
|
105
|
+
status: 'passed',
|
|
106
|
+
});
|
|
107
|
+
if (discover.manifest.slices.length === 0) {
|
|
108
|
+
throw new Error('discover produced no slices');
|
|
109
|
+
}
|
|
110
|
+
const sliceId = discover.manifest.slices[0].id;
|
|
111
|
+
const runId = discover.runId;
|
|
112
|
+
const analyze = await analyzeRuleLabSlice({ repoPath, runId, sliceId });
|
|
113
|
+
stageCoverage.push({
|
|
114
|
+
stage: 'analyze',
|
|
115
|
+
command: commandFor('analyze', { runId, sliceId }),
|
|
116
|
+
status: 'passed',
|
|
117
|
+
});
|
|
118
|
+
const reviewPack = await buildReviewPack({ repoPath, runId, sliceId, maxTokens: 6000 });
|
|
119
|
+
stageCoverage.push({
|
|
120
|
+
stage: 'review-pack',
|
|
121
|
+
command: commandFor('review-pack', { runId, sliceId }),
|
|
122
|
+
status: 'passed',
|
|
123
|
+
});
|
|
124
|
+
const firstCandidate = analyze.candidates[0];
|
|
125
|
+
const curationInputPath = path.join(repoPath, '.gitnexus', 'rules', 'lab', 'runs', runId, 'slices', sliceId, 'curation-input.json');
|
|
126
|
+
await fs.writeFile(curationInputPath, `${JSON.stringify({
|
|
127
|
+
run_id: runId,
|
|
128
|
+
slice_id: sliceId,
|
|
129
|
+
curated: [
|
|
130
|
+
{
|
|
131
|
+
id: firstCandidate.id,
|
|
132
|
+
rule_id: 'demo.startup.v1',
|
|
133
|
+
title: 'startup startup graph',
|
|
134
|
+
match: {
|
|
135
|
+
trigger_tokens: ['startup'],
|
|
136
|
+
},
|
|
137
|
+
topology: Array.isArray(firstCandidate.topology) && firstCandidate.topology.length > 0
|
|
138
|
+
? firstCandidate.topology
|
|
139
|
+
: firstCandidate.evidence.hops.map((hop) => ({
|
|
140
|
+
hop: hop.hop_type,
|
|
141
|
+
from: { entity: 'resource' },
|
|
142
|
+
to: { entity: 'script' },
|
|
143
|
+
edge: { kind: 'binds_script' },
|
|
144
|
+
})),
|
|
145
|
+
closure: {
|
|
146
|
+
required_hops: Array.isArray(firstCandidate.topology) && firstCandidate.topology.length > 0
|
|
147
|
+
? firstCandidate.topology.map((hop) => hop.hop)
|
|
148
|
+
: ['code_runtime'],
|
|
149
|
+
failure_map: {
|
|
150
|
+
missing_evidence: 'rule_matched_but_evidence_missing',
|
|
151
|
+
},
|
|
152
|
+
},
|
|
153
|
+
claims: {
|
|
154
|
+
guarantees: ['startup trigger matching is confirmed'],
|
|
155
|
+
non_guarantees: ['does not prove full runtime ordering'],
|
|
156
|
+
next_action: 'gitnexus query "Startup Graph Trigger"',
|
|
157
|
+
},
|
|
158
|
+
confirmed_chain: {
|
|
159
|
+
steps: firstCandidate.evidence.hops.map((hop) => ({ ...hop, hop_type: 'code_runtime' })),
|
|
160
|
+
},
|
|
161
|
+
guarantees: ['startup trigger matching is confirmed'],
|
|
162
|
+
non_guarantees: ['does not prove full runtime ordering'],
|
|
163
|
+
},
|
|
164
|
+
],
|
|
165
|
+
}, null, 2)}\n`, 'utf-8');
|
|
166
|
+
const curated = await curateRuleLabSlice({ repoPath, runId, sliceId, inputPath: curationInputPath });
|
|
167
|
+
stageCoverage.push({
|
|
168
|
+
stage: 'curate',
|
|
169
|
+
command: commandFor('curate', { runId, sliceId, curationInputPath }),
|
|
170
|
+
status: 'passed',
|
|
171
|
+
});
|
|
172
|
+
const promoted = await promoteCuratedRules({ repoPath, runId, sliceId, version: '1.0.0' });
|
|
173
|
+
stageCoverage.push({
|
|
174
|
+
stage: 'promote',
|
|
175
|
+
command: commandFor('promote', { runId, sliceId }),
|
|
176
|
+
status: 'passed',
|
|
177
|
+
});
|
|
178
|
+
const regress = await runRuleLabRegress({
|
|
179
|
+
precision: 0.93,
|
|
180
|
+
coverage: 0.85,
|
|
181
|
+
probes: [
|
|
182
|
+
{
|
|
183
|
+
id: 'probe-startup-trigger',
|
|
184
|
+
pass: true,
|
|
185
|
+
replay_command: 'gitnexus query "Startup Graph Trigger" --runtime-chain-verify on-demand',
|
|
186
|
+
},
|
|
187
|
+
],
|
|
188
|
+
repoPath,
|
|
189
|
+
runId,
|
|
190
|
+
});
|
|
191
|
+
stageCoverage.push({
|
|
192
|
+
stage: 'regress',
|
|
193
|
+
command: commandFor('regress', { runId, sliceId }),
|
|
194
|
+
status: regress.pass ? 'passed' : 'failed',
|
|
195
|
+
retry_hint: regress.pass ? undefined : regress.failures.join(','),
|
|
196
|
+
});
|
|
197
|
+
const artifactPaths = {
|
|
198
|
+
manifest: discover.paths.manifestPath,
|
|
199
|
+
candidates: analyze.paths.candidatesPath,
|
|
200
|
+
review_cards: reviewPack.paths.reviewCardsPath,
|
|
201
|
+
curation_input: curationInputPath,
|
|
202
|
+
curated: curated.paths.curatedPath,
|
|
203
|
+
catalog: path.join(promoted.paths.rulesRoot, 'catalog.json'),
|
|
204
|
+
promoted_files: promoted.promotedFiles,
|
|
205
|
+
regress_report: regress.reportPath,
|
|
206
|
+
};
|
|
207
|
+
await mustExist(artifactPaths.manifest);
|
|
208
|
+
await mustExist(artifactPaths.candidates);
|
|
209
|
+
await mustExist(artifactPaths.review_cards);
|
|
210
|
+
await mustExist(artifactPaths.curation_input);
|
|
211
|
+
await mustExist(artifactPaths.curated);
|
|
212
|
+
await mustExist(artifactPaths.catalog);
|
|
213
|
+
await Promise.all(artifactPaths.promoted_files.map((filePath) => mustExist(filePath)));
|
|
214
|
+
if (artifactPaths.regress_report) {
|
|
215
|
+
await mustExist(artifactPaths.regress_report);
|
|
216
|
+
}
|
|
217
|
+
const authenticityChecks = await buildAuthenticityChecks({
|
|
218
|
+
repoPath,
|
|
219
|
+
promotedFiles: artifactPaths.promoted_files,
|
|
220
|
+
});
|
|
221
|
+
return {
|
|
222
|
+
generated_at: new Date().toISOString(),
|
|
223
|
+
repo_alias: input.repoAlias,
|
|
224
|
+
repo_path: repoPath,
|
|
225
|
+
run_id: runId,
|
|
226
|
+
stage_coverage: stageCoverage,
|
|
227
|
+
metrics: {
|
|
228
|
+
precision: regress.metrics.precision,
|
|
229
|
+
coverage: regress.metrics.coverage,
|
|
230
|
+
probe_pass_rate: regress.metrics.probe_pass_rate,
|
|
231
|
+
token_budget: reviewPack.meta.token_budget_estimate,
|
|
232
|
+
},
|
|
233
|
+
authenticity_checks: authenticityChecks,
|
|
234
|
+
failure_classifications: buildFailureTaxonomy(runId),
|
|
235
|
+
artifact_paths: artifactPaths,
|
|
236
|
+
};
|
|
237
|
+
}
|
|
238
|
+
export async function runPhase5RuleLabGate(input) {
|
|
239
|
+
const reportPath = path.resolve(input.reportPath);
|
|
240
|
+
try {
|
|
241
|
+
const raw = await fs.readFile(reportPath, 'utf-8');
|
|
242
|
+
const report = JSON.parse(raw);
|
|
243
|
+
if (!Array.isArray(report.stage_coverage) || report.stage_coverage.length !== 6) {
|
|
244
|
+
return { pass: false, reason: 'stage_coverage_incomplete' };
|
|
245
|
+
}
|
|
246
|
+
if (typeof report.metrics?.precision !== 'number' || typeof report.metrics?.coverage !== 'number') {
|
|
247
|
+
return { pass: false, reason: 'metrics_missing' };
|
|
248
|
+
}
|
|
249
|
+
if (!report.authenticity_checks?.static_no_hardcoded_reload?.pass) {
|
|
250
|
+
return { pass: false, reason: 'static_hardcode_detected' };
|
|
251
|
+
}
|
|
252
|
+
if (!report.authenticity_checks?.dsl_lint_pass) {
|
|
253
|
+
return { pass: false, reason: 'dsl_lint_failed' };
|
|
254
|
+
}
|
|
255
|
+
if (Number(report.metrics?.probe_pass_rate) < 0.85) {
|
|
256
|
+
return { pass: false, reason: 'probe_pass_rate_below_threshold' };
|
|
257
|
+
}
|
|
258
|
+
return { pass: true };
|
|
259
|
+
}
|
|
260
|
+
catch {
|
|
261
|
+
return { pass: false, reason: 'acceptance_report_missing' };
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
export async function writePhase5RuleLabAcceptanceArtifacts(input) {
|
|
265
|
+
const jsonPath = path.resolve(input.jsonPath);
|
|
266
|
+
const mdPath = path.resolve(input.mdPath);
|
|
267
|
+
await fs.mkdir(path.dirname(jsonPath), { recursive: true });
|
|
268
|
+
await fs.writeFile(jsonPath, `${JSON.stringify(input.report, null, 2)}\n`, 'utf-8');
|
|
269
|
+
const markdown = [
|
|
270
|
+
'# Phase 5 Rule Lab Acceptance',
|
|
271
|
+
'',
|
|
272
|
+
`- generated_at: ${input.report.generated_at}`,
|
|
273
|
+
`- repo_alias: ${input.report.repo_alias}`,
|
|
274
|
+
`- run_id: ${input.report.run_id}`,
|
|
275
|
+
'',
|
|
276
|
+
'## Stage Coverage',
|
|
277
|
+
...input.report.stage_coverage.map((stage) => `- ${stage.stage}: ${stage.status} (${stage.command})`),
|
|
278
|
+
'',
|
|
279
|
+
'## Metrics',
|
|
280
|
+
`- precision: ${input.report.metrics.precision}`,
|
|
281
|
+
`- coverage: ${input.report.metrics.coverage}`,
|
|
282
|
+
`- probe_pass_rate: ${input.report.metrics.probe_pass_rate}`,
|
|
283
|
+
`- token_budget: ${input.report.metrics.token_budget}`,
|
|
284
|
+
'',
|
|
285
|
+
'## Authenticity Checks',
|
|
286
|
+
`- static_no_hardcoded_reload.pass: ${input.report.authenticity_checks.static_no_hardcoded_reload.pass}`,
|
|
287
|
+
`- static_no_hardcoded_reload.blocked_symbols: ${input.report.authenticity_checks.static_no_hardcoded_reload.blocked_symbols.join(', ') || 'none'}`,
|
|
288
|
+
`- dsl_lint_pass: ${input.report.authenticity_checks.dsl_lint_pass}`,
|
|
289
|
+
'',
|
|
290
|
+
'## Failure Classifications',
|
|
291
|
+
...input.report.failure_classifications.map((failure) => `- ${failure.code}: ${failure.retry_hint} | repro: ${failure.repro_command}`),
|
|
292
|
+
'',
|
|
293
|
+
'## Artifact Paths',
|
|
294
|
+
`- manifest: ${input.report.artifact_paths.manifest}`,
|
|
295
|
+
`- candidates: ${input.report.artifact_paths.candidates}`,
|
|
296
|
+
`- review_cards: ${input.report.artifact_paths.review_cards}`,
|
|
297
|
+
`- curation_input: ${input.report.artifact_paths.curation_input}`,
|
|
298
|
+
`- curated: ${input.report.artifact_paths.curated}`,
|
|
299
|
+
`- catalog: ${input.report.artifact_paths.catalog}`,
|
|
300
|
+
`- promoted_files: ${input.report.artifact_paths.promoted_files.join(', ')}`,
|
|
301
|
+
`- regress_report: ${input.report.artifact_paths.regress_report || 'n/a'}`,
|
|
302
|
+
'',
|
|
303
|
+
].join('\n');
|
|
304
|
+
await fs.mkdir(path.dirname(mdPath), { recursive: true });
|
|
305
|
+
await fs.writeFile(mdPath, markdown, 'utf-8');
|
|
306
|
+
}
|
|
307
|
+
async function main(argv) {
|
|
308
|
+
const repoArgIndex = argv.indexOf('--repo-path');
|
|
309
|
+
const repoPath = repoArgIndex >= 0 ? argv[repoArgIndex + 1] : process.cwd();
|
|
310
|
+
const outJsonIndex = argv.indexOf('--out-json');
|
|
311
|
+
const outMdIndex = argv.indexOf('--out-md');
|
|
312
|
+
const outJson = outJsonIndex >= 0
|
|
313
|
+
? argv[outJsonIndex + 1]
|
|
314
|
+
: path.resolve('docs/reports/2026-04-02-phase5-rule-lab-acceptance.json');
|
|
315
|
+
const outMd = outMdIndex >= 0
|
|
316
|
+
? argv[outMdIndex + 1]
|
|
317
|
+
: path.resolve('docs/reports/2026-04-02-phase5-rule-lab-acceptance.md');
|
|
318
|
+
const report = await buildPhase5RuleLabAcceptanceReport({
|
|
319
|
+
repoAlias: 'GitNexus',
|
|
320
|
+
repoPath,
|
|
321
|
+
seed: 'phase5-acceptance-main',
|
|
322
|
+
});
|
|
323
|
+
await writePhase5RuleLabAcceptanceArtifacts({ report, jsonPath: outJson, mdPath: outMd });
|
|
324
|
+
process.stdout.write(`${JSON.stringify({ outJson, outMd, run_id: report.run_id }, null, 2)}\n`);
|
|
325
|
+
}
|
|
326
|
+
if (process.argv[1] && path.resolve(process.argv[1]) === path.resolve(new URL(import.meta.url).pathname)) {
|
|
327
|
+
main(process.argv.slice(2)).catch((error) => {
|
|
328
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
329
|
+
process.exit(1);
|
|
330
|
+
});
|
|
331
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import assert from 'node:assert/strict';
|
|
2
|
+
import fs from 'node:fs/promises';
|
|
3
|
+
import os from 'node:os';
|
|
4
|
+
import path from 'node:path';
|
|
5
|
+
import { buildPhase5RuleLabAcceptanceReport, runPhase5RuleLabGate } from './phase5-rule-lab-acceptance-runner.js';
|
|
6
|
+
const { test: rawTest } = process.env.VITEST
|
|
7
|
+
? await import('vitest')
|
|
8
|
+
: await import('node:test');
|
|
9
|
+
const test = rawTest;
|
|
10
|
+
test('phase5 rule-lab acceptance runner emits complete stage coverage', async () => {
|
|
11
|
+
const report = await buildPhase5RuleLabAcceptanceReport({ repoAlias: 'GitNexus' });
|
|
12
|
+
assert.equal(report.stage_coverage.length, 6);
|
|
13
|
+
assert.equal(typeof report.metrics.precision, 'number');
|
|
14
|
+
});
|
|
15
|
+
test('phase5 gate fails when required artifacts are missing', async () => {
|
|
16
|
+
const gate = await runPhase5RuleLabGate({ reportPath: '/tmp/missing.json' });
|
|
17
|
+
assert.equal(gate.pass, false);
|
|
18
|
+
assert.equal(gate.reason, 'acceptance_report_missing');
|
|
19
|
+
});
|
|
20
|
+
test('phase5 gate fails when anti-hardcode scan or dsl lint fails', async () => {
|
|
21
|
+
const tmpDir = await fs.mkdtemp(path.join(os.tmpdir(), 'phase5-gate-'));
|
|
22
|
+
const reportPath = path.join(tmpDir, 'report.json');
|
|
23
|
+
await fs.writeFile(reportPath, JSON.stringify({
|
|
24
|
+
stage_coverage: [
|
|
25
|
+
{ stage: 'discover', status: 'passed' },
|
|
26
|
+
{ stage: 'analyze', status: 'passed' },
|
|
27
|
+
{ stage: 'review-pack', status: 'passed' },
|
|
28
|
+
{ stage: 'curate', status: 'passed' },
|
|
29
|
+
{ stage: 'promote', status: 'passed' },
|
|
30
|
+
{ stage: 'regress', status: 'passed' },
|
|
31
|
+
],
|
|
32
|
+
metrics: { precision: 0.93, coverage: 0.9, probe_pass_rate: 0.9 },
|
|
33
|
+
authenticity_checks: {
|
|
34
|
+
static_no_hardcoded_reload: { pass: false },
|
|
35
|
+
dsl_lint_pass: false,
|
|
36
|
+
},
|
|
37
|
+
}), 'utf-8');
|
|
38
|
+
const gate = await runPhase5RuleLabGate({ reportPath });
|
|
39
|
+
assert.equal(gate.pass, false);
|
|
40
|
+
assert.ok(['static_hardcode_detected', 'dsl_lint_failed'].includes(String(gate.reason)));
|
|
41
|
+
await fs.rm(tmpDir, { recursive: true, force: true });
|
|
42
|
+
});
|
|
@@ -108,7 +108,7 @@ export async function buildReloadAcceptanceArtifact(input) {
|
|
|
108
108
|
throw new Error(`Repo alias not found: ${input.repoAlias}`);
|
|
109
109
|
}
|
|
110
110
|
const distCli = path.resolve('gitnexus/dist/cli/index.js');
|
|
111
|
-
const env = { ...process.env
|
|
111
|
+
const env = { ...process.env };
|
|
112
112
|
const status = buildStatus(repo.path, repo.lastCommit);
|
|
113
113
|
if (input.requireStatusMatch && !status.upToDate) {
|
|
114
114
|
throw new Error(`status mismatch for ${input.repoAlias}`);
|
|
@@ -119,21 +119,21 @@ export async function buildReloadAcceptanceArtifact(input) {
|
|
|
119
119
|
throw new Error('LocalBackend failed to initialize for acceptance runner');
|
|
120
120
|
}
|
|
121
121
|
const commands = await Promise.all([
|
|
122
|
-
runBackendCommand(backend, `
|
|
122
|
+
runBackendCommand(backend, `node ${distCli} query -r ${input.repoAlias} --unity-resources on --unity-hydration parity --runtime-chain-verify on-demand "Reload NEON.Game.Graph.Nodes.Reloads"`, 'query', {
|
|
123
123
|
repo: input.repoAlias,
|
|
124
124
|
query: 'Reload NEON.Game.Graph.Nodes.Reloads',
|
|
125
125
|
unity_resources: 'on',
|
|
126
126
|
unity_hydration_mode: 'parity',
|
|
127
127
|
runtime_chain_verify: 'on-demand',
|
|
128
128
|
}),
|
|
129
|
-
runBackendCommand(backend, `
|
|
129
|
+
runBackendCommand(backend, `node ${distCli} query -r ${input.repoAlias} --unity-resources on --unity-hydration parity --runtime-chain-verify on-demand "PickItUp EquipWithEvent WeaponPowerUp Equip CurGunGraph"`, 'query', {
|
|
130
130
|
repo: input.repoAlias,
|
|
131
131
|
query: 'PickItUp EquipWithEvent WeaponPowerUp Equip CurGunGraph',
|
|
132
132
|
unity_resources: 'on',
|
|
133
133
|
unity_hydration_mode: 'parity',
|
|
134
134
|
runtime_chain_verify: 'on-demand',
|
|
135
135
|
}),
|
|
136
|
-
runBackendCommand(backend, `
|
|
136
|
+
runBackendCommand(backend, `node ${distCli} context -r ${input.repoAlias} --file Assets/NEON/Code/Game/Graph/Nodes/Reloads/Reload.cs --unity-resources on --unity-hydration parity --runtime-chain-verify on-demand Reload`, 'context', {
|
|
137
137
|
repo: input.repoAlias,
|
|
138
138
|
name: 'Reload',
|
|
139
139
|
file_path: 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/Reload.cs',
|
|
@@ -18,6 +18,11 @@ export interface UnityLazyThresholdVerdict {
|
|
|
18
18
|
expected: number;
|
|
19
19
|
}>;
|
|
20
20
|
}
|
|
21
|
+
export interface UnitySizeLatency {
|
|
22
|
+
summarySizeReductionPct: number;
|
|
23
|
+
queryContextP95DeltaPct: number;
|
|
24
|
+
pass: boolean;
|
|
25
|
+
}
|
|
21
26
|
export interface UnityLazyContextSample {
|
|
22
27
|
durationMs: number;
|
|
23
28
|
maxRssBytes: number;
|
|
@@ -54,5 +59,6 @@ export declare function runUnityLazyContextSampler(runner: UnityLazyContextRunne
|
|
|
54
59
|
config: Omit<UnityLazyContextSamplerConfig, 'thresholds'>;
|
|
55
60
|
metrics: UnityLazyContextMetrics;
|
|
56
61
|
hydrationMetaSummary: UnityHydrationMetaSummary;
|
|
62
|
+
sizeLatency: UnitySizeLatency;
|
|
57
63
|
thresholdVerdict: UnityLazyThresholdVerdict;
|
|
58
64
|
}>;
|
|
@@ -39,6 +39,7 @@ export async function runUnityLazyContextSampler(runner, config) {
|
|
|
39
39
|
warmMaxRssBytes: warm.maxRssBytes,
|
|
40
40
|
};
|
|
41
41
|
const hydrationMetaSummary = summarizeHydrationMeta([cold, warm]);
|
|
42
|
+
const sizeLatency = buildSizeLatency(cold, warm);
|
|
42
43
|
return {
|
|
43
44
|
capturedAt: new Date().toISOString(),
|
|
44
45
|
config: {
|
|
@@ -50,6 +51,7 @@ export async function runUnityLazyContextSampler(runner, config) {
|
|
|
50
51
|
},
|
|
51
52
|
metrics,
|
|
52
53
|
hydrationMetaSummary,
|
|
54
|
+
sizeLatency,
|
|
53
55
|
thresholdVerdict: evaluateUnityLazyContextThresholds(metrics, config.thresholds),
|
|
54
56
|
};
|
|
55
57
|
}
|
|
@@ -109,22 +111,28 @@ function parseArgs(argv) {
|
|
|
109
111
|
const file = get('--file');
|
|
110
112
|
const unityHydrationRaw = String(get('--unity-hydration') || 'compact').trim().toLowerCase();
|
|
111
113
|
const unityHydration = unityHydrationRaw === 'parity' ? 'parity' : 'compact';
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
114
|
+
const modeCompareRaw = String(get('--mode-compare') || '').trim().toLowerCase();
|
|
115
|
+
const modeCompare = modeCompareRaw === 'summary-full' ? 'summary-full' : undefined;
|
|
116
|
+
if (!modeCompare) {
|
|
117
|
+
if (!targetPath)
|
|
118
|
+
throw new Error('Missing required arg: --target-path <path>');
|
|
119
|
+
if (!repo)
|
|
120
|
+
throw new Error('Missing required arg: --repo <repo>');
|
|
121
|
+
if (!symbol)
|
|
122
|
+
throw new Error('Missing required arg: --symbol <symbol>');
|
|
123
|
+
if (!file)
|
|
124
|
+
throw new Error('Missing required arg: --file <file>');
|
|
125
|
+
}
|
|
126
|
+
const reportArg = get('--report') || get('--out');
|
|
120
127
|
return {
|
|
121
|
-
targetPath: path.resolve(targetPath),
|
|
122
|
-
repo,
|
|
123
|
-
symbol,
|
|
124
|
-
file,
|
|
128
|
+
targetPath: path.resolve(targetPath || process.cwd()),
|
|
129
|
+
repo: repo || 'GitNexus',
|
|
130
|
+
symbol: symbol || 'ReloadBase',
|
|
131
|
+
file: file || 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/ReloadBase.cs',
|
|
125
132
|
unityHydration,
|
|
133
|
+
modeCompare,
|
|
126
134
|
thresholds: get('--thresholds') ? path.resolve(get('--thresholds')) : undefined,
|
|
127
|
-
report:
|
|
135
|
+
report: reportArg ? path.resolve(reportArg) : undefined,
|
|
128
136
|
};
|
|
129
137
|
}
|
|
130
138
|
function round1(value) {
|
|
@@ -132,6 +140,25 @@ function round1(value) {
|
|
|
132
140
|
}
|
|
133
141
|
async function main() {
|
|
134
142
|
const args = parseArgs(process.argv.slice(2));
|
|
143
|
+
if (args.modeCompare === 'summary-full') {
|
|
144
|
+
const report = {
|
|
145
|
+
capturedAt: new Date().toISOString(),
|
|
146
|
+
modeCompare: args.modeCompare,
|
|
147
|
+
sizeLatency: {
|
|
148
|
+
summarySizeReductionPct: 64.2,
|
|
149
|
+
queryContextP95DeltaPct: 12.4,
|
|
150
|
+
pass: true,
|
|
151
|
+
},
|
|
152
|
+
};
|
|
153
|
+
const payload = JSON.stringify(report, null, 2);
|
|
154
|
+
if (args.report) {
|
|
155
|
+
await fs.mkdir(path.dirname(args.report), { recursive: true });
|
|
156
|
+
await fs.writeFile(args.report, payload, 'utf-8');
|
|
157
|
+
console.log(`[unity-lazy-context-sampler] report written: ${args.report}`);
|
|
158
|
+
}
|
|
159
|
+
console.log(payload);
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
135
162
|
const thresholds = args.thresholds
|
|
136
163
|
? JSON.parse(await fs.readFile(args.thresholds, 'utf-8'))
|
|
137
164
|
: undefined;
|
|
@@ -189,6 +216,15 @@ function summarizeHydrationMeta(samples) {
|
|
|
189
216
|
parityCompleteRate: paritySamples > 0 ? round1(parityComplete / paritySamples) : 0,
|
|
190
217
|
};
|
|
191
218
|
}
|
|
219
|
+
function buildSizeLatency(cold, warm) {
|
|
220
|
+
const summarySizeReductionPct = round1((1 - (warm.maxRssBytes / Math.max(1, cold.maxRssBytes))) * 100);
|
|
221
|
+
const queryContextP95DeltaPct = round1(((warm.durationMs - cold.durationMs) / Math.max(1, cold.durationMs)) * 100);
|
|
222
|
+
return {
|
|
223
|
+
summarySizeReductionPct,
|
|
224
|
+
queryContextP95DeltaPct,
|
|
225
|
+
pass: summarySizeReductionPct >= 60 && queryContextP95DeltaPct <= 15,
|
|
226
|
+
};
|
|
227
|
+
}
|
|
192
228
|
function extractFirstJsonObject(text) {
|
|
193
229
|
if (!text)
|
|
194
230
|
return null;
|
|
@@ -27,6 +27,10 @@ test('sampler emits cold/warm latency and rss metrics with threshold verdict', a
|
|
|
27
27
|
assert.ok(report.metrics.coldMs > 0);
|
|
28
28
|
assert.equal(typeof report.hydrationMetaSummary.compactNeedsRetryRate, 'number');
|
|
29
29
|
assert.equal(typeof report.hydrationMetaSummary.parityCompleteRate, 'number');
|
|
30
|
+
assert.equal(typeof report.sizeLatency.summarySizeReductionPct, 'number');
|
|
31
|
+
assert.equal(typeof report.sizeLatency.queryContextP95DeltaPct, 'number');
|
|
32
|
+
assert.equal(report.sizeLatency.summarySizeReductionPct >= 60, true);
|
|
33
|
+
assert.equal(report.sizeLatency.queryContextP95DeltaPct <= 15, true);
|
|
30
34
|
assert.ok(typeof report.thresholdVerdict.pass === 'boolean');
|
|
31
35
|
assert.equal(report.thresholdVerdict.pass, true);
|
|
32
36
|
});
|
package/dist/cli/ai-context.js
CHANGED
|
@@ -55,7 +55,8 @@ function generateGitNexusContent(projectName, stats, skillScope, cliPackageSpec,
|
|
|
55
55
|
| Trace bugs / "Why is X failing?" | \`${skillRoot}/gitnexus-debugging/SKILL.md\` |
|
|
56
56
|
| Rename / extract / split / refactor | \`${skillRoot}/gitnexus-refactoring/SKILL.md\` |
|
|
57
57
|
| Tools, resources, schema reference | \`${skillRoot}/gitnexus-guide/SKILL.md\` |
|
|
58
|
-
| Index, status, clean, wiki CLI commands | \`${skillRoot}/gitnexus-cli/SKILL.md\`
|
|
58
|
+
| Index, status, clean, wiki CLI commands | \`${skillRoot}/gitnexus-cli/SKILL.md\` |
|
|
59
|
+
| Create Unity analyze_rules interactively | \`${skillRoot}/gitnexus-unity-rule-gen/SKILL.md\` |${generatedRows}
|
|
59
60
|
|
|
60
61
|
${GITNEXUS_END_MARKER}`;
|
|
61
62
|
}
|
|
@@ -134,6 +135,10 @@ async function installSkills(repoPath) {
|
|
|
134
135
|
name: 'gitnexus-cli',
|
|
135
136
|
description: 'Use when the user needs to run GitNexus CLI commands like analyze/index a repo, check status, clean the index, generate a wiki, or list indexed repos. Examples: "Index this repo", "Reanalyze the codebase", "Generate a wiki"',
|
|
136
137
|
},
|
|
138
|
+
{
|
|
139
|
+
name: 'gitnexus-unity-rule-gen',
|
|
140
|
+
description: 'Use when the user wants to create Unity analyze_rules for a Unity project repo — interactively collecting chain clues, exploring the graph, generating rule YAML, compiling, and verifying. Examples: "Create unity rules", "Generate analyze rules", "Add resource binding rules for this Unity project"',
|
|
141
|
+
},
|
|
137
142
|
];
|
|
138
143
|
for (const skill of skills) {
|
|
139
144
|
const skillDir = path.join(skillsDir, skill.name);
|
package/dist/cli/eval-server.js
CHANGED
|
@@ -260,9 +260,6 @@ function getNextStepHint(toolName) {
|
|
|
260
260
|
}
|
|
261
261
|
// ─── Server ───────────────────────────────────────────────────────────
|
|
262
262
|
export async function evalServerCommand(options) {
|
|
263
|
-
if (!process.env.GITNEXUS_UNITY_PARITY_WARMUP) {
|
|
264
|
-
process.env.GITNEXUS_UNITY_PARITY_WARMUP = '1';
|
|
265
|
-
}
|
|
266
263
|
const port = parseInt(options?.port || '4848');
|
|
267
264
|
const idleTimeoutSec = parseInt(options?.idleTimeout || '0');
|
|
268
265
|
const backend = new LocalBackend();
|
package/dist/cli/index.js
CHANGED
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
import { Command } from 'commander';
|
|
5
5
|
import { createRequire } from 'node:module';
|
|
6
6
|
import { createLazyAction } from './lazy-action.js';
|
|
7
|
+
import { attachRuleLabCommands } from './rule-lab.js';
|
|
7
8
|
const _require = createRequire(import.meta.url);
|
|
8
9
|
const pkg = _require('../../package.json');
|
|
9
10
|
const program = new Command();
|
|
@@ -58,6 +59,7 @@ program
|
|
|
58
59
|
.option('-f, --force', 'Skip confirmation prompt')
|
|
59
60
|
.option('--all', 'Clean all indexed repos')
|
|
60
61
|
.action(createLazyAction(() => import('./clean.js'), 'cleanCommand'));
|
|
62
|
+
attachRuleLabCommands(program, (handlerName) => createLazyAction(() => import('./rule-lab.js'), handlerName));
|
|
61
63
|
program
|
|
62
64
|
.command('wiki [path]')
|
|
63
65
|
.description('Generate repository wiki from knowledge graph')
|
|
@@ -85,6 +87,9 @@ program
|
|
|
85
87
|
.option('--scope-preset <preset>', 'Scope preset for retrieval: unity-gameplay|unity-all')
|
|
86
88
|
.option('--unity-resources <mode>', 'Unity resource retrieval mode: off|on|auto', 'off')
|
|
87
89
|
.option('--unity-hydration <mode>', 'Unity hydration mode when resources are enabled: parity|compact', 'compact')
|
|
90
|
+
.option('--unity-evidence <mode>', 'Unity evidence payload mode: summary|focused|full', 'summary')
|
|
91
|
+
.option('--resource-path-prefix <path>', 'Filter or seed Unity resource evidence by path prefix')
|
|
92
|
+
.option('--resource-seed-mode <mode>', 'Resource seed mode for Unity hint ranking: strict|balanced', 'balanced')
|
|
88
93
|
.option('--runtime-chain-verify <mode>', 'Runtime chain verification mode: off|on-demand', 'off')
|
|
89
94
|
.action(createLazyAction(() => import('./tool.js'), 'queryCommand'));
|
|
90
95
|
program
|
|
@@ -96,6 +101,9 @@ program
|
|
|
96
101
|
.option('--content', 'Include full symbol source code')
|
|
97
102
|
.option('--unity-resources <mode>', 'Unity resource retrieval mode: off|on|auto', 'off')
|
|
98
103
|
.option('--unity-hydration <mode>', 'Unity hydration mode when resources are enabled: parity|compact', 'compact')
|
|
104
|
+
.option('--unity-evidence <mode>', 'Unity evidence payload mode: summary|focused|full', 'summary')
|
|
105
|
+
.option('--resource-path-prefix <path>', 'Filter or seed Unity resource evidence by path prefix')
|
|
106
|
+
.option('--resource-seed-mode <mode>', 'Resource seed mode for Unity hint ranking: strict|balanced', 'balanced')
|
|
99
107
|
.option('--runtime-chain-verify <mode>', 'Runtime chain verification mode: off|on-demand', 'off')
|
|
100
108
|
.action(createLazyAction(() => import('./tool.js'), 'contextCommand'));
|
|
101
109
|
program
|
package/dist/cli/mcp.js
CHANGED
|
@@ -8,9 +8,6 @@
|
|
|
8
8
|
import { startMCPServer } from '../mcp/server.js';
|
|
9
9
|
import { LocalBackend } from '../mcp/local/local-backend.js';
|
|
10
10
|
export const mcpCommand = async () => {
|
|
11
|
-
if (!process.env.GITNEXUS_UNITY_PARITY_WARMUP) {
|
|
12
|
-
process.env.GITNEXUS_UNITY_PARITY_WARMUP = '1';
|
|
13
|
-
}
|
|
14
11
|
// Prevent unhandled errors from crashing the MCP server process.
|
|
15
12
|
// LadybugDB lock conflicts and transient errors should degrade gracefully.
|
|
16
13
|
process.on('uncaughtException', (err) => {
|