@veewo/gitnexus 1.4.9 → 1.4.11-rc
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/live-evidence-validator.d.ts +19 -0
- package/dist/benchmark/u2-e2e/live-evidence-validator.js +87 -0
- package/dist/benchmark/u2-e2e/live-evidence-validator.test.d.ts +1 -0
- package/dist/benchmark/u2-e2e/live-evidence-validator.test.js +33 -0
- package/dist/benchmark/u2-e2e/neonspark-full-e2e.js +23 -4
- package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.d.ts +38 -0
- package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.js +206 -0
- package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.test.d.ts +1 -0
- package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.test.js +72 -0
- package/dist/benchmark/u2-e2e/report.d.ts +1 -0
- package/dist/benchmark/u2-e2e/report.js +2 -0
- package/dist/benchmark/u2-e2e/retrieval-runner.d.ts +34 -0
- package/dist/benchmark/u2-e2e/retrieval-runner.js +95 -5
- package/dist/benchmark/u2-e2e/retrieval-runner.test.js +161 -2
- package/dist/cli/ai-context.js +32 -1
- package/dist/cli/ai-context.test.js +10 -0
- package/dist/cli/analyze-summary.d.ts +1 -0
- package/dist/cli/analyze-summary.js +21 -0
- package/dist/cli/analyze-summary.test.js +7 -1
- package/dist/cli/analyze.js +3 -10
- package/dist/cli/eval-server.js +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/cli/setup.js +9 -0
- package/dist/cli/setup.test.js +2 -0
- package/dist/cli/tool.d.ts +2 -0
- package/dist/cli/tool.js +2 -0
- package/dist/core/ingestion/pipeline.js +24 -3
- package/dist/core/ingestion/process-processor.d.ts +6 -0
- package/dist/core/ingestion/process-processor.js +188 -7
- package/dist/core/ingestion/unity-lifecycle-config.d.ts +5 -0
- package/dist/core/ingestion/unity-lifecycle-config.js +25 -0
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.d.ts +26 -0
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.js +384 -0
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.test.d.ts +1 -0
- package/dist/core/ingestion/unity-lifecycle-synthetic-calls.test.js +541 -0
- package/dist/core/ingestion/unity-resource-processor.test.js +81 -0
- package/dist/core/lbug/csv-generator.js +11 -1
- package/dist/core/lbug/fallback-relationship-replay.d.ts +21 -0
- package/dist/core/lbug/fallback-relationship-replay.js +39 -0
- package/dist/core/lbug/fallback-relationship-replay.test.d.ts +1 -0
- package/dist/core/lbug/fallback-relationship-replay.test.js +25 -0
- package/dist/core/lbug/lbug-adapter.d.ts +5 -0
- package/dist/core/lbug/lbug-adapter.js +22 -23
- package/dist/core/lbug/schema.d.ts +2 -2
- package/dist/core/lbug/schema.js +9 -0
- package/dist/core/lbug/schema.test.js +1 -0
- package/dist/mcp/local/local-backend.d.ts +1 -1
- package/dist/mcp/local/local-backend.js +339 -50
- package/dist/mcp/local/local-backend.unity-merge.test.js +1 -1
- package/dist/mcp/local/process-confidence.d.ts +19 -0
- package/dist/mcp/local/process-confidence.js +29 -0
- package/dist/mcp/local/process-confidence.test.d.ts +1 -0
- package/dist/mcp/local/process-confidence.test.js +36 -0
- package/dist/mcp/local/process-evidence.d.ts +28 -0
- package/dist/mcp/local/process-evidence.js +65 -0
- package/dist/mcp/local/process-evidence.test.d.ts +1 -0
- package/dist/mcp/local/process-evidence.test.js +56 -0
- package/dist/mcp/local/runtime-chain-evidence.d.ts +7 -0
- package/dist/mcp/local/runtime-chain-evidence.js +13 -0
- package/dist/mcp/local/runtime-chain-evidence.test.d.ts +1 -0
- package/dist/mcp/local/runtime-chain-evidence.test.js +24 -0
- package/dist/mcp/local/runtime-chain-verify.d.ts +37 -0
- package/dist/mcp/local/runtime-chain-verify.js +221 -0
- package/dist/mcp/local/runtime-chain-verify.test.d.ts +1 -0
- package/dist/mcp/local/runtime-chain-verify.test.js +56 -0
- package/dist/mcp/local/unity-process-confidence-config.d.ts +1 -0
- package/dist/mcp/local/unity-process-confidence-config.js +4 -0
- package/dist/mcp/local/unity-runtime-chain-verify-config.d.ts +1 -0
- package/dist/mcp/local/unity-runtime-chain-verify-config.js +10 -0
- package/dist/mcp/local/unity-runtime-hydration.d.ts +50 -0
- package/dist/mcp/local/unity-runtime-hydration.js +323 -0
- package/dist/mcp/local/unity-runtime-hydration.test.d.ts +1 -0
- package/dist/mcp/local/unity-runtime-hydration.test.js +108 -0
- package/dist/mcp/resources.js +12 -2
- package/dist/mcp/tools.js +32 -0
- package/package.json +1 -1
- package/skills/_shared/unity-runtime-process-contract.md +38 -0
- package/skills/gitnexus-cli.md +16 -0
- package/skills/gitnexus-debugging.md +6 -0
- package/skills/gitnexus-exploring.md +6 -0
- package/skills/gitnexus-guide.md +4 -0
- package/skills/gitnexus-impact-analysis.md +6 -0
- package/skills/gitnexus-pr-review.md +5 -0
- package/skills/gitnexus-refactoring.md +4 -0
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
import { buildUnityScanContext, buildUnityScanContextFromSeed } from '../../core/unity/scan-context.js';
|
|
2
|
+
import { resolveUnityBindings } from '../../core/unity/resolver.js';
|
|
3
|
+
import { formatLazyHydrationBudgetDiagnostic, } from './unity-enrichment.js';
|
|
4
|
+
import { resolveUnityLazyConfig } from './unity-lazy-config.js';
|
|
5
|
+
import { hydrateLazyBindings } from './unity-lazy-hydrator.js';
|
|
6
|
+
import { readUnityOverlayBindings, upsertUnityOverlayBindings } from './unity-lazy-overlay.js';
|
|
7
|
+
import { readUnityParityCache, upsertUnityParityCache } from './unity-parity-cache.js';
|
|
8
|
+
import { createParityWarmupQueue } from './unity-parity-warmup-queue.js';
|
|
9
|
+
import { loadUnityParitySeed } from './unity-parity-seed-loader.js';
|
|
10
|
+
const inFlightParityHydration = new Map();
|
|
11
|
+
const parityWarmupQueue = createParityWarmupQueue({
|
|
12
|
+
maxParallel: resolveParityWarmupMaxParallel(process.env),
|
|
13
|
+
});
|
|
14
|
+
function resolveParityWarmupMaxParallel(env) {
|
|
15
|
+
const raw = String(env.GITNEXUS_UNITY_PARITY_WARMUP_MAX_PARALLEL || '').trim();
|
|
16
|
+
const parsed = Number.parseInt(raw, 10);
|
|
17
|
+
if (Number.isFinite(parsed) && parsed > 0) {
|
|
18
|
+
return parsed;
|
|
19
|
+
}
|
|
20
|
+
return 2;
|
|
21
|
+
}
|
|
22
|
+
function normalizePath(filePath) {
|
|
23
|
+
return String(filePath || '').replace(/\\/g, '/');
|
|
24
|
+
}
|
|
25
|
+
function bindingIdentity(binding) {
|
|
26
|
+
return [
|
|
27
|
+
normalizePath(binding.resourcePath),
|
|
28
|
+
binding.bindingKind,
|
|
29
|
+
binding.componentObjectId,
|
|
30
|
+
].join('|');
|
|
31
|
+
}
|
|
32
|
+
export function mergeUnityBindings(baseBindings, resolvedByPath) {
|
|
33
|
+
const merged = [];
|
|
34
|
+
const expandedPaths = new Set();
|
|
35
|
+
for (const binding of baseBindings) {
|
|
36
|
+
const resourcePath = normalizePath(binding.resourcePath);
|
|
37
|
+
if (!binding.lightweight) {
|
|
38
|
+
merged.push(binding);
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
const expanded = resolvedByPath.get(resourcePath);
|
|
42
|
+
if (expanded && expanded.length > 0) {
|
|
43
|
+
if (!expandedPaths.has(resourcePath)) {
|
|
44
|
+
merged.push(...expanded.map((row) => ({ ...row, lightweight: false })));
|
|
45
|
+
expandedPaths.add(resourcePath);
|
|
46
|
+
}
|
|
47
|
+
continue;
|
|
48
|
+
}
|
|
49
|
+
merged.push(binding);
|
|
50
|
+
}
|
|
51
|
+
return merged;
|
|
52
|
+
}
|
|
53
|
+
export function mergeParityUnityBindings(baseNonLightweightBindings, resolvedBindings) {
|
|
54
|
+
const merged = [];
|
|
55
|
+
const seen = new Set();
|
|
56
|
+
for (const row of [...baseNonLightweightBindings, ...resolvedBindings]) {
|
|
57
|
+
const key = bindingIdentity(row);
|
|
58
|
+
if (seen.has(key))
|
|
59
|
+
continue;
|
|
60
|
+
seen.add(key);
|
|
61
|
+
merged.push({ ...row, lightweight: false });
|
|
62
|
+
}
|
|
63
|
+
return merged;
|
|
64
|
+
}
|
|
65
|
+
export function attachUnityHydrationMeta(payload, input) {
|
|
66
|
+
const { hasExpandableBindings, ...metaInput } = input;
|
|
67
|
+
const reasons = [];
|
|
68
|
+
if (metaInput.effectiveMode === 'compact' && hasExpandableBindings) {
|
|
69
|
+
reasons.push('mode_compact');
|
|
70
|
+
}
|
|
71
|
+
if (metaInput.fallbackToCompact) {
|
|
72
|
+
reasons.push('fallback_to_compact');
|
|
73
|
+
}
|
|
74
|
+
if (hasExpandableBindings) {
|
|
75
|
+
reasons.push('lightweight_bindings_remaining');
|
|
76
|
+
}
|
|
77
|
+
if ((payload.unityDiagnostics || []).some((diag) => /budget exceeded/i.test(String(diag || '')))) {
|
|
78
|
+
reasons.push('budget_exceeded');
|
|
79
|
+
}
|
|
80
|
+
const isComplete = reasons.length === 0;
|
|
81
|
+
const needsParityRetry = !isComplete && metaInput.effectiveMode === 'compact';
|
|
82
|
+
return {
|
|
83
|
+
...payload,
|
|
84
|
+
hydrationMeta: {
|
|
85
|
+
...metaInput,
|
|
86
|
+
resourceBindingCount: payload.resourceBindings.length,
|
|
87
|
+
unityDiagnosticsCount: payload.unityDiagnostics.length,
|
|
88
|
+
isComplete,
|
|
89
|
+
completenessReason: reasons,
|
|
90
|
+
needsParityRetry,
|
|
91
|
+
...(needsParityRetry ? { retryHint: 'rerun_with_unity_hydration=parity' } : {}),
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function hydrateUnityForSymbol(input) {
|
|
96
|
+
const runtime = resolveRuntime(input.runtime);
|
|
97
|
+
const startedAt = runtime.now();
|
|
98
|
+
if (input.mode === 'compact') {
|
|
99
|
+
const compactPayload = await runCompactHydration(input, runtime);
|
|
100
|
+
const withMeta = attachUnityHydrationMeta(compactPayload, {
|
|
101
|
+
requestedMode: 'compact',
|
|
102
|
+
effectiveMode: 'compact',
|
|
103
|
+
elapsedMs: runtime.now() - startedAt,
|
|
104
|
+
fallbackToCompact: false,
|
|
105
|
+
hasExpandableBindings: hasExpandableBindings(compactPayload),
|
|
106
|
+
});
|
|
107
|
+
if (withMeta.hydrationMeta?.needsParityRetry) {
|
|
108
|
+
scheduleParityWarmup(input, runtime);
|
|
109
|
+
}
|
|
110
|
+
return withMeta;
|
|
111
|
+
}
|
|
112
|
+
const parityResult = await runParityHydrationWithFallback(input, runtime);
|
|
113
|
+
return attachUnityHydrationMeta(parityResult.payload, {
|
|
114
|
+
requestedMode: 'parity',
|
|
115
|
+
effectiveMode: parityResult.effectiveMode,
|
|
116
|
+
elapsedMs: runtime.now() - startedAt,
|
|
117
|
+
fallbackToCompact: parityResult.fallbackToCompact,
|
|
118
|
+
hasExpandableBindings: hasExpandableBindings(parityResult.payload),
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
function resolveRuntime(overrides) {
|
|
122
|
+
return {
|
|
123
|
+
now: () => Date.now(),
|
|
124
|
+
queue: parityWarmupQueue,
|
|
125
|
+
resolveLazyConfig: resolveUnityLazyConfig,
|
|
126
|
+
hydrateLazyBindings,
|
|
127
|
+
readOverlayBindings: readUnityOverlayBindings,
|
|
128
|
+
upsertOverlayBindings: upsertUnityOverlayBindings,
|
|
129
|
+
readParityCache: readUnityParityCache,
|
|
130
|
+
upsertParityCache: upsertUnityParityCache,
|
|
131
|
+
loadParitySeed: loadUnityParitySeed,
|
|
132
|
+
buildScanContext: buildUnityScanContext,
|
|
133
|
+
buildScanContextFromSeed: buildUnityScanContextFromSeed,
|
|
134
|
+
resolveBindings: resolveUnityBindings,
|
|
135
|
+
shouldEnableWarmup,
|
|
136
|
+
...overrides,
|
|
137
|
+
};
|
|
138
|
+
}
|
|
139
|
+
function hasExpandableBindings(payload) {
|
|
140
|
+
return payload.resourceBindings.some((binding) => binding.lightweight || binding.componentObjectId === 'summary');
|
|
141
|
+
}
|
|
142
|
+
function buildParityWarmupKey(input) {
|
|
143
|
+
return `${input.deps.storagePath}::${input.deps.indexedCommit}::${input.symbol.uid}`;
|
|
144
|
+
}
|
|
145
|
+
function scheduleParityWarmup(input, runtime) {
|
|
146
|
+
if (!runtime.shouldEnableWarmup(process.env)) {
|
|
147
|
+
return;
|
|
148
|
+
}
|
|
149
|
+
if (!input.symbol.uid || !input.symbol.name || !input.symbol.filePath) {
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
void runtime.queue.run(() => getOrRunParityHydration(input, runtime))
|
|
153
|
+
.then(() => undefined)
|
|
154
|
+
.catch(() => undefined);
|
|
155
|
+
}
|
|
156
|
+
function shouldEnableWarmup(env) {
|
|
157
|
+
const raw = String(env.GITNEXUS_UNITY_PARITY_WARMUP || '').trim().toLowerCase();
|
|
158
|
+
return raw === '1' || raw === 'true' || raw === 'on';
|
|
159
|
+
}
|
|
160
|
+
async function getOrRunParityHydration(input, runtime) {
|
|
161
|
+
const key = buildParityWarmupKey(input);
|
|
162
|
+
const existing = inFlightParityHydration.get(key);
|
|
163
|
+
if (existing) {
|
|
164
|
+
return existing;
|
|
165
|
+
}
|
|
166
|
+
const pending = (async () => {
|
|
167
|
+
const cached = await runtime.readParityCache(input.deps.storagePath, input.deps.indexedCommit, input.symbol.uid);
|
|
168
|
+
if (cached) {
|
|
169
|
+
return cached;
|
|
170
|
+
}
|
|
171
|
+
const payload = await computeParityPayload(input, runtime);
|
|
172
|
+
await runtime.upsertParityCache(input.deps.storagePath, input.deps.indexedCommit, input.symbol.uid, payload);
|
|
173
|
+
return payload;
|
|
174
|
+
})().finally(() => {
|
|
175
|
+
inFlightParityHydration.delete(key);
|
|
176
|
+
});
|
|
177
|
+
inFlightParityHydration.set(key, pending);
|
|
178
|
+
return pending;
|
|
179
|
+
}
|
|
180
|
+
async function computeParityPayload(input, runtime) {
|
|
181
|
+
const symbolDeclarations = [{ symbol: input.symbol.name, scriptPath: input.symbol.filePath }];
|
|
182
|
+
const paritySeed = await runtime.loadParitySeed(input.deps.storagePath, {
|
|
183
|
+
indexedCommit: input.deps.indexedCommit,
|
|
184
|
+
});
|
|
185
|
+
const seededScanContext = paritySeed
|
|
186
|
+
? runtime.buildScanContextFromSeed({ seed: paritySeed, symbolDeclarations })
|
|
187
|
+
: null;
|
|
188
|
+
let resolved = await runtime.resolveBindings({
|
|
189
|
+
repoRoot: input.deps.repoPath,
|
|
190
|
+
symbol: input.symbol.name,
|
|
191
|
+
scanContext: seededScanContext || await runtime.buildScanContext({
|
|
192
|
+
repoRoot: input.deps.repoPath,
|
|
193
|
+
symbolDeclarations,
|
|
194
|
+
}),
|
|
195
|
+
deepParseLargeResources: true,
|
|
196
|
+
});
|
|
197
|
+
if (seededScanContext && resolved.resourceBindings.length === 0 && input.basePayload.resourceBindings.length > 0) {
|
|
198
|
+
const fallbackScanContext = await runtime.buildScanContext({
|
|
199
|
+
repoRoot: input.deps.repoPath,
|
|
200
|
+
symbolDeclarations,
|
|
201
|
+
});
|
|
202
|
+
resolved = await runtime.resolveBindings({
|
|
203
|
+
repoRoot: input.deps.repoPath,
|
|
204
|
+
symbol: input.symbol.name,
|
|
205
|
+
scanContext: fallbackScanContext,
|
|
206
|
+
deepParseLargeResources: true,
|
|
207
|
+
});
|
|
208
|
+
}
|
|
209
|
+
if (resolved.resourceBindings.length === 0 && input.basePayload.resourceBindings.length > 0) {
|
|
210
|
+
throw new Error('parity-expand returned zero bindings');
|
|
211
|
+
}
|
|
212
|
+
const baseNonLightweight = input.basePayload.resourceBindings.filter((binding) => !binding.lightweight && binding.componentObjectId !== 'summary');
|
|
213
|
+
const mergedBindings = mergeParityUnityBindings(baseNonLightweight, resolved.resourceBindings);
|
|
214
|
+
return toUnityContextPayload(mergedBindings, [
|
|
215
|
+
...input.basePayload.unityDiagnostics,
|
|
216
|
+
...resolved.unityDiagnostics,
|
|
217
|
+
]);
|
|
218
|
+
}
|
|
219
|
+
async function runParityHydrationWithFallback(input, runtime) {
|
|
220
|
+
try {
|
|
221
|
+
return {
|
|
222
|
+
payload: await getOrRunParityHydration(input, runtime),
|
|
223
|
+
effectiveMode: 'parity',
|
|
224
|
+
fallbackToCompact: false,
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
catch (error) {
|
|
228
|
+
const compactFallback = await runCompactHydration(input, runtime);
|
|
229
|
+
const message = String(error instanceof Error ? error.message : error);
|
|
230
|
+
return {
|
|
231
|
+
payload: {
|
|
232
|
+
...compactFallback,
|
|
233
|
+
unityDiagnostics: [
|
|
234
|
+
...compactFallback.unityDiagnostics,
|
|
235
|
+
/parity-expand returned zero bindings/i.test(message)
|
|
236
|
+
? 'parity-expand returned zero bindings; fell back to compact hydration'
|
|
237
|
+
: `parity-expand failed: ${message}`,
|
|
238
|
+
],
|
|
239
|
+
},
|
|
240
|
+
effectiveMode: 'compact',
|
|
241
|
+
fallbackToCompact: true,
|
|
242
|
+
};
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
async function runCompactHydration(input, runtime) {
|
|
246
|
+
const lightweightPaths = [...new Set(input.basePayload.resourceBindings
|
|
247
|
+
.filter((binding) => binding.lightweight || binding.componentObjectId === 'summary')
|
|
248
|
+
.map((binding) => normalizePath(binding.resourcePath))
|
|
249
|
+
.filter((value) => value.length > 0))];
|
|
250
|
+
if (lightweightPaths.length === 0) {
|
|
251
|
+
return input.basePayload;
|
|
252
|
+
}
|
|
253
|
+
const overlayHits = await runtime.readOverlayBindings(input.deps.storagePath, input.deps.indexedCommit, input.symbol.uid, lightweightPaths);
|
|
254
|
+
const pendingPaths = lightweightPaths.filter((resourcePath) => !overlayHits.has(resourcePath));
|
|
255
|
+
const resolvedByPath = new Map(overlayHits);
|
|
256
|
+
const unityDiagnostics = [...input.basePayload.unityDiagnostics];
|
|
257
|
+
if (pendingPaths.length > 0) {
|
|
258
|
+
try {
|
|
259
|
+
const cfg = runtime.resolveLazyConfig(process.env);
|
|
260
|
+
const hydration = await runtime.hydrateLazyBindings({
|
|
261
|
+
pendingPaths,
|
|
262
|
+
config: cfg,
|
|
263
|
+
dedupeKey: `${input.symbol.uid}::${pendingPaths.slice().sort().join('|')}`,
|
|
264
|
+
resolveBatch: async (resourcePaths) => {
|
|
265
|
+
const scopedPaths = [
|
|
266
|
+
input.symbol.filePath,
|
|
267
|
+
`${input.symbol.filePath}.meta`,
|
|
268
|
+
...resourcePaths,
|
|
269
|
+
...resourcePaths.map((resourcePath) => `${resourcePath}.meta`),
|
|
270
|
+
].map(normalizePath);
|
|
271
|
+
const scanContext = await runtime.buildScanContext({
|
|
272
|
+
repoRoot: input.deps.repoPath,
|
|
273
|
+
scopedPaths,
|
|
274
|
+
symbolDeclarations: [{ symbol: input.symbol.name, scriptPath: input.symbol.filePath }],
|
|
275
|
+
});
|
|
276
|
+
const resolved = await runtime.resolveBindings({
|
|
277
|
+
repoRoot: input.deps.repoPath,
|
|
278
|
+
symbol: input.symbol.name,
|
|
279
|
+
scanContext,
|
|
280
|
+
resourcePathAllowlist: resourcePaths,
|
|
281
|
+
deepParseLargeResources: true,
|
|
282
|
+
});
|
|
283
|
+
unityDiagnostics.push(...resolved.unityDiagnostics);
|
|
284
|
+
const byPath = new Map();
|
|
285
|
+
for (const resourcePath of resourcePaths) {
|
|
286
|
+
byPath.set(resourcePath, resolved.resourceBindings.filter((binding) => normalizePath(binding.resourcePath) === normalizePath(resourcePath)));
|
|
287
|
+
}
|
|
288
|
+
return byPath;
|
|
289
|
+
},
|
|
290
|
+
});
|
|
291
|
+
const freshByPath = hydration.resolvedByPath;
|
|
292
|
+
if (hydration.timedOut) {
|
|
293
|
+
unityDiagnostics.push(formatLazyHydrationBudgetDiagnostic(hydration.elapsedMs));
|
|
294
|
+
}
|
|
295
|
+
const hydrationExtras = hydration.diagnostics.filter((diag) => !/budget exceeded/i.test(diag));
|
|
296
|
+
if (hydrationExtras.length > 0) {
|
|
297
|
+
unityDiagnostics.push(...hydrationExtras);
|
|
298
|
+
}
|
|
299
|
+
await runtime.upsertOverlayBindings(input.deps.storagePath, input.deps.indexedCommit, input.symbol.uid, freshByPath);
|
|
300
|
+
for (const [resourcePath, bindings] of freshByPath.entries()) {
|
|
301
|
+
resolvedByPath.set(resourcePath, bindings);
|
|
302
|
+
}
|
|
303
|
+
}
|
|
304
|
+
catch (error) {
|
|
305
|
+
unityDiagnostics.push(`lazy-expand failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
const mergedBindings = mergeUnityBindings(input.basePayload.resourceBindings, resolvedByPath);
|
|
309
|
+
return toUnityContextPayload(mergedBindings, unityDiagnostics);
|
|
310
|
+
}
|
|
311
|
+
function toUnityContextPayload(resourceBindings, unityDiagnostics) {
|
|
312
|
+
return {
|
|
313
|
+
resourceBindings,
|
|
314
|
+
serializedFields: {
|
|
315
|
+
scalarFields: resourceBindings.flatMap((binding) => binding.serializedFields.scalarFields),
|
|
316
|
+
referenceFields: resourceBindings.flatMap((binding) => binding.serializedFields.referenceFields),
|
|
317
|
+
},
|
|
318
|
+
unityDiagnostics,
|
|
319
|
+
};
|
|
320
|
+
}
|
|
321
|
+
export function __resetUnityRuntimeHydrationStateForTest() {
|
|
322
|
+
inFlightParityHydration.clear();
|
|
323
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { hydrateUnityForSymbol } from './unity-runtime-hydration.js';
|
|
4
|
+
test('hydrateUnityForSymbol(compact) marks needsParityRetry when lightweight bindings remain', async () => {
|
|
5
|
+
const out = await hydrateUnityForSymbol({
|
|
6
|
+
mode: 'compact',
|
|
7
|
+
basePayload: {
|
|
8
|
+
resourceBindings: [
|
|
9
|
+
{
|
|
10
|
+
resourcePath: 'Assets/A.prefab',
|
|
11
|
+
resourceType: 'prefab',
|
|
12
|
+
bindingKind: 'direct',
|
|
13
|
+
componentObjectId: 'summary',
|
|
14
|
+
lightweight: true,
|
|
15
|
+
evidence: { line: 0, lineText: '' },
|
|
16
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
17
|
+
resolvedReferences: [],
|
|
18
|
+
assetRefPaths: [],
|
|
19
|
+
},
|
|
20
|
+
],
|
|
21
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
22
|
+
unityDiagnostics: [],
|
|
23
|
+
},
|
|
24
|
+
deps: {
|
|
25
|
+
executeQuery: async () => [],
|
|
26
|
+
repoPath: '/tmp/repo',
|
|
27
|
+
storagePath: '/tmp/storage',
|
|
28
|
+
indexedCommit: 'abc123',
|
|
29
|
+
},
|
|
30
|
+
symbol: {
|
|
31
|
+
uid: 'Class:Assets/Scripts/A.cs:A',
|
|
32
|
+
name: 'A',
|
|
33
|
+
filePath: 'Assets/Scripts/A.cs',
|
|
34
|
+
},
|
|
35
|
+
runtime: {
|
|
36
|
+
shouldEnableWarmup: () => false,
|
|
37
|
+
resolveLazyConfig: () => ({ maxPendingPathsPerRequest: 10, batchSize: 10, maxHydrationMs: 5000 }),
|
|
38
|
+
hydrateLazyBindings: async () => ({
|
|
39
|
+
resolvedByPath: new Map(),
|
|
40
|
+
timedOut: false,
|
|
41
|
+
elapsedMs: 1,
|
|
42
|
+
diagnostics: [],
|
|
43
|
+
}),
|
|
44
|
+
readOverlayBindings: async () => new Map(),
|
|
45
|
+
upsertOverlayBindings: async () => undefined,
|
|
46
|
+
},
|
|
47
|
+
});
|
|
48
|
+
assert.equal(out.hydrationMeta?.effectiveMode, 'compact');
|
|
49
|
+
assert.equal(out.hydrationMeta?.needsParityRetry, true);
|
|
50
|
+
});
|
|
51
|
+
test('hydrateUnityForSymbol(parity) sets isComplete=true on parity success', async () => {
|
|
52
|
+
const out = await hydrateUnityForSymbol({
|
|
53
|
+
mode: 'parity',
|
|
54
|
+
basePayload: {
|
|
55
|
+
resourceBindings: [
|
|
56
|
+
{
|
|
57
|
+
resourcePath: 'Assets/A.prefab',
|
|
58
|
+
resourceType: 'prefab',
|
|
59
|
+
bindingKind: 'direct',
|
|
60
|
+
componentObjectId: 'summary',
|
|
61
|
+
lightweight: true,
|
|
62
|
+
evidence: { line: 0, lineText: '' },
|
|
63
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
64
|
+
resolvedReferences: [],
|
|
65
|
+
assetRefPaths: [],
|
|
66
|
+
},
|
|
67
|
+
],
|
|
68
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
69
|
+
unityDiagnostics: [],
|
|
70
|
+
},
|
|
71
|
+
deps: {
|
|
72
|
+
executeQuery: async () => [],
|
|
73
|
+
repoPath: '/tmp/repo',
|
|
74
|
+
storagePath: '/tmp/storage',
|
|
75
|
+
indexedCommit: 'abc123',
|
|
76
|
+
},
|
|
77
|
+
symbol: {
|
|
78
|
+
uid: 'Class:Assets/Scripts/A.cs:A',
|
|
79
|
+
name: 'A',
|
|
80
|
+
filePath: 'Assets/Scripts/A.cs',
|
|
81
|
+
},
|
|
82
|
+
runtime: {
|
|
83
|
+
shouldEnableWarmup: () => false,
|
|
84
|
+
readParityCache: async () => null,
|
|
85
|
+
upsertParityCache: async () => undefined,
|
|
86
|
+
loadParitySeed: async () => null,
|
|
87
|
+
buildScanContext: async () => ({}),
|
|
88
|
+
resolveBindings: async () => ({
|
|
89
|
+
resourceBindings: [
|
|
90
|
+
{
|
|
91
|
+
resourcePath: 'Assets/A.prefab',
|
|
92
|
+
resourceType: 'prefab',
|
|
93
|
+
bindingKind: 'direct',
|
|
94
|
+
componentObjectId: '114',
|
|
95
|
+
lightweight: false,
|
|
96
|
+
evidence: { line: 1, lineText: 'stub' },
|
|
97
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
98
|
+
resolvedReferences: [],
|
|
99
|
+
assetRefPaths: [],
|
|
100
|
+
},
|
|
101
|
+
],
|
|
102
|
+
unityDiagnostics: [],
|
|
103
|
+
}),
|
|
104
|
+
},
|
|
105
|
+
});
|
|
106
|
+
assert.equal(out.hydrationMeta?.effectiveMode, 'parity');
|
|
107
|
+
assert.equal(out.hydrationMeta?.isComplete, true);
|
|
108
|
+
});
|
package/dist/mcp/resources.js
CHANGED
|
@@ -64,7 +64,7 @@ export function getResourceTemplates() {
|
|
|
64
64
|
{
|
|
65
65
|
uriTemplate: 'gitnexus://repo/{name}/process/{processName}',
|
|
66
66
|
name: 'Process Trace',
|
|
67
|
-
description: 'Step-by-step execution trace',
|
|
67
|
+
description: 'Step-by-step execution trace with lifecycle subtype and step evidence when available',
|
|
68
68
|
mimeType: 'text/yaml',
|
|
69
69
|
},
|
|
70
70
|
];
|
|
@@ -250,6 +250,12 @@ async function getProcessesResource(backend, repoName) {
|
|
|
250
250
|
lines.push(` - name: "${label}"`);
|
|
251
251
|
lines.push(` type: ${proc.processType || 'unknown'}`);
|
|
252
252
|
lines.push(` steps: ${proc.stepCount || 0}`);
|
|
253
|
+
if (proc.processSubtype) {
|
|
254
|
+
lines.push(` subtype: ${proc.processSubtype}`);
|
|
255
|
+
}
|
|
256
|
+
if (proc.runtimeChainConfidence) {
|
|
257
|
+
lines.push(` runtime_chain_confidence: ${proc.runtimeChainConfidence}`);
|
|
258
|
+
}
|
|
253
259
|
}
|
|
254
260
|
if (result.processes.length > displayLimit) {
|
|
255
261
|
lines.push(`\n# Showing top ${displayLimit} of ${result.processes.length} processes. Use gitnexus_query for deeper search.`);
|
|
@@ -358,13 +364,17 @@ async function getProcessDetailResource(name, backend, repoName) {
|
|
|
358
364
|
const lines = [
|
|
359
365
|
`name: "${proc.heuristicLabel || proc.label || proc.id}"`,
|
|
360
366
|
`type: ${proc.processType || 'unknown'}`,
|
|
367
|
+
`subtype: ${proc.processSubtype || 'static_calls'}`,
|
|
368
|
+
`runtime_chain_confidence: ${proc.runtimeChainConfidence || 'high'}`,
|
|
361
369
|
`step_count: ${proc.stepCount || steps.length}`,
|
|
362
370
|
];
|
|
363
371
|
if (steps.length > 0) {
|
|
364
372
|
lines.push('');
|
|
365
373
|
lines.push('trace:');
|
|
366
374
|
for (const step of steps) {
|
|
367
|
-
|
|
375
|
+
const reason = step.reason ? ` reason=${step.reason}` : '';
|
|
376
|
+
const confidence = step.confidence !== undefined ? ` confidence=${step.confidence}` : '';
|
|
377
|
+
lines.push(` ${step.step}: ${step.name} (${step.filePath})${reason}${confidence}`);
|
|
368
378
|
}
|
|
369
379
|
}
|
|
370
380
|
return lines.join('\n');
|
package/dist/mcp/tools.js
CHANGED
|
@@ -34,6 +34,18 @@ Returns results grouped by process (execution flow):
|
|
|
34
34
|
- processes: ranked execution flows with relevance priority
|
|
35
35
|
- process_symbols: all symbols in those flows with file locations and module (functional area)
|
|
36
36
|
- definitions: standalone types/interfaces not in any process
|
|
37
|
+
- processes[].evidence_mode: direct_step | method_projected | resource_heuristic
|
|
38
|
+
- processes[].confidence: high | medium | low
|
|
39
|
+
- processes[].process_subtype: unity_lifecycle | static_calls (when persisted metadata exists)
|
|
40
|
+
- processes[].runtime_chain_confidence: high | medium | low (when GITNEXUS_UNITY_PROCESS_CONFIDENCE_FIELDS=on)
|
|
41
|
+
- processes[].runtime_chain_evidence_level: none | clue | verified_segment | verified_chain (when GITNEXUS_UNITY_PROCESS_CONFIDENCE_FIELDS=on)
|
|
42
|
+
- processes[].verification_hint: { action, target, next_command } (required when confidence=low and confidence fields flag is on)
|
|
43
|
+
- process_symbols[].process_evidence_mode: direct_step | method_projected | resource_heuristic
|
|
44
|
+
- process_symbols[].process_confidence: high | medium | low
|
|
45
|
+
- process_symbols[].process_subtype: unity_lifecycle | static_calls (when persisted metadata exists)
|
|
46
|
+
- process_symbols[].runtime_chain_confidence: high | medium | low (when GITNEXUS_UNITY_PROCESS_CONFIDENCE_FIELDS=on)
|
|
47
|
+
- process_symbols[].runtime_chain_evidence_level: none | clue | verified_segment | verified_chain (when GITNEXUS_UNITY_PROCESS_CONFIDENCE_FIELDS=on)
|
|
48
|
+
- process_symbols[].verification_hint: { action, target, next_command } (when confidence fields flag is on)
|
|
37
49
|
|
|
38
50
|
Hybrid ranking: BM25 keyword + semantic vector search, ranked by Reciprocal Rank Fusion.
|
|
39
51
|
Supports optional scope controls for noisy codebases:
|
|
@@ -70,6 +82,12 @@ Includes optional Unity retrieval contract:
|
|
|
70
82
|
description: 'Unity hydration mode when unity_resources is enabled (default: compact)',
|
|
71
83
|
default: 'compact',
|
|
72
84
|
},
|
|
85
|
+
runtime_chain_verify: {
|
|
86
|
+
type: 'string',
|
|
87
|
+
enum: ['off', 'on-demand'],
|
|
88
|
+
description: 'Explicit runtime chain verification mode (default: off)',
|
|
89
|
+
default: 'off',
|
|
90
|
+
},
|
|
73
91
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
74
92
|
},
|
|
75
93
|
required: ['query'],
|
|
@@ -134,6 +152,14 @@ AFTER THIS: Use impact() if planning changes, or READ gitnexus://repo/{name}/pro
|
|
|
134
152
|
|
|
135
153
|
Handles disambiguation: if multiple symbols share the same name, returns candidates for you to pick from. Use uid param for zero-ambiguity lookup from prior results.
|
|
136
154
|
|
|
155
|
+
Process participation metadata:
|
|
156
|
+
- processes[].evidence_mode: direct_step | method_projected | resource_heuristic
|
|
157
|
+
- processes[].confidence: high | medium | low
|
|
158
|
+
- processes[].process_subtype: unity_lifecycle | static_calls (when persisted metadata exists)
|
|
159
|
+
- processes[].runtime_chain_confidence: high | medium | low (when GITNEXUS_UNITY_PROCESS_CONFIDENCE_FIELDS=on)
|
|
160
|
+
- processes[].runtime_chain_evidence_level: none | clue | verified_segment | verified_chain (when GITNEXUS_UNITY_PROCESS_CONFIDENCE_FIELDS=on)
|
|
161
|
+
- processes[].verification_hint: { action, target, next_command } (required when confidence=low and confidence fields flag is on)
|
|
162
|
+
|
|
137
163
|
Unity retrieval contract:
|
|
138
164
|
- Set unity_resources=on|auto to include Unity resource evidence.
|
|
139
165
|
- Default unity_hydration_mode=compact (fast path).
|
|
@@ -157,6 +183,12 @@ Unity retrieval contract:
|
|
|
157
183
|
description: 'Unity hydration mode when unity_resources is enabled (default: compact)',
|
|
158
184
|
default: 'compact',
|
|
159
185
|
},
|
|
186
|
+
runtime_chain_verify: {
|
|
187
|
+
type: 'string',
|
|
188
|
+
enum: ['off', 'on-demand'],
|
|
189
|
+
description: 'Explicit runtime chain verification mode (default: off)',
|
|
190
|
+
default: 'off',
|
|
191
|
+
},
|
|
160
192
|
repo: { type: 'string', description: 'Repository name or path. Omit if only one repo is indexed.' },
|
|
161
193
|
},
|
|
162
194
|
required: [],
|
package/package.json
CHANGED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Unity Runtime Process Contract
|
|
2
|
+
|
|
3
|
+
Use this contract when analysis touches Unity runtime process semantics (runtime chain, lifecycle/loader stitching, or confidence-based closure).
|
|
4
|
+
|
|
5
|
+
## Trigger Conditions
|
|
6
|
+
|
|
7
|
+
Load this contract when any of the following is true:
|
|
8
|
+
|
|
9
|
+
- Query/debug/impact/refactor task requires Unity runtime process closure.
|
|
10
|
+
- Result contains Unity process evidence with `confidence` interpretation.
|
|
11
|
+
- Result has empty `processes` but Unity resource evidence is present.
|
|
12
|
+
- User asks for runtime-chain verification quality or closure certainty.
|
|
13
|
+
|
|
14
|
+
## Required Workflow
|
|
15
|
+
|
|
16
|
+
1. Run `query/context` with `unity_resources: "on"` and `unity_hydration_mode: "compact"` first.
|
|
17
|
+
2. If `hydrationMeta.needsParityRetry === true`, rerun with `unity_hydration_mode: "parity"` before conclusions.
|
|
18
|
+
3. Do not conclude "no runtime chain" from empty `processes` alone.
|
|
19
|
+
4. If Unity evidence exists, continue stitching:
|
|
20
|
+
- `processes`
|
|
21
|
+
- `resourceBindings`
|
|
22
|
+
- asset/meta mapping anchors
|
|
23
|
+
- runtime candidate symbols
|
|
24
|
+
5. Treat low-confidence rows as unresolved unless `verification_hint` includes:
|
|
25
|
+
- `action`
|
|
26
|
+
- `target`
|
|
27
|
+
- `next_command`
|
|
28
|
+
6. Semantic closure requires hop anchors/evidence anchors for each stitched step.
|
|
29
|
+
|
|
30
|
+
## Optional Strong Verification
|
|
31
|
+
|
|
32
|
+
For Reload-focused confirmation, request on-demand verification:
|
|
33
|
+
|
|
34
|
+
- pass `runtime_chain_verify: "on-demand"` in MCP tools, or
|
|
35
|
+
- use CLI `--runtime-chain-verify on-demand`.
|
|
36
|
+
|
|
37
|
+
When on-demand verification is used, report `runtime_chain.status`, `evidence_level`, `hops`, and `gaps` before final risk/closure statements.
|
|
38
|
+
|
package/skills/gitnexus-cli.md
CHANGED
|
@@ -113,6 +113,22 @@ Rules:
|
|
|
113
113
|
- If response `hydrationMeta.needsParityRetry=true`, rerun with `--unity-hydration parity`.
|
|
114
114
|
- `--unity-hydration parity` is completeness-first mode for advanced verification.
|
|
115
115
|
|
|
116
|
+
### Unity runtime process contract trigger
|
|
117
|
+
|
|
118
|
+
When CLI analysis targets Unity runtime process semantics (runtime chain closure/confidence), load:
|
|
119
|
+
|
|
120
|
+
- `_shared/unity-runtime-process-contract.md`
|
|
121
|
+
|
|
122
|
+
Runtime-process verification examples:
|
|
123
|
+
|
|
124
|
+
```bash
|
|
125
|
+
$GN query "Reload NEON.Game.Graph.Nodes.Reloads" --repo neonspark --unity-resources on --unity-hydration parity --runtime-chain-verify on-demand
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
$GN context ReloadNode --repo neonspark --unity-resources on --unity-hydration compact --runtime-chain-verify on-demand
|
|
130
|
+
```
|
|
131
|
+
|
|
116
132
|
### unity-ui-trace — Unity UI evidence tracing workflow
|
|
117
133
|
|
|
118
134
|
```bash
|
|
@@ -39,6 +39,12 @@ description: "Use when the user is debugging a bug, tracing an error, or asking
|
|
|
39
39
|
- [ ] Read source files to confirm root cause
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
## Unity Runtime Process Trigger
|
|
43
|
+
|
|
44
|
+
When debugging involves Unity runtime process semantics (runtime chain confidence, process closure certainty, lifecycle/loader stitching), load and follow:
|
|
45
|
+
|
|
46
|
+
- `_shared/unity-runtime-process-contract.md`
|
|
47
|
+
|
|
42
48
|
## Debugging Patterns
|
|
43
49
|
|
|
44
50
|
| Symptom | GitNexus Approach |
|
|
@@ -39,6 +39,12 @@ description: "Use when the user asks how code works, wants to understand archite
|
|
|
39
39
|
- [ ] Read source files for implementation details
|
|
40
40
|
```
|
|
41
41
|
|
|
42
|
+
## Unity Runtime Process Trigger
|
|
43
|
+
|
|
44
|
+
When exploration touches Unity runtime process semantics (runtime chain closure, lifecycle/loader stitching, confidence-based closure), load and follow:
|
|
45
|
+
|
|
46
|
+
- `_shared/unity-runtime-process-contract.md`
|
|
47
|
+
|
|
42
48
|
## Resources
|
|
43
49
|
|
|
44
50
|
| Resource | What you get |
|
package/skills/gitnexus-guide.md
CHANGED
|
@@ -56,6 +56,10 @@ Recommended default workflow:
|
|
|
56
56
|
- `isComplete: true` → keep compact result
|
|
57
57
|
3. Treat parity as the completeness path for advanced verification.
|
|
58
58
|
|
|
59
|
+
When task scope includes Unity runtime process semantics, load and follow:
|
|
60
|
+
|
|
61
|
+
- `_shared/unity-runtime-process-contract.md`
|
|
62
|
+
|
|
59
63
|
### Unity UI Trace Contract (`unity_ui_trace` / `gitnexus unity-ui-trace`)
|
|
60
64
|
|
|
61
65
|
Input:
|
|
@@ -38,6 +38,12 @@ description: "Use when the user wants to know what will break if they change som
|
|
|
38
38
|
- [ ] Assess risk level and report to user
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
## Unity Runtime Process Trigger
|
|
42
|
+
|
|
43
|
+
When impact analysis depends on Unity runtime process closure or confidence interpretation, load and follow:
|
|
44
|
+
|
|
45
|
+
- `_shared/unity-runtime-process-contract.md`
|
|
46
|
+
|
|
41
47
|
## Understanding Output
|
|
42
48
|
|
|
43
49
|
| Depth | Risk Level | Meaning |
|
|
@@ -28,6 +28,11 @@ description: "Use when the user wants to review a pull request, understand what
|
|
|
28
28
|
|
|
29
29
|
> If "Index is stale" → run `gitnexus analyze` when local CLI exists; otherwise resolve the pinned npx package spec from `~/.gitnexus/config.json` and run `npx -y <resolved-cli-spec> analyze` before reviewing.
|
|
30
30
|
|
|
31
|
+
Conditional triggers:
|
|
32
|
+
- If analysis touches Unity serialized/binding-state interpretation, apply `_shared/unity-resource-binding-contract.md`.
|
|
33
|
+
- If analysis touches UIToolkit visual semantics, apply `_shared/unity-ui-trace-contract.md`.
|
|
34
|
+
- If analysis touches Unity runtime process semantics (runtime chain closure/confidence), apply `_shared/unity-runtime-process-contract.md`.
|
|
35
|
+
|
|
31
36
|
## Checklist
|
|
32
37
|
|
|
33
38
|
```
|