@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
|
@@ -12,33 +12,13 @@ const LIFECYCLE_CALLBACKS = new Set([
|
|
|
12
12
|
'OnDisable',
|
|
13
13
|
'OnDestroy',
|
|
14
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
15
|
const SYNTHETIC_RUNTIME_ROOT_NAME = 'unity-runtime-root';
|
|
35
16
|
const SYNTHETIC_RUNTIME_ROOT_ID = generateId('Method', SYNTHETIC_RUNTIME_ROOT_NAME);
|
|
36
17
|
export const DEFAULT_UNITY_LIFECYCLE_SYNTHETIC_CONFIG = {
|
|
37
|
-
enabled:
|
|
18
|
+
enabled: true,
|
|
38
19
|
maxSyntheticEdgesPerClass: 12,
|
|
39
20
|
maxSyntheticEdgesTotal: 256,
|
|
40
21
|
lifecycleEdgeConfidence: 0.72,
|
|
41
|
-
loaderEdgeConfidence: 0.68,
|
|
42
22
|
};
|
|
43
23
|
export const detectUnityLifecycleHosts = (graph) => {
|
|
44
24
|
const methodsByClass = new Map();
|
|
@@ -79,12 +59,10 @@ export const detectUnityLifecycleHosts = (graph) => {
|
|
|
79
59
|
continue;
|
|
80
60
|
const methods = methodsByClass.get(node.id) ?? [];
|
|
81
61
|
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
62
|
hosts.push({
|
|
84
63
|
classNode: node,
|
|
85
64
|
baseType,
|
|
86
65
|
lifecycleCallbacks: sortMethodsByName(lifecycleCallbacks),
|
|
87
|
-
loaderAnchors: sortMethodsByName(loaderAnchors),
|
|
88
66
|
methods: sortMethodsByName(methods),
|
|
89
67
|
});
|
|
90
68
|
}
|
|
@@ -95,15 +73,6 @@ export const applyUnityLifecycleSyntheticCalls = (graph, config = {}) => {
|
|
|
95
73
|
...DEFAULT_UNITY_LIFECYCLE_SYNTHETIC_CONFIG,
|
|
96
74
|
...config,
|
|
97
75
|
};
|
|
98
|
-
if (!cfg.enabled) {
|
|
99
|
-
return {
|
|
100
|
-
syntheticEdgeCount: 0,
|
|
101
|
-
lifecycleEdgeCount: 0,
|
|
102
|
-
loaderEdgeCount: 0,
|
|
103
|
-
hostCount: 0,
|
|
104
|
-
rejectedHostCount: 0,
|
|
105
|
-
};
|
|
106
|
-
}
|
|
107
76
|
const hosts = detectUnityLifecycleHosts(graph);
|
|
108
77
|
const acceptedHosts = [];
|
|
109
78
|
let rejectedHostCount = 0;
|
|
@@ -114,27 +83,11 @@ export const applyUnityLifecycleSyntheticCalls = (graph, config = {}) => {
|
|
|
114
83
|
}
|
|
115
84
|
acceptedHosts.push(host);
|
|
116
85
|
}
|
|
117
|
-
acceptedHosts.sort((left, right) =>
|
|
86
|
+
acceptedHosts.sort((left, right) => right.lifecycleCallbacks.length - left.lifecycleCallbacks.length);
|
|
118
87
|
if (acceptedHosts.length === 0) {
|
|
119
|
-
return {
|
|
120
|
-
syntheticEdgeCount: 0,
|
|
121
|
-
lifecycleEdgeCount: 0,
|
|
122
|
-
loaderEdgeCount: 0,
|
|
123
|
-
hostCount: 0,
|
|
124
|
-
rejectedHostCount,
|
|
125
|
-
};
|
|
88
|
+
return { syntheticEdgeCount: 0, lifecycleEdgeCount: 0, loaderEdgeCount: 0, hostCount: 0, rejectedHostCount };
|
|
126
89
|
}
|
|
127
90
|
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
91
|
const existingPairs = new Set();
|
|
139
92
|
for (const rel of graph.iterRelationships()) {
|
|
140
93
|
if (rel.type === 'CALLS')
|
|
@@ -143,89 +96,35 @@ export const applyUnityLifecycleSyntheticCalls = (graph, config = {}) => {
|
|
|
143
96
|
const syntheticEdgesPerClass = new Map();
|
|
144
97
|
let syntheticEdgeCount = 0;
|
|
145
98
|
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
99
|
for (const host of acceptedHosts) {
|
|
185
100
|
const classId = host.classNode.id;
|
|
186
101
|
for (const callback of host.lifecycleCallbacks) {
|
|
187
|
-
|
|
102
|
+
const classCount = syntheticEdgesPerClass.get(classId) ?? 0;
|
|
103
|
+
if (syntheticEdgeCount >= cfg.maxSyntheticEdgesTotal)
|
|
188
104
|
break;
|
|
189
|
-
|
|
190
|
-
}
|
|
191
|
-
if (!canAllocate(classId))
|
|
192
|
-
continue;
|
|
193
|
-
for (const callback of host.lifecycleCallbacks) {
|
|
194
|
-
if (!canAllocate(classId))
|
|
105
|
+
if (classCount >= cfg.maxSyntheticEdgesPerClass)
|
|
195
106
|
break;
|
|
196
|
-
|
|
197
|
-
|
|
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'))
|
|
107
|
+
const pairKey = `${SYNTHETIC_RUNTIME_ROOT_ID}->${callback.id}`;
|
|
108
|
+
if (existingPairs.has(pairKey))
|
|
217
109
|
continue;
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
110
|
+
graph.addRelationship({
|
|
111
|
+
id: generateId('CALLS', `${SYNTHETIC_RUNTIME_ROOT_ID}->${callback.id}:unity-lifecycle-synthetic`),
|
|
112
|
+
sourceId: SYNTHETIC_RUNTIME_ROOT_ID,
|
|
113
|
+
targetId: callback.id,
|
|
114
|
+
type: 'CALLS',
|
|
115
|
+
confidence: cfg.lifecycleEdgeConfidence,
|
|
116
|
+
reason: 'unity-lifecycle-synthetic',
|
|
117
|
+
});
|
|
118
|
+
existingPairs.add(pairKey);
|
|
119
|
+
syntheticEdgeCount += 1;
|
|
120
|
+
lifecycleEdgeCount += 1;
|
|
121
|
+
syntheticEdgesPerClass.set(classId, classCount + 1);
|
|
223
122
|
}
|
|
224
123
|
}
|
|
225
124
|
return {
|
|
226
125
|
syntheticEdgeCount,
|
|
227
126
|
lifecycleEdgeCount,
|
|
228
|
-
loaderEdgeCount,
|
|
127
|
+
loaderEdgeCount: 0,
|
|
229
128
|
hostCount: acceptedHosts.length,
|
|
230
129
|
rejectedHostCount,
|
|
231
130
|
runtimeRootNodeId: syntheticEdgeCount > 0 ? SYNTHETIC_RUNTIME_ROOT_ID : undefined,
|
|
@@ -237,11 +136,7 @@ const resolveUnityBaseType = (graph, extendsByClass, classIdsByName, classId, vi
|
|
|
237
136
|
visited.add(classId);
|
|
238
137
|
for (const edge of extendsByClass.get(classId) ?? []) {
|
|
239
138
|
const targetNode = graph.getNode(edge.targetId);
|
|
240
|
-
const candidates = [
|
|
241
|
-
targetNode?.properties?.name ?? '',
|
|
242
|
-
edge.targetId,
|
|
243
|
-
edge.reason,
|
|
244
|
-
];
|
|
139
|
+
const candidates = [targetNode?.properties?.name ?? '', edge.targetId, edge.reason];
|
|
245
140
|
for (const candidate of candidates) {
|
|
246
141
|
const normalized = normalizeBaseType(candidate);
|
|
247
142
|
if (normalized)
|
|
@@ -264,12 +159,10 @@ const normalizeBaseType = (value) => {
|
|
|
264
159
|
const text = String(value || '').trim();
|
|
265
160
|
if (!text)
|
|
266
161
|
return undefined;
|
|
267
|
-
if (text.endsWith(UNITY_MONOBEHAVIOUR) || text.includes(`.${UNITY_MONOBEHAVIOUR}`))
|
|
162
|
+
if (text.endsWith(UNITY_MONOBEHAVIOUR) || text.includes(`.${UNITY_MONOBEHAVIOUR}`))
|
|
268
163
|
return UNITY_MONOBEHAVIOUR;
|
|
269
|
-
}
|
|
270
|
-
if (text.endsWith(UNITY_SCRIPTABLE_OBJECT) || text.includes(`.${UNITY_SCRIPTABLE_OBJECT}`)) {
|
|
164
|
+
if (text.endsWith(UNITY_SCRIPTABLE_OBJECT) || text.includes(`.${UNITY_SCRIPTABLE_OBJECT}`))
|
|
271
165
|
return UNITY_SCRIPTABLE_OBJECT;
|
|
272
|
-
}
|
|
273
166
|
return undefined;
|
|
274
167
|
};
|
|
275
168
|
const ensureRuntimeRootNode = (graph) => {
|
|
@@ -278,10 +171,7 @@ const ensureRuntimeRootNode = (graph) => {
|
|
|
278
171
|
graph.addNode({
|
|
279
172
|
id: SYNTHETIC_RUNTIME_ROOT_ID,
|
|
280
173
|
label: 'Method',
|
|
281
|
-
properties: {
|
|
282
|
-
name: SYNTHETIC_RUNTIME_ROOT_NAME,
|
|
283
|
-
filePath: '',
|
|
284
|
-
},
|
|
174
|
+
properties: { name: SYNTHETIC_RUNTIME_ROOT_NAME, filePath: '' },
|
|
285
175
|
});
|
|
286
176
|
};
|
|
287
177
|
const isPlaceholderHost = (host) => {
|
|
@@ -299,86 +189,9 @@ const sortMethodsByName = (methods) => [...methods].sort((left, right) => {
|
|
|
299
189
|
return byName;
|
|
300
190
|
return left.id.localeCompare(right.id);
|
|
301
191
|
});
|
|
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
192
|
const resolveNamedClassTargets = (classIdsByName, rawTargetId) => {
|
|
379
193
|
const text = String(rawTargetId || '').trim();
|
|
380
194
|
if (!text.startsWith('Class:'))
|
|
381
195
|
return [];
|
|
382
|
-
|
|
383
|
-
return classIdsByName.get(className) ?? [];
|
|
196
|
+
return classIdsByName.get(text.slice('Class:'.length)) ?? [];
|
|
384
197
|
};
|
|
@@ -243,7 +243,7 @@ test('detects Unity hosts through transitive inheritance chains', () => {
|
|
|
243
243
|
const gunGraphHost = hosts.find((host) => host.classNode.id === gunGraphId);
|
|
244
244
|
assert.ok(gunGraphHost);
|
|
245
245
|
assert.equal(gunGraphHost.baseType, 'ScriptableObject');
|
|
246
|
-
assert.
|
|
246
|
+
assert.ok(gunGraphHost.methods.length > 0);
|
|
247
247
|
});
|
|
248
248
|
test('prioritizes gameplay lifecycle hosts when synthetic edge budget is tight', () => {
|
|
249
249
|
const graph = createKnowledgeGraph();
|
|
@@ -3,6 +3,7 @@ import { generateId } from '../../lib/utils.js';
|
|
|
3
3
|
import { buildUnityScanContext } from '../unity/scan-context.js';
|
|
4
4
|
import { resolveUnityBindings } from '../unity/resolver.js';
|
|
5
5
|
import { buildUnityParitySeed } from './unity-parity-seed.js';
|
|
6
|
+
import { resolveUnityConfig } from '../config/unity-config.js';
|
|
6
7
|
const UNITY_DIAGNOSTIC_SAMPLE_LIMIT = 3;
|
|
7
8
|
export async function processUnityResources(graph, options, deps) {
|
|
8
9
|
const tStart = performance.now();
|
|
@@ -116,6 +117,53 @@ export async function processUnityResources(graph, options, deps) {
|
|
|
116
117
|
};
|
|
117
118
|
for (const binding of resolved.resourceBindings) {
|
|
118
119
|
bindingCount += 1;
|
|
120
|
+
componentCount += 1;
|
|
121
|
+
const resourceFileId = ensureResourceFileNode(graph, binding.resourcePath);
|
|
122
|
+
const componentPayload = buildUnityPayload(binding, payloadMode);
|
|
123
|
+
graph.addRelationship({
|
|
124
|
+
id: generateId('UNITY_COMPONENT_INSTANCE', `${classNode.id}->${resourceFileId}:${binding.componentObjectId}`),
|
|
125
|
+
type: 'UNITY_COMPONENT_INSTANCE',
|
|
126
|
+
sourceId: classNode.id,
|
|
127
|
+
targetId: resourceFileId,
|
|
128
|
+
confidence: 1.0,
|
|
129
|
+
reason: JSON.stringify(componentPayload),
|
|
130
|
+
});
|
|
131
|
+
graph.addRelationship({
|
|
132
|
+
id: generateId('UNITY_GRAPH_NODE_SCRIPT_REF', `${resourceFileId}->${classNode.id}`),
|
|
133
|
+
type: 'UNITY_GRAPH_NODE_SCRIPT_REF',
|
|
134
|
+
sourceId: resourceFileId,
|
|
135
|
+
targetId: classNode.id,
|
|
136
|
+
confidence: 1.0,
|
|
137
|
+
reason: JSON.stringify({
|
|
138
|
+
resourcePath: normalizePath(binding.resourcePath),
|
|
139
|
+
resourceType: binding.resourceType,
|
|
140
|
+
bindingKind: binding.bindingKind,
|
|
141
|
+
componentObjectId: binding.componentObjectId,
|
|
142
|
+
}),
|
|
143
|
+
});
|
|
144
|
+
for (const ref of binding.resolvedReferences || []) {
|
|
145
|
+
const targetAssetPath = normalizePath(String(ref.target?.assetPath || '').trim());
|
|
146
|
+
const referenceGuid = String(ref.guid || '').trim();
|
|
147
|
+
if (!targetAssetPath || !referenceGuid)
|
|
148
|
+
continue;
|
|
149
|
+
const sourceFileId = ensureResourceFileNode(graph, binding.resourcePath);
|
|
150
|
+
const targetFileId = ensureResourceFileNode(graph, targetAssetPath);
|
|
151
|
+
graph.addRelationship({
|
|
152
|
+
id: generateId('UNITY_ASSET_GUID_REF', `${sourceFileId}->${targetFileId}:${ref.fieldName}:${referenceGuid}:${String(ref.fileId || '')}`),
|
|
153
|
+
type: 'UNITY_ASSET_GUID_REF',
|
|
154
|
+
sourceId: sourceFileId,
|
|
155
|
+
targetId: targetFileId,
|
|
156
|
+
confidence: 1.0,
|
|
157
|
+
reason: JSON.stringify({
|
|
158
|
+
resourcePath: normalizePath(binding.resourcePath),
|
|
159
|
+
targetResourcePath: targetAssetPath,
|
|
160
|
+
guid: referenceGuid.toLowerCase(),
|
|
161
|
+
fileId: String(ref.fileId || ''),
|
|
162
|
+
fieldName: ref.fieldName,
|
|
163
|
+
sourceLayer: ref.sourceLayer || 'unknown',
|
|
164
|
+
}),
|
|
165
|
+
});
|
|
166
|
+
}
|
|
119
167
|
appendSummary(classNode.id, binding);
|
|
120
168
|
const serializableTypeLinking = collectSerializableTypeTargetsForBinding(symbol, binding, scanContext, canonicalClassNodeBySymbol);
|
|
121
169
|
serializedTypeEdgeCount += serializableTypeLinking.edgeCount;
|
|
@@ -123,8 +171,22 @@ export async function processUnityResources(graph, options, deps) {
|
|
|
123
171
|
for (const hitSymbol of serializableTypeLinking.symbols) {
|
|
124
172
|
serializedTypeSymbols.add(hitSymbol);
|
|
125
173
|
}
|
|
126
|
-
for (const
|
|
127
|
-
appendSummary(targetClassId, binding);
|
|
174
|
+
for (const link of serializableTypeLinking.links) {
|
|
175
|
+
appendSummary(link.targetClassId, binding);
|
|
176
|
+
graph.addRelationship({
|
|
177
|
+
id: generateId('UNITY_SERIALIZED_TYPE_IN', `${classNode.id}->${link.targetClassId}:${normalizePath(binding.resourcePath)}:${link.fieldName}`),
|
|
178
|
+
type: 'UNITY_SERIALIZED_TYPE_IN',
|
|
179
|
+
sourceId: classNode.id,
|
|
180
|
+
targetId: link.targetClassId,
|
|
181
|
+
confidence: 1.0,
|
|
182
|
+
reason: JSON.stringify({
|
|
183
|
+
hostSymbol: symbol,
|
|
184
|
+
declaredType: link.declaredType,
|
|
185
|
+
fieldName: link.fieldName,
|
|
186
|
+
sourceLayer: link.sourceLayer,
|
|
187
|
+
resourcePath: normalizePath(binding.resourcePath),
|
|
188
|
+
}),
|
|
189
|
+
});
|
|
128
190
|
}
|
|
129
191
|
}
|
|
130
192
|
for (const [sourceNodeId, perPath] of summaryBySource.entries()) {
|
|
@@ -205,24 +267,7 @@ function normalizePath(filePath) {
|
|
|
205
267
|
function resolveUnityPayloadMode(explicit) {
|
|
206
268
|
if (explicit)
|
|
207
269
|
return explicit;
|
|
208
|
-
|
|
209
|
-
if (envMode === 'full')
|
|
210
|
-
return 'full';
|
|
211
|
-
return 'compact';
|
|
212
|
-
}
|
|
213
|
-
function createComponentNode(symbol, binding, payloadMode) {
|
|
214
|
-
const payload = buildUnityPayload(binding, payloadMode);
|
|
215
|
-
return {
|
|
216
|
-
id: generateId('CodeElement', `${binding.resourcePath}:${binding.componentObjectId}`),
|
|
217
|
-
label: 'CodeElement',
|
|
218
|
-
properties: {
|
|
219
|
-
name: `${symbol}@${binding.componentObjectId}`,
|
|
220
|
-
filePath: binding.resourcePath,
|
|
221
|
-
startLine: binding.evidence.line,
|
|
222
|
-
endLine: binding.evidence.line,
|
|
223
|
-
description: JSON.stringify(payload),
|
|
224
|
-
},
|
|
225
|
-
};
|
|
270
|
+
return resolveUnityConfig().config.payloadMode ?? 'compact';
|
|
226
271
|
}
|
|
227
272
|
function buildUnityPayload(binding, mode) {
|
|
228
273
|
const payload = {
|
|
@@ -285,7 +330,7 @@ function collectSerializableTypeTargetsForBinding(hostSymbol, binding, scanConte
|
|
|
285
330
|
edgeCount: 0,
|
|
286
331
|
missCount: 0,
|
|
287
332
|
symbols: new Set(),
|
|
288
|
-
|
|
333
|
+
links: [],
|
|
289
334
|
};
|
|
290
335
|
if (!scanContext)
|
|
291
336
|
return stats;
|
|
@@ -310,7 +355,12 @@ function collectSerializableTypeTargetsForBinding(hostSymbol, binding, scanConte
|
|
|
310
355
|
stats.missCount += 1;
|
|
311
356
|
continue;
|
|
312
357
|
}
|
|
313
|
-
stats.
|
|
358
|
+
stats.links.push({
|
|
359
|
+
targetClassId: serializableNode.id,
|
|
360
|
+
fieldName,
|
|
361
|
+
declaredType,
|
|
362
|
+
sourceLayer,
|
|
363
|
+
});
|
|
314
364
|
stats.edgeCount += 1;
|
|
315
365
|
stats.symbols.add(declaredType);
|
|
316
366
|
}
|
|
@@ -330,6 +380,21 @@ function collectBindingFieldSources(binding) {
|
|
|
330
380
|
}
|
|
331
381
|
return fieldSources;
|
|
332
382
|
}
|
|
383
|
+
function ensureResourceFileNode(graph, resourcePath) {
|
|
384
|
+
const normalizedPath = normalizePath(resourcePath);
|
|
385
|
+
const fileId = generateId('File', normalizedPath);
|
|
386
|
+
if (!graph.getNode(fileId)) {
|
|
387
|
+
graph.addNode({
|
|
388
|
+
id: fileId,
|
|
389
|
+
label: 'File',
|
|
390
|
+
properties: {
|
|
391
|
+
name: normalizedPath.split('/').pop() || normalizedPath,
|
|
392
|
+
filePath: normalizedPath,
|
|
393
|
+
},
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
return fileId;
|
|
397
|
+
}
|
|
333
398
|
function collectResourceSummaryRows(bindings) {
|
|
334
399
|
const summaryByPath = new Map();
|
|
335
400
|
for (const binding of bindings) {
|
|
@@ -32,7 +32,7 @@ const listRelativeFixtureFiles = async (root) => {
|
|
|
32
32
|
}
|
|
33
33
|
return out;
|
|
34
34
|
};
|
|
35
|
-
test('processUnityResources
|
|
35
|
+
test('processUnityResources emits schema-compatible component-instance edges and materialized resource file nodes', async () => {
|
|
36
36
|
const graph = createKnowledgeGraph();
|
|
37
37
|
for (const symbol of symbols) {
|
|
38
38
|
const filePath = `Assets/Scripts/${symbol}.cs`;
|
|
@@ -65,12 +65,14 @@ test('processUnityResources does not emit UNITY_COMPONENT_IN or synthetic resour
|
|
|
65
65
|
}
|
|
66
66
|
const result = await processUnityResources(graph, { repoPath: fixtureRoot });
|
|
67
67
|
const unityFileRelations = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_COMPONENT_IN');
|
|
68
|
+
const unityComponentInstanceRelations = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_COMPONENT_INSTANCE');
|
|
68
69
|
const unitySummaryRelations = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_RESOURCE_SUMMARY');
|
|
69
70
|
const syntheticResourceFiles = [...graph.iterNodes()].filter((node) => node.label === 'File' && /\.(prefab|unity|asset)$/.test(String(node.properties.filePath)));
|
|
70
71
|
const componentNodes = [...graph.iterNodes()].filter((node) => node.label === 'CodeElement');
|
|
71
72
|
assert.equal(result.bindingCount > 0, true);
|
|
72
73
|
assert.equal(unityFileRelations.length, 0);
|
|
73
|
-
assert.
|
|
74
|
+
assert.ok(unityComponentInstanceRelations.length > 0);
|
|
75
|
+
assert.ok(syntheticResourceFiles.length > 0);
|
|
74
76
|
assert.ok(unitySummaryRelations.length > 0);
|
|
75
77
|
assert.equal(componentNodes.length, 0);
|
|
76
78
|
assert.ok(result.bindingCount >= symbols.length);
|
|
@@ -452,6 +454,69 @@ test('processUnityResources writes UNITY_RESOURCE_SUMMARY for serializable class
|
|
|
452
454
|
const summaryRelations = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_RESOURCE_SUMMARY');
|
|
453
455
|
const serializableSummary = summaryRelations.filter((rel) => rel.sourceId === serializableClassId);
|
|
454
456
|
assert.equal(serializableSummary.length, 1);
|
|
457
|
+
const serializedTypeRelations = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_SERIALIZED_TYPE_IN');
|
|
458
|
+
assert.equal(serializedTypeRelations.length, 1);
|
|
459
|
+
const reason = JSON.parse(String(serializedTypeRelations[0]?.reason || '{}'));
|
|
460
|
+
assert.equal(reason.fieldName, 'assetRef');
|
|
461
|
+
assert.equal(reason.declaredType, 'AssetRef');
|
|
462
|
+
assert.equal(reason.hostSymbol, 'HostClass');
|
|
463
|
+
});
|
|
464
|
+
test('processUnityResources writes asset-guid and graph-node reference edges from resolved references', async () => {
|
|
465
|
+
const graph = createKnowledgeGraph();
|
|
466
|
+
const hostPath = 'Assets/Scripts/WeaponConfig.cs';
|
|
467
|
+
const classId = generateId('Class', `${hostPath}:WeaponConfig`);
|
|
468
|
+
graph.addNode({
|
|
469
|
+
id: classId,
|
|
470
|
+
label: 'Class',
|
|
471
|
+
properties: { name: 'WeaponConfig', filePath: hostPath },
|
|
472
|
+
});
|
|
473
|
+
const fakeScanContext = {
|
|
474
|
+
symbolToScriptPath: new Map([['WeaponConfig', hostPath]]),
|
|
475
|
+
scriptPathToGuid: new Map([[hostPath, '11111111111111111111111111111111']]),
|
|
476
|
+
guidToResourceHits: new Map([
|
|
477
|
+
['11111111111111111111111111111111', [{ resourcePath: 'Assets/Data/WeaponConfig.asset', resourceType: 'asset', line: 3, lineText: 'guid: 1111' }]],
|
|
478
|
+
]),
|
|
479
|
+
resourceDocCache: new Map(),
|
|
480
|
+
};
|
|
481
|
+
await processUnityResources(graph, { repoPath: fixtureRoot }, {
|
|
482
|
+
buildScanContext: async () => fakeScanContext,
|
|
483
|
+
resolveBindings: async () => ({
|
|
484
|
+
symbol: 'WeaponConfig',
|
|
485
|
+
scriptPath: hostPath,
|
|
486
|
+
scriptGuid: '11111111111111111111111111111111',
|
|
487
|
+
resourceBindings: [
|
|
488
|
+
{
|
|
489
|
+
resourcePath: 'Assets/Data/WeaponConfig.asset',
|
|
490
|
+
resourceType: 'asset',
|
|
491
|
+
bindingKind: 'direct',
|
|
492
|
+
componentObjectId: '11400000',
|
|
493
|
+
evidence: { line: 3, lineText: 'guid: 1111' },
|
|
494
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
495
|
+
resolvedReferences: [
|
|
496
|
+
{
|
|
497
|
+
fieldName: 'gungraph',
|
|
498
|
+
sourceLayer: 'asset',
|
|
499
|
+
fileId: '11400000',
|
|
500
|
+
guid: 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa',
|
|
501
|
+
fromList: false,
|
|
502
|
+
resolution: 'external-asset',
|
|
503
|
+
target: { assetPath: 'Assets/Graphs/Weapon.asset' },
|
|
504
|
+
},
|
|
505
|
+
],
|
|
506
|
+
},
|
|
507
|
+
],
|
|
508
|
+
serializedFields: { scalarFields: [], referenceFields: [] },
|
|
509
|
+
unityDiagnostics: [],
|
|
510
|
+
}),
|
|
511
|
+
});
|
|
512
|
+
const graphNodeRefs = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_GRAPH_NODE_SCRIPT_REF');
|
|
513
|
+
const guidRefs = [...graph.iterRelationships()].filter((rel) => rel.type === 'UNITY_ASSET_GUID_REF');
|
|
514
|
+
assert.equal(graphNodeRefs.length, 1);
|
|
515
|
+
assert.equal(guidRefs.length, 1);
|
|
516
|
+
const guidReason = JSON.parse(String(guidRefs[0]?.reason || '{}'));
|
|
517
|
+
assert.equal(guidReason.guid, 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa');
|
|
518
|
+
assert.equal(guidReason.targetResourcePath, 'Assets/Graphs/Weapon.asset');
|
|
519
|
+
assert.equal(guidReason.fieldName, 'gungraph');
|
|
455
520
|
});
|
|
456
521
|
test('processUnityResources writes compact UNITY_RESOURCE_SUMMARY reason by default', async () => {
|
|
457
522
|
const graph = createKnowledgeGraph();
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { KnowledgeGraph } from '../graph/types.js';
|
|
2
|
+
import type { RuntimeClaimRule } from '../../mcp/local/runtime-claim-rule-registry.js';
|
|
3
|
+
import type { UnityConfig } from '../config/unity-config.js';
|
|
4
|
+
export interface UnityRuntimeBindingResult {
|
|
5
|
+
edgesInjected: number;
|
|
6
|
+
ruleResults: Array<{
|
|
7
|
+
ruleId: string;
|
|
8
|
+
edgesInjected: number;
|
|
9
|
+
}>;
|
|
10
|
+
}
|
|
11
|
+
export declare function applyUnityRuntimeBindingRules(graph: KnowledgeGraph, rules: RuntimeClaimRule[], _config: UnityConfig): UnityRuntimeBindingResult;
|