@veewo/gitnexus 1.5.6 → 1.5.8

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 (104) hide show
  1. package/dist/benchmark/analyze-runner.d.ts +0 -2
  2. package/dist/benchmark/analyze-runner.js +0 -6
  3. package/dist/benchmark/analyze-runner.test.js +1 -10
  4. package/dist/benchmark/runner.d.ts +0 -2
  5. package/dist/benchmark/runner.js +0 -2
  6. package/dist/benchmark/u2-e2e/neonspark-full-e2e.js +0 -11
  7. package/dist/benchmark/u2-performance-sampler.js +3 -16
  8. package/dist/cli/ai-context.js +1 -7
  9. package/dist/cli/analyze-options.d.ts +19 -6
  10. package/dist/cli/analyze-options.js +76 -71
  11. package/dist/cli/analyze-options.test.js +78 -73
  12. package/dist/cli/analyze-runtime-summary.js +0 -1
  13. package/dist/cli/analyze-runtime-summary.test.js +0 -2
  14. package/dist/cli/analyze-summary.d.ts +0 -2
  15. package/dist/cli/analyze-summary.js +0 -24
  16. package/dist/cli/analyze-summary.test.js +1 -65
  17. package/dist/cli/analyze.d.ts +2 -4
  18. package/dist/cli/analyze.js +14 -30
  19. package/dist/cli/analyze.test.js +9 -15
  20. package/dist/cli/benchmark-agent-context.d.ts +0 -2
  21. package/dist/cli/benchmark-agent-context.js +0 -2
  22. package/dist/cli/benchmark-agent-safe-query-context.d.ts +0 -2
  23. package/dist/cli/benchmark-agent-safe-query-context.js +0 -2
  24. package/dist/cli/benchmark-unity.d.ts +0 -2
  25. package/dist/cli/benchmark-unity.js +0 -2
  26. package/dist/cli/clean.d.ts +2 -3
  27. package/dist/cli/clean.js +4 -25
  28. package/dist/cli/index.js +1 -12
  29. package/dist/core/ingestion/pipeline.js +1 -44
  30. package/dist/mcp/local/agent-safe-response.js +1 -1
  31. package/dist/mcp/local/local-backend.d.ts +0 -23
  32. package/dist/mcp/local/local-backend.js +69 -248
  33. package/dist/mcp/local/runtime-chain-verify.test.js +0 -49
  34. package/dist/mcp/local/runtime-claim-rule-registry.d.ts +0 -11
  35. package/dist/mcp/local/runtime-claim-rule-registry.js +0 -159
  36. package/dist/mcp/local/runtime-claim-rule-registry.test.js +67 -214
  37. package/dist/mcp/tools.js +0 -70
  38. package/dist/storage/repo-manager.d.ts +1 -0
  39. package/dist/types/pipeline.d.ts +0 -3
  40. package/package.json +1 -1
  41. package/skills/gitnexus-cli.md +62 -38
  42. package/vendor/node_modules/node-addon-api/node_addon_api.Makefile +6 -0
  43. package/vendor/node_modules/node-addon-api/node_addon_api.target.mk +122 -0
  44. package/vendor/node_modules/node-addon-api/node_addon_api_except.target.mk +126 -0
  45. package/vendor/node_modules/node-addon-api/node_addon_api_except_all.target.mk +122 -0
  46. package/vendor/node_modules/node-addon-api/node_addon_api_maybe.target.mk +122 -0
  47. package/vendor/tree-sitter-dart/build/Release/.deps/node_modules/node-addon-api/node_addon_api_except.stamp.d +1 -0
  48. package/vendor/tree-sitter-dart/build/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  49. package/vendor/tree-sitter-proto/build/Release/.deps/node_modules/node-addon-api/node_addon_api_except.stamp.d +1 -0
  50. package/vendor/tree-sitter-proto/build/node_modules/node-addon-api/node_addon_api_except.stamp +0 -0
  51. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.d.ts +0 -60
  52. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.js +0 -395
  53. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.d.ts +0 -1
  54. package/dist/benchmark/u2-e2e/phase5-rule-lab-acceptance-runner.test.js +0 -41
  55. package/dist/cli/rule-lab.d.ts +0 -38
  56. package/dist/cli/rule-lab.js +0 -148
  57. package/dist/cli/rule-lab.test.d.ts +0 -1
  58. package/dist/cli/rule-lab.test.js +0 -31
  59. package/dist/cli/scope-manifest-config.d.ts +0 -9
  60. package/dist/cli/scope-manifest-config.js +0 -37
  61. package/dist/cli/sync-manifest.d.ts +0 -27
  62. package/dist/cli/sync-manifest.js +0 -200
  63. package/dist/cli/sync-manifest.test.d.ts +0 -1
  64. package/dist/cli/sync-manifest.test.js +0 -88
  65. package/dist/core/ingestion/unity-runtime-binding-rules.d.ts +0 -26
  66. package/dist/core/ingestion/unity-runtime-binding-rules.js +0 -408
  67. package/dist/rule-lab/analyze.d.ts +0 -13
  68. package/dist/rule-lab/analyze.js +0 -125
  69. package/dist/rule-lab/analyze.test.d.ts +0 -1
  70. package/dist/rule-lab/analyze.test.js +0 -246
  71. package/dist/rule-lab/compile.d.ts +0 -5
  72. package/dist/rule-lab/compile.js +0 -51
  73. package/dist/rule-lab/compiled-bundles.d.ts +0 -30
  74. package/dist/rule-lab/compiled-bundles.js +0 -36
  75. package/dist/rule-lab/curate.d.ts +0 -33
  76. package/dist/rule-lab/curate.js +0 -155
  77. package/dist/rule-lab/curate.test.d.ts +0 -1
  78. package/dist/rule-lab/curate.test.js +0 -137
  79. package/dist/rule-lab/curation-input-builder.d.ts +0 -45
  80. package/dist/rule-lab/curation-input-builder.js +0 -133
  81. package/dist/rule-lab/discover.d.ts +0 -13
  82. package/dist/rule-lab/discover.js +0 -74
  83. package/dist/rule-lab/discover.test.d.ts +0 -1
  84. package/dist/rule-lab/discover.test.js +0 -42
  85. package/dist/rule-lab/paths.d.ts +0 -21
  86. package/dist/rule-lab/paths.js +0 -37
  87. package/dist/rule-lab/paths.test.d.ts +0 -1
  88. package/dist/rule-lab/paths.test.js +0 -46
  89. package/dist/rule-lab/promote.d.ts +0 -26
  90. package/dist/rule-lab/promote.js +0 -387
  91. package/dist/rule-lab/promote.test.d.ts +0 -1
  92. package/dist/rule-lab/promote.test.js +0 -314
  93. package/dist/rule-lab/regress.d.ts +0 -60
  94. package/dist/rule-lab/regress.js +0 -122
  95. package/dist/rule-lab/regress.test.d.ts +0 -1
  96. package/dist/rule-lab/regress.test.js +0 -68
  97. package/dist/rule-lab/review-pack.d.ts +0 -34
  98. package/dist/rule-lab/review-pack.js +0 -165
  99. package/dist/rule-lab/review-pack.test.d.ts +0 -1
  100. package/dist/rule-lab/review-pack.test.js +0 -116
  101. package/dist/rule-lab/types.d.ts +0 -135
  102. package/dist/rule-lab/types.js +0 -1
  103. package/skills/_shared/unity-rule-authoring-contract.md +0 -64
  104. package/skills/gitnexus-unity-rule-gen.md +0 -107
