@veewo/gitnexus 1.4.10-rc → 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.
Files changed (84) hide show
  1. package/dist/benchmark/u2-e2e/live-evidence-validator.d.ts +19 -0
  2. package/dist/benchmark/u2-e2e/live-evidence-validator.js +87 -0
  3. package/dist/benchmark/u2-e2e/live-evidence-validator.test.d.ts +1 -0
  4. package/dist/benchmark/u2-e2e/live-evidence-validator.test.js +33 -0
  5. package/dist/benchmark/u2-e2e/neonspark-full-e2e.js +23 -4
  6. package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.d.ts +38 -0
  7. package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.js +206 -0
  8. package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.test.d.ts +1 -0
  9. package/dist/benchmark/u2-e2e/reload-v1-acceptance-runner.test.js +72 -0
  10. package/dist/benchmark/u2-e2e/report.d.ts +1 -0
  11. package/dist/benchmark/u2-e2e/report.js +2 -0
  12. package/dist/benchmark/u2-e2e/retrieval-runner.d.ts +34 -0
  13. package/dist/benchmark/u2-e2e/retrieval-runner.js +95 -5
  14. package/dist/benchmark/u2-e2e/retrieval-runner.test.js +161 -2
  15. package/dist/cli/ai-context.js +31 -1
  16. package/dist/cli/ai-context.test.js +10 -0
  17. package/dist/cli/analyze-summary.d.ts +1 -0
  18. package/dist/cli/analyze-summary.js +21 -0
  19. package/dist/cli/analyze-summary.test.js +7 -1
  20. package/dist/cli/analyze.js +3 -10
  21. package/dist/cli/eval-server.js +1 -1
  22. package/dist/cli/index.js +2 -0
  23. package/dist/cli/setup.js +9 -0
  24. package/dist/cli/setup.test.js +2 -0
  25. package/dist/cli/tool.d.ts +2 -0
  26. package/dist/cli/tool.js +2 -0
  27. package/dist/core/ingestion/pipeline.js +24 -3
  28. package/dist/core/ingestion/process-processor.d.ts +6 -0
  29. package/dist/core/ingestion/process-processor.js +188 -7
  30. package/dist/core/ingestion/unity-lifecycle-config.d.ts +5 -0
  31. package/dist/core/ingestion/unity-lifecycle-config.js +25 -0
  32. package/dist/core/ingestion/unity-lifecycle-synthetic-calls.d.ts +26 -0
  33. package/dist/core/ingestion/unity-lifecycle-synthetic-calls.js +384 -0
  34. package/dist/core/ingestion/unity-lifecycle-synthetic-calls.test.d.ts +1 -0
  35. package/dist/core/ingestion/unity-lifecycle-synthetic-calls.test.js +541 -0
  36. package/dist/core/ingestion/unity-resource-processor.test.js +81 -0
  37. package/dist/core/lbug/csv-generator.js +11 -1
  38. package/dist/core/lbug/fallback-relationship-replay.d.ts +21 -0
  39. package/dist/core/lbug/fallback-relationship-replay.js +39 -0
  40. package/dist/core/lbug/fallback-relationship-replay.test.d.ts +1 -0
  41. package/dist/core/lbug/fallback-relationship-replay.test.js +25 -0
  42. package/dist/core/lbug/lbug-adapter.d.ts +5 -0
  43. package/dist/core/lbug/lbug-adapter.js +22 -23
  44. package/dist/core/lbug/schema.d.ts +2 -2
  45. package/dist/core/lbug/schema.js +9 -0
  46. package/dist/core/lbug/schema.test.js +1 -0
  47. package/dist/mcp/local/local-backend.d.ts +1 -1
  48. package/dist/mcp/local/local-backend.js +339 -50
  49. package/dist/mcp/local/local-backend.unity-merge.test.js +1 -1
  50. package/dist/mcp/local/process-confidence.d.ts +19 -0
  51. package/dist/mcp/local/process-confidence.js +29 -0
  52. package/dist/mcp/local/process-confidence.test.d.ts +1 -0
  53. package/dist/mcp/local/process-confidence.test.js +36 -0
  54. package/dist/mcp/local/process-evidence.d.ts +28 -0
  55. package/dist/mcp/local/process-evidence.js +65 -0
  56. package/dist/mcp/local/process-evidence.test.d.ts +1 -0
  57. package/dist/mcp/local/process-evidence.test.js +56 -0
  58. package/dist/mcp/local/runtime-chain-evidence.d.ts +7 -0
  59. package/dist/mcp/local/runtime-chain-evidence.js +13 -0
  60. package/dist/mcp/local/runtime-chain-evidence.test.d.ts +1 -0
  61. package/dist/mcp/local/runtime-chain-evidence.test.js +24 -0
  62. package/dist/mcp/local/runtime-chain-verify.d.ts +37 -0
  63. package/dist/mcp/local/runtime-chain-verify.js +221 -0
  64. package/dist/mcp/local/runtime-chain-verify.test.d.ts +1 -0
  65. package/dist/mcp/local/runtime-chain-verify.test.js +56 -0
  66. package/dist/mcp/local/unity-process-confidence-config.d.ts +1 -0
  67. package/dist/mcp/local/unity-process-confidence-config.js +4 -0
  68. package/dist/mcp/local/unity-runtime-chain-verify-config.d.ts +1 -0
  69. package/dist/mcp/local/unity-runtime-chain-verify-config.js +10 -0
  70. package/dist/mcp/local/unity-runtime-hydration.d.ts +50 -0
  71. package/dist/mcp/local/unity-runtime-hydration.js +323 -0
  72. package/dist/mcp/local/unity-runtime-hydration.test.d.ts +1 -0
  73. package/dist/mcp/local/unity-runtime-hydration.test.js +108 -0
  74. package/dist/mcp/resources.js +12 -2
  75. package/dist/mcp/tools.js +32 -0
  76. package/package.json +1 -1
  77. package/skills/_shared/unity-runtime-process-contract.md +38 -0
  78. package/skills/gitnexus-cli.md +16 -0
  79. package/skills/gitnexus-debugging.md +6 -0
  80. package/skills/gitnexus-exploring.md +6 -0
  81. package/skills/gitnexus-guide.md +4 -0
  82. package/skills/gitnexus-impact-analysis.md +6 -0
  83. package/skills/gitnexus-pr-review.md +5 -0
  84. package/skills/gitnexus-refactoring.md +4 -0