@@ -1,408 +0,0 @@
1
- import { generateId } from '../../lib/utils.js';
2
- const RULE_EDGE_CONFIDENCE = 0.75;
3
- const RULE_ANOMALY_PREVIEW_LIMIT = 5;
4
- export function applyUnityRuntimeBindingRules(graph, rules, config) {
5
- const ruleResults = [];
6
- let totalEdges = 0;
7
- const existingPairs = new Set();
8
- for (const rel of graph.iterRelationships()) {
9
- if (rel.type === 'CALLS')
10
- existingPairs.add(`${rel.sourceId}->${rel.targetId}`);
11
- }
12
- const addSyntheticEdge = (sourceId, targetId, reason) => {
13
- if (sourceId === targetId)
14
- return false;
15
- const key = `${sourceId}->${targetId}`;
16
- if (existingPairs.has(key))
17
- return false;
18
- graph.addRelationship({
19
- id: generateId('CALLS', `${sourceId}->${targetId}:${reason}`),
20
- sourceId,
21
- targetId,
22
- type: 'CALLS',
23
- confidence: RULE_EDGE_CONFIDENCE,
24
- reason,
25
- });
26
- existingPairs.add(key);
27
- return true;
28
- };
29
- // Pre-build indexes
30
- const methodsByClassId = new Map();
31
- const containerNodes = [];
32
- const containerLabels = config.enableContainerNodes
33
- ? new Set(['Class', 'Struct', 'Interface', 'Record'])
34
- : new Set(['Class']);
35
- for (const rel of graph.iterRelationships()) {
36
- if (rel.type !== 'HAS_METHOD')
37
- continue;
38
- const method = graph.getNode(rel.targetId);
39
- if (!method || (method.label !== 'Method' && method.label !== 'Function'))
40
- continue;
41
- const list = methodsByClassId.get(rel.sourceId) ?? [];
42
- list.push(method);
43
- methodsByClassId.set(rel.sourceId, list);
44
- }
45
- for (const node of graph.iterNodes()) {
46
- if (containerLabels.has(node.label))
47
- containerNodes.push(node);
48
- }
49
- // Collect UNITY_ASSET_GUID_REF and UNITY_COMPONENT_INSTANCE edges
50
- const assetGuidRefs = [];
51
- const componentInstances = [];
52
- for (const rel of graph.iterRelationships()) {
53
- if (rel.type === 'UNITY_ASSET_GUID_REF')
54
- assetGuidRefs.push(rel);
55
- else if (rel.type === 'UNITY_COMPONENT_INSTANCE')
56
- componentInstances.push(rel);
57
- }
58
- const prefabSourceTargetsBySource = buildPrefabSourceTargetsBySource(assetGuidRefs);
59
- const methodsByResourceId = buildMethodsByResourceId(componentInstances, methodsByClassId);
60
- const executionState = {
61
- methodsByResourceId,
62
- resourceMethodLookupCache: new Map(),
63
- sceneRuntimeResourceIdsCache: new Map(),
64
- diagnostics: {
65
- rulesEvaluated: rules.length,
66
- bindingsEvaluated: 0,
67
- bindingsByKind: {},
68
- methodLookupCalls: 0,
69
- methodLookupCacheHits: 0,
70
- sceneRuntimeTraversalCalls: 0,
71
- sceneRuntimeTraversalCacheHits: 0,
72
- sceneRuntimeResourcesVisited: 0,
73
- anomalySet: new Set(),
74
- },
75
- };
76
- // Pre-build scene file index: lowercase scene name → fileId[]
77
- const sceneFilesByName = new Map();
78
- for (const node of graph.iterNodes()) {
79
- if (node.label !== 'File')
80
- continue;
81
- const filePath = String(node.properties.filePath ?? '');
82
- if (!filePath.endsWith('.unity'))
83
- continue;
84
- const fileName = (filePath.split('/').pop() ?? '').replace(/\.unity$/, '').toLowerCase();
85
- const list = sceneFilesByName.get(fileName) ?? [];
86
- list.push(node.id);
87
- sceneFilesByName.set(fileName, list);
88
- }
89
- for (const rule of rules) {
90
- let ruleEdges = 0;
91
- for (const binding of rule.resource_bindings ?? []) {
92
- executionState.diagnostics.bindingsEvaluated += 1;
93
- executionState.diagnostics.bindingsByKind[binding.kind] =
94
- (executionState.diagnostics.bindingsByKind[binding.kind] || 0) + 1;
95
- ruleEdges += processBinding(binding, rule.id, assetGuidRefs, componentInstances, methodsByClassId, containerNodes, sceneFilesByName, prefabSourceTargetsBySource, executionState, addSyntheticEdge);
96
- }
97
- if (rule.lifecycle_overrides?.additional_entry_points?.length) {
98
- ruleEdges += processLifecycleOverrides(rule, methodsByClassId, containerNodes, addSyntheticEdge);
99
- }
100
- totalEdges += ruleEdges;
101
- ruleResults.push({ ruleId: rule.id, edgesInjected: ruleEdges });
102
- }
103
- return {
104
- edgesInjected: totalEdges,
105
- ruleResults,
106
- diagnostics: finalizeRuleBindingDiagnostics(executionState.diagnostics, totalEdges),
107
- };
108
- }
109
- function findMethodsOnResource(resourceFileId, executionState, entryPoints) {
110
- executionState.diagnostics.methodLookupCalls += 1;
111
- const cacheKey = `${resourceFileId}::${entryPoints.join('|')}`;
112
- const cached = executionState.resourceMethodLookupCache.get(cacheKey);
113
- if (cached) {
114
- executionState.diagnostics.methodLookupCacheHits += 1;
115
- return cached;
116
- }
117
- const methods = executionState.methodsByResourceId.get(resourceFileId) ?? [];
118
- if (methods.length === 0) {
119
- executionState.resourceMethodLookupCache.set(cacheKey, []);
120
- return [];
121
- }
122
- const entrySet = new Set(entryPoints);
123
- const results = [];
124
- for (const method of methods) {
125
- if (entrySet.has(method.properties.name))
126
- results.push(method);
127
- }
128
- executionState.resourceMethodLookupCache.set(cacheKey, results);
129
- return results;
130
- }
131
- function processBinding(binding, ruleId, assetGuidRefs, componentInstances, methodsByClassId, containerNodes, sceneFilesByName, prefabSourceTargetsBySource, executionState, addEdge) {
132
- if (binding.kind === 'asset_ref_loads_components') {
133
- return processAssetRefLoadsComponents(binding, ruleId, assetGuidRefs, executionState, addEdge);
134
- }
135
- if (binding.kind === 'method_triggers_field_load') {
136
- return processMethodTriggersFieldLoad(binding, ruleId, assetGuidRefs, componentInstances, methodsByClassId, containerNodes, executionState, addEdge);
137
- }
138
- if (binding.kind === 'method_triggers_scene_load') {
139
- return processMethodTriggersSceneLoad(binding, ruleId, componentInstances, methodsByClassId, containerNodes, sceneFilesByName, prefabSourceTargetsBySource, executionState, addEdge);
140
- }
141
- if (binding.kind === 'method_triggers_method') {
142
- return processMethodTriggersMethod(binding, ruleId, methodsByClassId, containerNodes, addEdge);
143
- }
144
- addAnomaly(executionState.diagnostics, `rule=${ruleId}: unsupported resource_binding kind "${binding.kind}"`);
145
- return 0;
146
- }
147
- function processAssetRefLoadsComponents(binding, ruleId, assetGuidRefs, executionState, addEdge) {
148
- let count = 0;
149
- const pattern = binding.ref_field_pattern ? new RegExp(binding.ref_field_pattern) : null;
150
- const entryPoints = binding.target_entry_points ?? [];
151
- if (!pattern || entryPoints.length === 0) {
152
- addAnomaly(executionState.diagnostics, `rule=${ruleId}: asset_ref_loads_components missing ref_field_pattern or target_entry_points`);
153
- return 0;
154
- }
155
- const runtimeRootId = generateId('Method', 'unity-runtime-root');
156
- for (const ref of assetGuidRefs) {
157
- let fieldName = '';
158
- try {
159
- const parsed = JSON.parse(ref.reason);
160
- fieldName = parsed.fieldName ?? '';
161
- }
162
- catch {
163
- continue;
164
- }
165
- if (!pattern.test(fieldName))
166
- continue;
167
- const targetMethods = findMethodsOnResource(ref.targetId, executionState, entryPoints);
168
- for (const method of targetMethods) {
169
- if (addEdge(runtimeRootId, method.id, `unity-rule-resource-load:${ruleId}`))
170
- count++;
171
- }
172
- }
173
- return count;
174
- }
175
- function processMethodTriggersFieldLoad(binding, ruleId, assetGuidRefs, componentInstances, methodsByClassId, containerNodes, executionState, addEdge) {
176
- let count = 0;
177
- const classPattern = binding.host_class_pattern ? new RegExp(binding.host_class_pattern) : null;
178
- const loaderMethodNames = new Set(binding.loader_methods ?? []);
179
- const entryPoints = binding.target_entry_points ?? [];
180
- const defaultEntryPoints = ['OnEnable', 'Awake', 'Start'];
181
- const resolvedEntryPoints = entryPoints.length > 0 ? entryPoints : defaultEntryPoints;
182
- if (!classPattern || loaderMethodNames.size === 0) {
183
- addAnomaly(executionState.diagnostics, `rule=${ruleId}: method_triggers_field_load missing host_class_pattern or loader_methods`);
184
- return 0;
185
- }
186
- // Build asset ref index by source file
187
- const refsBySource = new Map();
188
- for (const ref of assetGuidRefs) {
189
- const list = refsBySource.get(ref.sourceId) ?? [];
190
- list.push(ref);
191
- refsBySource.set(ref.sourceId, list);
192
- }
193
- for (const cls of containerNodes) {
194
- if (!classPattern.test(cls.properties.name))
195
- continue;
196
- const methods = methodsByClassId.get(cls.id) ?? [];
197
- const loaders = methods.filter(m => loaderMethodNames.has(m.properties.name));
198
- if (loaders.length === 0)
199
- continue;
200
- // Find resource files this class is mounted on
201
- const resourceFileIds = new Set();
202
- for (const ci of componentInstances) {
203
- if (ci.sourceId === cls.id)
204
- resourceFileIds.add(ci.targetId);
205
- }
206
- // Follow asset refs from those resource files
207
- for (const resourceFileId of resourceFileIds) {
208
- for (const ref of refsBySource.get(resourceFileId) ?? []) {
209
- const targetMethods = findMethodsOnResource(ref.targetId, executionState, resolvedEntryPoints);
210
- for (const loader of loaders) {
211
- for (const target of targetMethods) {
212
- if (addEdge(loader.id, target.id, `unity-rule-loader-bridge:${ruleId}`))
213
- count++;
214
- }
215
- }
216
- }
217
- }
218
- }
219
- return count;
220
- }
221
- function processMethodTriggersSceneLoad(binding, ruleId, componentInstances, methodsByClassId, containerNodes, sceneFilesByName, prefabSourceTargetsBySource, executionState, addEdge) {
222
- const classPattern = binding.host_class_pattern ? new RegExp(binding.host_class_pattern) : null;
223
- const loaderMethodNames = new Set(binding.loader_methods ?? []);
224
- const sceneName = binding.scene_name;
225
- const defaultEntryPoints = ['OnEnable', 'Awake', 'Start'];
226
- const entryPoints = (binding.target_entry_points ?? []).length > 0
227
- ? binding.target_entry_points
228
- : defaultEntryPoints;
229
- if (!classPattern || loaderMethodNames.size === 0 || !sceneName) {
230
- addAnomaly(executionState.diagnostics, `rule=${ruleId}: method_triggers_scene_load missing host_class_pattern, loader_methods, or scene_name`);
231
- return 0;
232
- }
233
- const sceneFileIds = sceneFilesByName.get(sceneName.toLowerCase()) ?? [];
234
- if (sceneFileIds.length === 0) {
235
- addAnomaly(executionState.diagnostics, `rule=${ruleId}: scene "${sceneName}" not found in File(.unity) index`);
236
- return 0;
237
- }
238
- let count = 0;
239
- for (const cls of containerNodes) {
240
- if (!classPattern.test(cls.properties.name))
241
- continue;
242
- const methods = methodsByClassId.get(cls.id) ?? [];
243
- const loaders = methods.filter(m => loaderMethodNames.has(m.properties.name));
244
- if (loaders.length === 0)
245
- continue;
246
- for (const sceneFileId of sceneFileIds) {
247
- const runtimeResourceIds = getSceneRuntimeResourceIds(sceneFileId, prefabSourceTargetsBySource, executionState);
248
- for (const runtimeResourceId of runtimeResourceIds) {
249
- const targetMethods = findMethodsOnResource(runtimeResourceId, executionState, entryPoints);
250
- for (const loader of loaders) {
251
- for (const target of targetMethods) {
252
- if (addEdge(loader.id, target.id, `unity-rule-scene-load:${ruleId}`))
253
- count++;
254
- }
255
- }
256
- }
257
- }
258
- }
259
- return count;
260
- }
261
- function buildMethodsByResourceId(componentInstances, methodsByClassId) {
262
- const methodsByResourceId = new Map();
263
- for (const componentRef of componentInstances) {
264
- const methods = methodsByClassId.get(componentRef.sourceId) ?? [];
265
- if (methods.length === 0)
266
- continue;
267
- const list = methodsByResourceId.get(componentRef.targetId) ?? [];
268
- list.push(...methods);
269
- methodsByResourceId.set(componentRef.targetId, list);
270
- }
271
- return methodsByResourceId;
272
- }
273
- function buildPrefabSourceTargetsBySource(assetGuidRefs) {
274
- const targetsBySource = new Map();
275
- for (const ref of assetGuidRefs) {
276
- let fieldName = '';
277
- try {
278
- const parsed = JSON.parse(String(ref.reason || '{}'));
279
- fieldName = String(parsed?.fieldName || '');
280
- }
281
- catch {
282
- continue;
283
- }
284
- if (fieldName !== 'm_SourcePrefab')
285
- continue;
286
- const targets = targetsBySource.get(ref.sourceId) ?? new Set();
287
- targets.add(ref.targetId);
288
- targetsBySource.set(ref.sourceId, targets);
289
- }
290
- const out = new Map();
291
- for (const [sourceId, targets] of targetsBySource.entries()) {
292
- out.set(sourceId, [...targets]);
293
- }
294
- return out;
295
- }
296
- function collectSceneRuntimeResourceIds(sceneFileId, prefabSourceTargetsBySource) {
297
- const visited = new Set([sceneFileId]);
298
- const queue = [sceneFileId];
299
- while (queue.length > 0) {
300
- const currentId = queue.shift();
301
- for (const targetId of prefabSourceTargetsBySource.get(currentId) ?? []) {
302
- if (visited.has(targetId))
303
- continue;
304
- visited.add(targetId);
305
- queue.push(targetId);
306
- }
307
- }
308
- return [...visited];
309
- }
310
- function getSceneRuntimeResourceIds(sceneFileId, prefabSourceTargetsBySource, executionState) {
311
- executionState.diagnostics.sceneRuntimeTraversalCalls += 1;
312
- const cached = executionState.sceneRuntimeResourceIdsCache.get(sceneFileId);
313
- if (cached) {
314
- executionState.diagnostics.sceneRuntimeTraversalCacheHits += 1;
315
- return cached;
316
- }
317
- const ids = collectSceneRuntimeResourceIds(sceneFileId, prefabSourceTargetsBySource);
318
- executionState.sceneRuntimeResourceIdsCache.set(sceneFileId, ids);
319
- executionState.diagnostics.sceneRuntimeResourcesVisited += ids.length;
320
- return ids;
321
- }
322
- function processMethodTriggersMethod(binding, ruleId, methodsByClassId, containerNodes, addEdge) {
323
- const { source_class_pattern, source_method, target_class_pattern, target_method } = binding;
324
- if (!source_class_pattern || !source_method || !target_class_pattern || !target_method)
325
- return 0;
326
- const srcPattern = new RegExp(source_class_pattern);
327
- const tgtPattern = new RegExp(target_class_pattern);
328
- let sourceMethodId;
329
- let targetMethodId;
330
- for (const cls of containerNodes) {
331
- if (!sourceMethodId && srcPattern.test(cls.properties.name)) {
332
- const match = (methodsByClassId.get(cls.id) ?? []).find(m => m.properties.name === source_method);
333
- if (match)
334
- sourceMethodId = match.id;
335
- }
336
- if (!targetMethodId && tgtPattern.test(cls.properties.name)) {
337
- const match = (methodsByClassId.get(cls.id) ?? []).find(m => m.properties.name === target_method);
338
- if (match)
339
- targetMethodId = match.id;
340
- }
341
- if (sourceMethodId && targetMethodId)
342
- break;
343
- }
344
- if (!sourceMethodId || !targetMethodId)
345
- return 0;
346
- return addEdge(sourceMethodId, targetMethodId, `unity-rule-method-bridge:${ruleId}`) ? 1 : 0;
347
- }
348
- function processLifecycleOverrides(rule, methodsByClassId, containerNodes, addEdge) {
349
- const overrides = rule.lifecycle_overrides;
350
- if (!overrides?.additional_entry_points?.length)
351
- return 0;
352
- const entrySet = new Set(overrides.additional_entry_points);
353
- const scopePattern = overrides.scope ? new RegExp(overrides.scope) : null;
354
- let count = 0;
355
- const runtimeRootId = generateId('Method', 'unity-runtime-root');
356
- for (const cls of containerNodes) {
357
- if (scopePattern && !scopePattern.test(cls.properties.filePath ?? cls.properties.name))
358
- continue;
359
- for (const method of methodsByClassId.get(cls.id) ?? []) {
360
- if (!entrySet.has(method.properties.name))
361
- continue;
362
- if (addEdge(runtimeRootId, method.id, `unity-rule-lifecycle-override:${rule.id}`))
363
- count++;
364
- }
365
- }
366
- return count;
367
- }
368
- function addAnomaly(diagnostics, message) {
369
- diagnostics.anomalySet.add(message);
370
- }
371
- function finalizeRuleBindingDiagnostics(diagnostics, edgesInjected) {
372
- const anomalies = [...diagnostics.anomalySet];
373
- const shouldAgentReport = anomalies.length > 0;
374
- const bindingsByKind = Object.fromEntries(Object.entries(diagnostics.bindingsByKind).sort(([a], [b]) => a.localeCompare(b)));
375
- const kindSummary = Object.entries(bindingsByKind)
376
- .map(([kind, count]) => `${kind}=${count}`)
377
- .join(', ') || 'none';
378
- const summary = [
379
- `rule_binding.summary: rules=${diagnostics.rulesEvaluated}, bindings=${diagnostics.bindingsEvaluated}, edges=${edgesInjected}`,
380
- `rule_binding.bindings_by_kind: ${kindSummary}`,
381
- `rule_binding.lookup: method_calls=${diagnostics.methodLookupCalls}, cache_hits=${diagnostics.methodLookupCacheHits}`,
382
- `rule_binding.scene_closure: traversals=${diagnostics.sceneRuntimeTraversalCalls}, cache_hits=${diagnostics.sceneRuntimeTraversalCacheHits}, visited_resources=${diagnostics.sceneRuntimeResourcesVisited}`,
383
- `rule_binding.agent_report: should_report=${shouldAgentReport} reason="${shouldAgentReport ? 'rule-binding anomalies detected' : 'no anomalies detected'}"`,
384
- ];
385
- if (anomalies.length > 0) {
386
- summary.push(`rule_binding.anomalies: count=${anomalies.length}`);
387
- for (const anomaly of anomalies.slice(0, RULE_ANOMALY_PREVIEW_LIMIT)) {
388
- summary.push(`rule_binding.anomaly: ${anomaly}`);
389
- }
390
- if (anomalies.length > RULE_ANOMALY_PREVIEW_LIMIT) {
391
- summary.push(`rule_binding.anomaly: ... ${anomalies.length - RULE_ANOMALY_PREVIEW_LIMIT} more`);
392
- }
393
- }
394
- return {
395
- rulesEvaluated: diagnostics.rulesEvaluated,
396
- bindingsEvaluated: diagnostics.bindingsEvaluated,
397
- bindingsByKind,
398
- methodLookupCalls: diagnostics.methodLookupCalls,
399
- methodLookupCacheHits: diagnostics.methodLookupCacheHits,
400
- sceneRuntimeTraversalCalls: diagnostics.sceneRuntimeTraversalCalls,
401
- sceneRuntimeTraversalCacheHits: diagnostics.sceneRuntimeTraversalCacheHits,
402
- sceneRuntimeResourcesVisited: diagnostics.sceneRuntimeResourcesVisited,
403
- anomalies,
404
- shouldAgentReport,
405
- agentReportReason: shouldAgentReport ? 'rule-binding anomalies detected' : 'no anomalies detected',
406
- summary,
407
- };
408
- }
@@ -1,13 +0,0 @@
1
- import { getRuleLabPaths } from './paths.js';
2
- import type { RuleLabCandidate, RuleLabSlice } from './types.js';
3
- export interface AnalyzeInput {
4
- repoPath: string;
5
- runId: string;
6
- sliceId: string;
7
- }
8
- export interface AnalyzeOutput {
9
- paths: ReturnType<typeof getRuleLabPaths>;
10
- candidates: RuleLabCandidate[];
11
- slice: RuleLabSlice;
12
- }
13
- export declare function analyzeRuleLabSlice(input: AnalyzeInput): Promise<AnalyzeOutput>;
@@ -1,125 +0,0 @@
1
- import fs from 'node:fs/promises';
2
- import path from 'node:path';
3
- import { createHash } from 'node:crypto';
4
- import { getRuleLabPaths } from './paths.js';
5
- import { buildCurationInput } from './curation-input-builder.js';
6
- function buildCandidateId(slice, variant) {
7
- return createHash('sha1')
8
- .update(`${slice.id}:${slice.trigger_family}:${slice.resource_types.join('|')}:${slice.host_base_type.join('|')}:${variant}`)
9
- .digest('hex')
10
- .slice(0, 12);
11
- }
12
- function normalizeToken(value) {
13
- return String(value || '')
14
- .trim()
15
- .toLowerCase()
16
- .replace(/[^a-z0-9]+/g, '-')
17
- .replace(/^-+|-+$/g, '');
18
- }
19
- function inferRuleStem(slice, pair) {
20
- const source = normalizeToken(pair.source_anchor.symbol || pair.source_anchor.file || `${slice.id}-source`);
21
- const target = normalizeToken(pair.target_anchor.symbol || pair.target_anchor.file || `${slice.id}-target`);
22
- const joined = [source, target].filter(Boolean).join('-');
23
- return joined || normalizeToken(slice.id) || 'runtime-rule';
24
- }
25
- function buildProposalTopology(slice) {
26
- const requiredHops = Array.isArray(slice.required_hops) && slice.required_hops.length > 0
27
- ? slice.required_hops
28
- : ['resource', 'code_runtime'];
29
- return requiredHops.map((hop) => ({
30
- hop,
31
- from: { entity: hop === 'resource' ? 'resource' : 'script' },
32
- to: { entity: hop === 'code_runtime' ? 'runtime' : 'script' },
33
- edge: { kind: hop === 'resource' ? 'binds_script' : 'calls' },
34
- }));
35
- }
36
- function buildExactPairCandidates(slice) {
37
- const pairs = Array.isArray(slice.exact_pairs) ? slice.exact_pairs : [];
38
- if (pairs.length === 0) {
39
- throw new Error('exact_pairs must be non-empty for reduced rule-lab analyze flow');
40
- }
41
- const seenPairIds = new Set();
42
- for (const pair of pairs) {
43
- const pairId = String(pair.id || '').trim();
44
- if (!pairId)
45
- continue;
46
- if (seenPairIds.has(pairId)) {
47
- throw new Error(`duplicate_exact_pair_id: ${pairId}`);
48
- }
49
- seenPairIds.add(pairId);
50
- }
51
- const topology = buildProposalTopology(slice);
52
- return pairs.map((pair, index) => {
53
- const pairKey = String(pair.id || `${index + 1}`).trim();
54
- const sourceAnchor = `${String(pair.source_anchor.file || '').trim()}:${Number(pair.source_anchor.line || 1)}`;
55
- const targetAnchor = `${String(pair.target_anchor.file || '').trim()}:${Number(pair.target_anchor.line || 1)}`;
56
- const draftRuleId = String(pair.draft_rule_id || '').trim() || `unity.event.${inferRuleStem(slice, pair)}.v1`;
57
- const bindingKind = pair.binding_kind || 'method_triggers_method';
58
- return {
59
- id: buildCandidateId(slice, `exact:${pairKey}`),
60
- title: `${slice.trigger_family} exact pair ${pairKey}`,
61
- rule_hint: `${slice.trigger_family}.${slice.id}.exact.${pairKey}`,
62
- proposal_kind: 'per_anchor_rule',
63
- aggregation_mode: 'per_anchor_rules',
64
- binding_kind: bindingKind,
65
- draft_rule_id: draftRuleId,
66
- topology,
67
- closure: {
68
- required_hops: topology.map((hop) => hop.hop),
69
- failure_map: {
70
- missing_evidence: 'rule_matched_but_evidence_missing',
71
- },
72
- },
73
- claims: {
74
- guarantees: [`exact pair linked: ${sourceAnchor} -> ${targetAnchor}`],
75
- non_guarantees: ['sparse gap path only; no exhaustive discovery semantics'],
76
- next_action: `gitnexus query "${slice.trigger_family}"`,
77
- },
78
- exact_pair: pair,
79
- evidence: {
80
- hops: [
81
- {
82
- hop_type: 'code_runtime',
83
- anchor: sourceAnchor,
84
- snippet: String(pair.source_anchor.symbol || 'source'),
85
- },
86
- {
87
- hop_type: 'code_runtime',
88
- anchor: targetAnchor,
89
- snippet: String(pair.target_anchor.symbol || 'target'),
90
- },
91
- ],
92
- },
93
- };
94
- });
95
- }
96
- function assertNoPlaceholderIds(runId, sliceId) {
97
- const placeholderRe = /<[^>]+>|placeholder|todo|tbd/i;
98
- if (placeholderRe.test(runId) || placeholderRe.test(sliceId)) {
99
- throw new Error('placeholder run/slice ids are not allowed');
100
- }
101
- }
102
- export async function analyzeRuleLabSlice(input) {
103
- assertNoPlaceholderIds(input.runId, input.sliceId);
104
- const normalizedRepoPath = path.resolve(input.repoPath);
105
- const paths = getRuleLabPaths(normalizedRepoPath, input.runId, input.sliceId);
106
- const slicePath = path.join(paths.slicesRoot, input.sliceId, 'slice.json');
107
- const raw = await fs.readFile(slicePath, 'utf-8');
108
- const slice = JSON.parse(raw);
109
- const candidates = buildExactPairCandidates(slice);
110
- const curation = buildCurationInput({
111
- runId: input.runId,
112
- sliceId: input.sliceId,
113
- slice,
114
- candidates,
115
- });
116
- await fs.mkdir(path.dirname(paths.candidatesPath), { recursive: true });
117
- await fs.writeFile(paths.candidatesPath, `${candidates.map((candidate) => JSON.stringify(candidate)).join('\n')}\n`, 'utf-8');
118
- await fs.writeFile(slicePath, `${JSON.stringify(slice, null, 2)}\n`, 'utf-8');
119
- await fs.writeFile(path.join(path.dirname(paths.candidatesPath), 'curation-input.json'), `${JSON.stringify(curation, null, 2)}\n`, 'utf-8');
120
- return {
121
- paths,
122
- candidates,
123
- slice,
124
- };
125
- }
@@ -1 +0,0 @@
1
- export {};