@@ -0,0 +1,384 @@
1
+ import { generateId } from '../../lib/utils.js';
2
+ const PLACEHOLDER_RE = /(TODO|TBD|\/placeholder\/)/i;
3
+ const UNITY_MONOBEHAVIOUR = 'MonoBehaviour';
4
+ const UNITY_SCRIPTABLE_OBJECT = 'ScriptableObject';
5
+ const LIFECYCLE_CALLBACKS = new Set([
6
+ 'Awake',
7
+ 'OnEnable',
8
+ 'Start',
9
+ 'Update',
10
+ 'FixedUpdate',
11
+ 'LateUpdate',
12
+ 'OnDisable',
13
+ 'OnDestroy',
14
+ ]);
15
+ const RUNTIME_LOADER_ANCHORS = new Set([
16
+ 'Equip',
17
+ 'EquipWithEvent',
18
+ 'RegisterGraphEvents',
19
+ 'RegisterEvents',
20
+ 'StartRoutineWithEvents',
21
+ 'GetValue',
22
+ 'CheckReload',
23
+ 'ReloadRoutine',
24
+ ]);
25
+ const DETERMINISTIC_LOADER_BRIDGES = [
26
+ ['Equip', 'EquipWithEvent'],
27
+ ['EquipWithEvent', 'RegisterEvents'],
28
+ ['RegisterGraphEvents', 'RegisterEvents'],
29
+ ['RegisterEvents', 'StartRoutineWithEvents'],
30
+ ['StartRoutineWithEvents', 'GetValue'],
31
+ ['GetValue', 'CheckReload'],
32
+ ['CheckReload', 'ReloadRoutine'],
33
+ ];
34
+ const SYNTHETIC_RUNTIME_ROOT_NAME = 'unity-runtime-root';
35
+ const SYNTHETIC_RUNTIME_ROOT_ID = generateId('Method', SYNTHETIC_RUNTIME_ROOT_NAME);
36
+ export const DEFAULT_UNITY_LIFECYCLE_SYNTHETIC_CONFIG = {
37
+ enabled: false,
38
+ maxSyntheticEdgesPerClass: 12,
39
+ maxSyntheticEdgesTotal: 256,
40
+ lifecycleEdgeConfidence: 0.72,
41
+ loaderEdgeConfidence: 0.68,
42
+ };
43
+ export const detectUnityLifecycleHosts = (graph) => {
44
+ const methodsByClass = new Map();
45
+ for (const rel of graph.iterRelationships()) {
46
+ if (rel.type !== 'HAS_METHOD')
47
+ continue;
48
+ const method = graph.getNode(rel.targetId);
49
+ if (!method)
50
+ continue;
51
+ if (method.label !== 'Method' && method.label !== 'Function')
52
+ continue;
53
+ const methods = methodsByClass.get(rel.sourceId) ?? [];
54
+ methods.push(method);
55
+ methodsByClass.set(rel.sourceId, methods);
56
+ }
57
+ const extendsByClass = new Map();
58
+ for (const rel of graph.iterRelationships()) {
59
+ if (rel.type !== 'EXTENDS' && rel.type !== 'INHERITS')
60
+ continue;
61
+ const edges = extendsByClass.get(rel.sourceId) ?? [];
62
+ edges.push(rel);
63
+ extendsByClass.set(rel.sourceId, edges);
64
+ }
65
+ const classIdsByName = new Map();
66
+ for (const node of graph.iterNodes()) {
67
+ if (node.label !== 'Class')
68
+ continue;
69
+ const ids = classIdsByName.get(String(node.properties.name)) ?? [];
70
+ ids.push(node.id);
71
+ classIdsByName.set(String(node.properties.name), ids);
72
+ }
73
+ const hosts = [];
74
+ for (const node of graph.iterNodes()) {
75
+ if (node.label !== 'Class')
76
+ continue;
77
+ const baseType = resolveUnityBaseType(graph, extendsByClass, classIdsByName, node.id);
78
+ if (!baseType)
79
+ continue;
80
+ const methods = methodsByClass.get(node.id) ?? [];
81
+ const lifecycleCallbacks = methods.filter((method) => LIFECYCLE_CALLBACKS.has(method.properties.name));
82
+ const loaderAnchors = methods.filter((method) => RUNTIME_LOADER_ANCHORS.has(method.properties.name));
83
+ hosts.push({
84
+ classNode: node,
85
+ baseType,
86
+ lifecycleCallbacks: sortMethodsByName(lifecycleCallbacks),
87
+ loaderAnchors: sortMethodsByName(loaderAnchors),
88
+ methods: sortMethodsByName(methods),
89
+ });
90
+ }
91
+ return hosts;
92
+ };
93
+ export const applyUnityLifecycleSyntheticCalls = (graph, config = {}) => {
94
+ const cfg = {
95
+ ...DEFAULT_UNITY_LIFECYCLE_SYNTHETIC_CONFIG,
96
+ ...config,
97
+ };
98
+ if (!cfg.enabled) {
99
+ return {
100
+ syntheticEdgeCount: 0,
101
+ lifecycleEdgeCount: 0,
102
+ loaderEdgeCount: 0,
103
+ hostCount: 0,
104
+ rejectedHostCount: 0,
105
+ };
106
+ }
107
+ const hosts = detectUnityLifecycleHosts(graph);
108
+ const acceptedHosts = [];
109
+ let rejectedHostCount = 0;
110
+ for (const host of hosts) {
111
+ if (isPlaceholderHost(host)) {
112
+ rejectedHostCount += 1;
113
+ continue;
114
+ }
115
+ acceptedHosts.push(host);
116
+ }
117
+ acceptedHosts.sort((left, right) => scoreUnityHost(right) - scoreUnityHost(left));
118
+ if (acceptedHosts.length === 0) {
119
+ return {
120
+ syntheticEdgeCount: 0,
121
+ lifecycleEdgeCount: 0,
122
+ loaderEdgeCount: 0,
123
+ hostCount: 0,
124
+ rejectedHostCount,
125
+ };
126
+ }
127
+ ensureRuntimeRootNode(graph);
128
+ const hostMethodToClassId = new Map();
129
+ const methodsByName = new Map();
130
+ for (const host of acceptedHosts) {
131
+ for (const method of host.methods) {
132
+ hostMethodToClassId.set(method.id, host.classNode.id);
133
+ const list = methodsByName.get(method.properties.name) ?? [];
134
+ list.push(method);
135
+ methodsByName.set(method.properties.name, list);
136
+ }
137
+ }
138
+ const existingPairs = new Set();
139
+ for (const rel of graph.iterRelationships()) {
140
+ if (rel.type === 'CALLS')
141
+ existingPairs.add(`${rel.sourceId}->${rel.targetId}`);
142
+ }
143
+ const syntheticEdgesPerClass = new Map();
144
+ let syntheticEdgeCount = 0;
145
+ let lifecycleEdgeCount = 0;
146
+ let loaderEdgeCount = 0;
147
+ const reservedBridgeBudget = Math.max(1, Math.floor(cfg.maxSyntheticEdgesTotal * 0.5));
148
+ const preBridgeBudget = Math.max(0, cfg.maxSyntheticEdgesTotal - reservedBridgeBudget);
149
+ const canAllocate = (classId, phase = 'pre_bridge') => {
150
+ if (syntheticEdgeCount >= cfg.maxSyntheticEdgesTotal)
151
+ return false;
152
+ if (phase === 'pre_bridge' && syntheticEdgeCount >= preBridgeBudget)
153
+ return false;
154
+ const classCount = syntheticEdgesPerClass.get(classId) ?? 0;
155
+ return classCount < cfg.maxSyntheticEdgesPerClass;
156
+ };
157
+ const addSyntheticEdge = (sourceId, targetId, reason, confidence, classId, phase = 'pre_bridge') => {
158
+ if (sourceId === targetId)
159
+ return false;
160
+ if (!canAllocate(classId, phase))
161
+ return false;
162
+ if (PLACEHOLDER_RE.test(sourceId) || PLACEHOLDER_RE.test(targetId))
163
+ return false;
164
+ const pairKey = `${sourceId}->${targetId}`;
165
+ if (existingPairs.has(pairKey))
166
+ return false;
167
+ graph.addRelationship({
168
+ id: generateId('CALLS', `${sourceId}->${targetId}:${reason}`),
169
+ sourceId,
170
+ targetId,
171
+ type: 'CALLS',
172
+ confidence,
173
+ reason,
174
+ });
175
+ existingPairs.add(pairKey);
176
+ syntheticEdgeCount += 1;
177
+ syntheticEdgesPerClass.set(classId, (syntheticEdgesPerClass.get(classId) ?? 0) + 1);
178
+ if (reason === 'unity-lifecycle-synthetic')
179
+ lifecycleEdgeCount += 1;
180
+ if (reason === 'unity-runtime-loader-synthetic')
181
+ loaderEdgeCount += 1;
182
+ return true;
183
+ };
184
+ for (const host of acceptedHosts) {
185
+ const classId = host.classNode.id;
186
+ for (const callback of host.lifecycleCallbacks) {
187
+ if (!canAllocate(classId))
188
+ break;
189
+ addSyntheticEdge(SYNTHETIC_RUNTIME_ROOT_ID, callback.id, 'unity-lifecycle-synthetic', cfg.lifecycleEdgeConfidence, classId, 'pre_bridge');
190
+ }
191
+ if (!canAllocate(classId))
192
+ continue;
193
+ for (const callback of host.lifecycleCallbacks) {
194
+ if (!canAllocate(classId))
195
+ break;
196
+ for (const loader of host.loaderAnchors) {
197
+ if (!canAllocate(classId))
198
+ break;
199
+ addSyntheticEdge(callback.id, loader.id, 'unity-runtime-loader-synthetic', cfg.loaderEdgeConfidence, classId, 'pre_bridge');
200
+ }
201
+ }
202
+ }
203
+ for (const [sourceName, targetName] of DETERMINISTIC_LOADER_BRIDGES) {
204
+ const sourceMethods = [...(methodsByName.get(sourceName) ?? [])].sort((left, right) => scoreRuntimeLoaderMethod(right) - scoreRuntimeLoaderMethod(left));
205
+ const targetMethods = [...(methodsByName.get(targetName) ?? [])].sort((left, right) => scoreRuntimeLoaderMethod(right) - scoreRuntimeLoaderMethod(left));
206
+ if (sourceMethods.length === 0 || targetMethods.length === 0)
207
+ continue;
208
+ const topSource = sourceMethods[0];
209
+ const topTarget = targetMethods[0];
210
+ const topSourceClassId = topSource ? hostMethodToClassId.get(topSource.id) : undefined;
211
+ if (topSource && topTarget && topSourceClassId) {
212
+ addSyntheticEdge(topSource.id, topTarget.id, 'unity-runtime-loader-synthetic', cfg.loaderEdgeConfidence, topSourceClassId, 'bridge');
213
+ }
214
+ for (const sourceMethod of sourceMethods) {
215
+ const classId = hostMethodToClassId.get(sourceMethod.id);
216
+ if (!classId || !canAllocate(classId, 'bridge'))
217
+ continue;
218
+ for (const targetMethod of targetMethods) {
219
+ if (!canAllocate(classId, 'bridge'))
220
+ break;
221
+ addSyntheticEdge(sourceMethod.id, targetMethod.id, 'unity-runtime-loader-synthetic', cfg.loaderEdgeConfidence, classId, 'bridge');
222
+ }
223
+ }
224
+ }
225
+ return {
226
+ syntheticEdgeCount,
227
+ lifecycleEdgeCount,
228
+ loaderEdgeCount,
229
+ hostCount: acceptedHosts.length,
230
+ rejectedHostCount,
231
+ runtimeRootNodeId: syntheticEdgeCount > 0 ? SYNTHETIC_RUNTIME_ROOT_ID : undefined,
232
+ };
233
+ };
234
+ const resolveUnityBaseType = (graph, extendsByClass, classIdsByName, classId, visited = new Set()) => {
235
+ if (visited.has(classId))
236
+ return undefined;
237
+ visited.add(classId);
238
+ for (const edge of extendsByClass.get(classId) ?? []) {
239
+ const targetNode = graph.getNode(edge.targetId);
240
+ const candidates = [
241
+ targetNode?.properties?.name ?? '',
242
+ edge.targetId,
243
+ edge.reason,
244
+ ];
245
+ for (const candidate of candidates) {
246
+ const normalized = normalizeBaseType(candidate);
247
+ if (normalized)
248
+ return normalized;
249
+ }
250
+ if (targetNode?.label === 'Class') {
251
+ const inherited = resolveUnityBaseType(graph, extendsByClass, classIdsByName, targetNode.id, visited);
252
+ if (inherited)
253
+ return inherited;
254
+ }
255
+ for (const candidateId of resolveNamedClassTargets(classIdsByName, edge.targetId)) {
256
+ const inherited = resolveUnityBaseType(graph, extendsByClass, classIdsByName, candidateId, visited);
257
+ if (inherited)
258
+ return inherited;
259
+ }
260
+ }
261
+ return undefined;
262
+ };
263
+ const normalizeBaseType = (value) => {
264
+ const text = String(value || '').trim();
265
+ if (!text)
266
+ return undefined;
267
+ if (text.endsWith(UNITY_MONOBEHAVIOUR) || text.includes(`.${UNITY_MONOBEHAVIOUR}`)) {
268
+ return UNITY_MONOBEHAVIOUR;
269
+ }
270
+ if (text.endsWith(UNITY_SCRIPTABLE_OBJECT) || text.includes(`.${UNITY_SCRIPTABLE_OBJECT}`)) {
271
+ return UNITY_SCRIPTABLE_OBJECT;
272
+ }
273
+ return undefined;
274
+ };
275
+ const ensureRuntimeRootNode = (graph) => {
276
+ if (graph.getNode(SYNTHETIC_RUNTIME_ROOT_ID))
277
+ return;
278
+ graph.addNode({
279
+ id: SYNTHETIC_RUNTIME_ROOT_ID,
280
+ label: 'Method',
281
+ properties: {
282
+ name: SYNTHETIC_RUNTIME_ROOT_NAME,
283
+ filePath: '',
284
+ },
285
+ });
286
+ };
287
+ const isPlaceholderHost = (host) => {
288
+ if (PLACEHOLDER_RE.test(host.classNode.properties.filePath))
289
+ return true;
290
+ for (const method of host.methods) {
291
+ if (PLACEHOLDER_RE.test(method.properties.filePath))
292
+ return true;
293
+ }
294
+ return false;
295
+ };
296
+ const sortMethodsByName = (methods) => [...methods].sort((left, right) => {
297
+ const byName = String(left.properties.name).localeCompare(String(right.properties.name));
298
+ if (byName !== 0)
299
+ return byName;
300
+ return left.id.localeCompare(right.id);
301
+ });
302
+ const scoreUnityHost = (host) => {
303
+ const filePath = String(host.classNode.properties.filePath || '');
304
+ let score = 0;
305
+ score += host.loaderAnchors.length * 40;
306
+ score += host.lifecycleCallbacks.length * 8;
307
+ if (filePath.includes('Assets/NEON/Code/Game/'))
308
+ score += 200;
309
+ else if (filePath.includes('Assets/NEON/Code/'))
310
+ score += 120;
311
+ else if (filePath.includes('Assets/'))
312
+ score += 40;
313
+ if (filePath.includes('/Graph/'))
314
+ score += 60;
315
+ if (filePath.includes('/PowerUps/'))
316
+ score += 40;
317
+ if (filePath.includes('/Core/'))
318
+ score += 30;
319
+ if (filePath.includes('/Reload'))
320
+ score += 30;
321
+ if (filePath.includes('/Packages/'))
322
+ score -= 120;
323
+ if (filePath.includes('/Legacy/'))
324
+ score -= 80;
325
+ if (filePath.startsWith('Assets/Scripts/'))
326
+ score -= 60;
327
+ for (const method of host.loaderAnchors) {
328
+ const methodName = String(method.properties.name || '');
329
+ if (methodName === 'RegisterGraphEvents' || methodName === 'RegisterEvents')
330
+ score += 25;
331
+ if (methodName === 'StartRoutineWithEvents')
332
+ score += 25;
333
+ if (methodName === 'GetValue' || methodName === 'CheckReload' || methodName === 'ReloadRoutine')
334
+ score += 20;
335
+ if (methodName === 'Equip' || methodName === 'EquipWithEvent')
336
+ score += 15;
337
+ }
338
+ return score;
339
+ };
340
+ const scoreRuntimeLoaderMethod = (method) => {
341
+ const filePath = String(method.properties.filePath || '');
342
+ const methodName = String(method.properties.name || '');
343
+ let score = 0;
344
+ if (filePath.includes('GunGraphMB'))
345
+ score += 200;
346
+ if (filePath.includes('/Graph/Graphs/GunGraph.cs'))
347
+ score += 220;
348
+ if (filePath.includes('/Graph/Nodes/Reloads/'))
349
+ score += 240;
350
+ if (filePath.includes('/PowerUps/WeaponPowerUp.cs'))
351
+ score += 180;
352
+ if (filePath.includes('/Game/Core/'))
353
+ score += 80;
354
+ if (filePath.includes('/Game/Graph/'))
355
+ score += 120;
356
+ if (filePath.includes('/Packages/'))
357
+ score -= 100;
358
+ if (filePath.includes('/Legacy/'))
359
+ score -= 80;
360
+ if (filePath.includes('/MonoScript/Minion'))
361
+ score -= 60;
362
+ if (methodName === 'RegisterGraphEvents')
363
+ score += 50;
364
+ if (methodName === 'RegisterEvents')
365
+ score += 60;
366
+ if (methodName === 'StartRoutineWithEvents')
367
+ score += 70;
368
+ if (methodName === 'GetValue')
369
+ score += 90;
370
+ if (methodName === 'CheckReload')
371
+ score += 90;
372
+ if (methodName === 'ReloadRoutine')
373
+ score += 90;
374
+ if (methodName === 'Equip' || methodName === 'EquipWithEvent')
375
+ score += 50;
376
+ return score;
377
+ };
378
+ const resolveNamedClassTargets = (classIdsByName, rawTargetId) => {
379
+ const text = String(rawTargetId || '').trim();
380
+ if (!text.startsWith('Class:'))
381
+ return [];
382
+ const className = text.slice('Class:'.length);
383
+ return classIdsByName.get(className) ?? [];
384
+ };