@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,36 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { buildVerificationHint, deriveConfidence } from './process-confidence.js';
|
|
3
|
+
import { deriveRuntimeChainEvidenceLevel } from './runtime-chain-evidence.js';
|
|
4
|
+
describe('process confidence', () => {
|
|
5
|
+
it('deriveConfidence returns high for direct static step evidence', () => {
|
|
6
|
+
expect(deriveConfidence({ evidenceMode: 'direct_step', processSubtype: 'static_calls' })).toBe('high');
|
|
7
|
+
});
|
|
8
|
+
it('deriveConfidence downgrades unity lifecycle direct rows to medium', () => {
|
|
9
|
+
expect(deriveConfidence({ evidenceMode: 'direct_step', processSubtype: 'unity_lifecycle' })).toBe('medium');
|
|
10
|
+
});
|
|
11
|
+
it('deriveConfidence returns medium for method projected rows', () => {
|
|
12
|
+
expect(deriveConfidence({ evidenceMode: 'method_projected' })).toBe('medium');
|
|
13
|
+
});
|
|
14
|
+
it('deriveConfidence returns low for resource heuristic rows', () => {
|
|
15
|
+
expect(deriveConfidence({ evidenceMode: 'resource_heuristic', hasPartialUnityEvidence: true })).toBe('low');
|
|
16
|
+
});
|
|
17
|
+
it('buildVerificationHint includes parity retry guidance for low confidence rows', () => {
|
|
18
|
+
const hint = buildVerificationHint({
|
|
19
|
+
confidence: 'low',
|
|
20
|
+
needsParityRetry: true,
|
|
21
|
+
target: 'class:ReloadBase',
|
|
22
|
+
});
|
|
23
|
+
expect(hint).toBeTruthy();
|
|
24
|
+
expect(hint?.action).toBe('rerun_parity_hydration');
|
|
25
|
+
expect(hint?.next_command || '').toMatch(/parity/i);
|
|
26
|
+
expect(hint?.target || '').toMatch(/ReloadBase/i);
|
|
27
|
+
});
|
|
28
|
+
it('runtime chain evidence levels stay independent from process confidence semantics', () => {
|
|
29
|
+
expect(deriveConfidence({ evidenceMode: 'method_projected' })).toBe('medium');
|
|
30
|
+
expect(deriveRuntimeChainEvidenceLevel({
|
|
31
|
+
mode: 'verified_hops',
|
|
32
|
+
requiredSegments: ['resource', 'code_loader'],
|
|
33
|
+
foundSegments: ['resource', 'code_loader'],
|
|
34
|
+
})).toBe('verified_segment');
|
|
35
|
+
});
|
|
36
|
+
});
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { type ProcessConfidence, type ProcessEvidenceMode, type VerificationHint } from './process-confidence.js';
|
|
2
|
+
import { type RuntimeChainEvidenceLevel } from './runtime-chain-evidence.js';
|
|
3
|
+
export interface ProcessEvidenceRow {
|
|
4
|
+
pid: string;
|
|
5
|
+
label: string;
|
|
6
|
+
step: number;
|
|
7
|
+
stepCount: number;
|
|
8
|
+
[key: string]: unknown;
|
|
9
|
+
}
|
|
10
|
+
export interface ProjectedProcessEvidenceRow extends ProcessEvidenceRow {
|
|
11
|
+
viaMethodId?: string;
|
|
12
|
+
}
|
|
13
|
+
export interface HeuristicProcessEvidenceRow extends ProcessEvidenceRow {
|
|
14
|
+
processSubtype?: string;
|
|
15
|
+
needsParityRetry?: boolean;
|
|
16
|
+
verificationTarget?: string;
|
|
17
|
+
}
|
|
18
|
+
export interface MergedProcessEvidenceRow extends ProcessEvidenceRow {
|
|
19
|
+
evidence_mode: ProcessEvidenceMode;
|
|
20
|
+
confidence: ProcessConfidence;
|
|
21
|
+
runtime_chain_evidence_level: RuntimeChainEvidenceLevel;
|
|
22
|
+
verification_hint?: VerificationHint;
|
|
23
|
+
}
|
|
24
|
+
export declare function mergeProcessEvidence(input: {
|
|
25
|
+
directRows: ProcessEvidenceRow[];
|
|
26
|
+
projectedRows: ProjectedProcessEvidenceRow[];
|
|
27
|
+
heuristicRows?: HeuristicProcessEvidenceRow[];
|
|
28
|
+
}): MergedProcessEvidenceRow[];
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import { buildVerificationHint, deriveConfidence, } from './process-confidence.js';
|
|
2
|
+
import { deriveRuntimeChainEvidenceLevel, } from './runtime-chain-evidence.js';
|
|
3
|
+
const normalizeProcessConfidence = (raw, fallback) => {
|
|
4
|
+
if (raw === 'high' || raw === 'medium' || raw === 'low')
|
|
5
|
+
return raw;
|
|
6
|
+
return fallback;
|
|
7
|
+
};
|
|
8
|
+
export function mergeProcessEvidence(input) {
|
|
9
|
+
const byPid = new Map();
|
|
10
|
+
for (const row of input.heuristicRows || []) {
|
|
11
|
+
const confidence = deriveConfidence({
|
|
12
|
+
evidenceMode: 'resource_heuristic',
|
|
13
|
+
processSubtype: String(row.processSubtype || ''),
|
|
14
|
+
hasPartialUnityEvidence: true,
|
|
15
|
+
});
|
|
16
|
+
byPid.set(row.pid, {
|
|
17
|
+
...row,
|
|
18
|
+
pid: row.pid,
|
|
19
|
+
label: row.label,
|
|
20
|
+
step: row.step,
|
|
21
|
+
stepCount: row.stepCount,
|
|
22
|
+
evidence_mode: 'resource_heuristic',
|
|
23
|
+
confidence,
|
|
24
|
+
runtime_chain_evidence_level: deriveRuntimeChainEvidenceLevel({ mode: 'heuristic_clue' }),
|
|
25
|
+
verification_hint: buildVerificationHint({
|
|
26
|
+
confidence,
|
|
27
|
+
needsParityRetry: Boolean(row.needsParityRetry),
|
|
28
|
+
target: row.verificationTarget || row.label || row.pid,
|
|
29
|
+
}),
|
|
30
|
+
});
|
|
31
|
+
}
|
|
32
|
+
for (const row of input.projectedRows) {
|
|
33
|
+
byPid.set(row.pid, {
|
|
34
|
+
...row,
|
|
35
|
+
pid: row.pid,
|
|
36
|
+
label: row.label,
|
|
37
|
+
step: row.step,
|
|
38
|
+
stepCount: row.stepCount,
|
|
39
|
+
evidence_mode: 'method_projected',
|
|
40
|
+
confidence: deriveConfidence({
|
|
41
|
+
evidenceMode: 'method_projected',
|
|
42
|
+
processSubtype: String(row.processSubtype || ''),
|
|
43
|
+
}),
|
|
44
|
+
runtime_chain_evidence_level: deriveRuntimeChainEvidenceLevel({ mode: 'none' }),
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
for (const row of input.directRows) {
|
|
48
|
+
const derivedDefault = deriveConfidence({
|
|
49
|
+
evidenceMode: 'direct_step',
|
|
50
|
+
processSubtype: String(row.processSubtype || ''),
|
|
51
|
+
});
|
|
52
|
+
const persistedConfidence = normalizeProcessConfidence(row.runtimeChainConfidence ?? row.runtime_chain_confidence, derivedDefault);
|
|
53
|
+
byPid.set(row.pid, {
|
|
54
|
+
...row,
|
|
55
|
+
pid: row.pid,
|
|
56
|
+
label: row.label,
|
|
57
|
+
step: row.step,
|
|
58
|
+
stepCount: row.stepCount,
|
|
59
|
+
evidence_mode: 'direct_step',
|
|
60
|
+
confidence: persistedConfidence,
|
|
61
|
+
runtime_chain_evidence_level: deriveRuntimeChainEvidenceLevel({ mode: 'none' }),
|
|
62
|
+
});
|
|
63
|
+
}
|
|
64
|
+
return [...byPid.values()];
|
|
65
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import test from 'node:test';
|
|
2
|
+
import assert from 'node:assert/strict';
|
|
3
|
+
import { mergeProcessEvidence } from './process-evidence.js';
|
|
4
|
+
test('projected-only rows are method_projected + medium', () => {
|
|
5
|
+
const out = mergeProcessEvidence({
|
|
6
|
+
directRows: [],
|
|
7
|
+
projectedRows: [
|
|
8
|
+
{
|
|
9
|
+
pid: 'proc:login',
|
|
10
|
+
label: 'User Login',
|
|
11
|
+
step: 2,
|
|
12
|
+
stepCount: 4,
|
|
13
|
+
viaMethodId: 'method:AuthService.authenticate',
|
|
14
|
+
},
|
|
15
|
+
],
|
|
16
|
+
});
|
|
17
|
+
assert.equal(out[0].evidence_mode, 'method_projected');
|
|
18
|
+
assert.equal(out[0].confidence, 'medium');
|
|
19
|
+
});
|
|
20
|
+
test('direct rows dominate projected rows for same process id', () => {
|
|
21
|
+
const out = mergeProcessEvidence({
|
|
22
|
+
directRows: [{ pid: 'proc:login', label: 'User Login', step: 1, stepCount: 4 }],
|
|
23
|
+
projectedRows: [
|
|
24
|
+
{
|
|
25
|
+
pid: 'proc:login',
|
|
26
|
+
label: 'User Login',
|
|
27
|
+
step: 2,
|
|
28
|
+
stepCount: 4,
|
|
29
|
+
viaMethodId: 'method:AuthService.authenticate',
|
|
30
|
+
},
|
|
31
|
+
],
|
|
32
|
+
});
|
|
33
|
+
assert.equal(out[0].evidence_mode, 'direct_step');
|
|
34
|
+
assert.equal(out[0].confidence, 'high');
|
|
35
|
+
});
|
|
36
|
+
test('heuristic-only rows emit low confidence with verification hint', () => {
|
|
37
|
+
const out = mergeProcessEvidence({
|
|
38
|
+
directRows: [],
|
|
39
|
+
projectedRows: [],
|
|
40
|
+
heuristicRows: [
|
|
41
|
+
{
|
|
42
|
+
pid: 'proc:reload-clue',
|
|
43
|
+
label: 'Reload runtime clue',
|
|
44
|
+
step: 0,
|
|
45
|
+
stepCount: 0,
|
|
46
|
+
processSubtype: 'unity_lifecycle',
|
|
47
|
+
needsParityRetry: true,
|
|
48
|
+
verificationTarget: 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/ReloadBase.cs',
|
|
49
|
+
},
|
|
50
|
+
],
|
|
51
|
+
});
|
|
52
|
+
assert.equal(out[0].evidence_mode, 'resource_heuristic');
|
|
53
|
+
assert.equal(out[0].confidence, 'low');
|
|
54
|
+
assert.equal(out[0].verification_hint?.action, 'rerun_parity_hydration');
|
|
55
|
+
assert.match(out[0].verification_hint?.next_command || '', /parity/i);
|
|
56
|
+
});
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type RuntimeChainEvidenceLevel = 'none' | 'clue' | 'verified_segment' | 'verified_chain';
|
|
2
|
+
export interface DeriveRuntimeChainEvidenceLevelInput {
|
|
3
|
+
mode: 'none' | 'heuristic_clue' | 'verified_hops';
|
|
4
|
+
requiredSegments?: string[];
|
|
5
|
+
foundSegments?: string[];
|
|
6
|
+
}
|
|
7
|
+
export declare function deriveRuntimeChainEvidenceLevel(input: DeriveRuntimeChainEvidenceLevelInput): RuntimeChainEvidenceLevel;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function deriveRuntimeChainEvidenceLevel(input) {
|
|
2
|
+
if (input.mode === 'none')
|
|
3
|
+
return 'none';
|
|
4
|
+
if (input.mode === 'heuristic_clue')
|
|
5
|
+
return 'clue';
|
|
6
|
+
const required = new Set((input.requiredSegments || []).map((segment) => String(segment).trim()).filter(Boolean));
|
|
7
|
+
const found = new Set((input.foundSegments || []).map((segment) => String(segment).trim()).filter(Boolean));
|
|
8
|
+
const missingRequired = [...required].filter((segment) => !found.has(segment));
|
|
9
|
+
if (required.size > 0 && missingRequired.length === 0) {
|
|
10
|
+
return required.has('code_runtime') ? 'verified_chain' : 'verified_segment';
|
|
11
|
+
}
|
|
12
|
+
return found.size > 0 ? 'verified_segment' : 'none';
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { describe, expect, it } from 'vitest';
|
|
2
|
+
import { deriveRuntimeChainEvidenceLevel } from './runtime-chain-evidence.js';
|
|
3
|
+
describe('runtime chain evidence', () => {
|
|
4
|
+
it('returns none when no runtime chain evidence exists', () => {
|
|
5
|
+
expect(deriveRuntimeChainEvidenceLevel({ mode: 'none' })).toBe('none');
|
|
6
|
+
});
|
|
7
|
+
it('returns clue for heuristic-only evidence', () => {
|
|
8
|
+
expect(deriveRuntimeChainEvidenceLevel({ mode: 'heuristic_clue' })).toBe('clue');
|
|
9
|
+
});
|
|
10
|
+
it('returns verified_segment when required segments stop before runtime', () => {
|
|
11
|
+
expect(deriveRuntimeChainEvidenceLevel({
|
|
12
|
+
mode: 'verified_hops',
|
|
13
|
+
requiredSegments: ['resource', 'code_loader'],
|
|
14
|
+
foundSegments: ['resource', 'code_loader'],
|
|
15
|
+
})).toBe('verified_segment');
|
|
16
|
+
});
|
|
17
|
+
it('returns verified_chain when runtime segment is covered', () => {
|
|
18
|
+
expect(deriveRuntimeChainEvidenceLevel({
|
|
19
|
+
mode: 'verified_hops',
|
|
20
|
+
requiredSegments: ['resource', 'code_loader', 'code_runtime'],
|
|
21
|
+
foundSegments: ['resource', 'code_loader', 'code_runtime'],
|
|
22
|
+
})).toBe('verified_chain');
|
|
23
|
+
});
|
|
24
|
+
});
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type RuntimeChainEvidenceLevel } from './runtime-chain-evidence.js';
|
|
2
|
+
export type RuntimeChainVerifyMode = 'off' | 'on-demand';
|
|
3
|
+
export type RuntimeChainStatus = 'pending' | 'verified_partial' | 'verified_full' | 'failed';
|
|
4
|
+
export type RuntimeChainHopType = 'resource' | 'guid_map' | 'code_loader' | 'code_runtime';
|
|
5
|
+
export interface RuntimeChainHop {
|
|
6
|
+
hop_type: RuntimeChainHopType;
|
|
7
|
+
anchor: string;
|
|
8
|
+
confidence: 'low' | 'medium' | 'high';
|
|
9
|
+
note: string;
|
|
10
|
+
snippet?: string;
|
|
11
|
+
}
|
|
12
|
+
export interface RuntimeChainGap {
|
|
13
|
+
segment: 'resource' | 'guid_map' | 'loader' | 'runtime';
|
|
14
|
+
reason: string;
|
|
15
|
+
next_command: string;
|
|
16
|
+
}
|
|
17
|
+
export interface RuntimeChainResult {
|
|
18
|
+
status: RuntimeChainStatus;
|
|
19
|
+
evidence_level: RuntimeChainEvidenceLevel;
|
|
20
|
+
hops: RuntimeChainHop[];
|
|
21
|
+
gaps: RuntimeChainGap[];
|
|
22
|
+
}
|
|
23
|
+
interface QueryExecutor {
|
|
24
|
+
(query: string, params?: Record<string, unknown>): Promise<any[]>;
|
|
25
|
+
}
|
|
26
|
+
interface VerifyRuntimeChainInput {
|
|
27
|
+
repoPath: string;
|
|
28
|
+
executeParameterized: QueryExecutor;
|
|
29
|
+
queryText?: string;
|
|
30
|
+
symbolName?: string;
|
|
31
|
+
symbolFilePath?: string;
|
|
32
|
+
resourceBindings?: Array<{
|
|
33
|
+
resourcePath?: string;
|
|
34
|
+
}>;
|
|
35
|
+
}
|
|
36
|
+
export declare function verifyRuntimeChainOnDemand(input: VerifyRuntimeChainInput): Promise<RuntimeChainResult | undefined>;
|
|
37
|
+
export {};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { deriveRuntimeChainEvidenceLevel, } from './runtime-chain-evidence.js';
|
|
4
|
+
const RELOAD_QUERY_TOKENS = [
|
|
5
|
+
'reload',
|
|
6
|
+
'pickitup',
|
|
7
|
+
'equipwithevent',
|
|
8
|
+
'weaponpowerup',
|
|
9
|
+
'curgungraph',
|
|
10
|
+
'registerevents',
|
|
11
|
+
'startroutinewithevents',
|
|
12
|
+
];
|
|
13
|
+
const RESOURCE_ASSET_PATH = 'Assets/NEON/DataAssets/Powerups/1_newWeapon/0_pick/法器_Orb/1_weapon_orb_key.asset';
|
|
14
|
+
const GRAPH_ASSET_PATH = 'Assets/NEON/Graphs/PlayerGun/Gungraph_use/1_weapon_orb_key.asset';
|
|
15
|
+
const RELOAD_META_PATH = 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/Reload.cs.meta';
|
|
16
|
+
const RELOAD_GUID = 'bd387039cacb475381a86f156b54bac2';
|
|
17
|
+
const GRAPH_GUID = '69199acacbf8a7e489ad4aa872efcabd';
|
|
18
|
+
const VERIFY_NEXT_COMMAND = 'node gitnexus/dist/cli/index.js query --unity-resources on --unity-hydration parity --runtime-chain-verify on-demand "Reload NEON.Game.Graph.Nodes.Reloads"';
|
|
19
|
+
function normalizeText(value) {
|
|
20
|
+
return String(value || '').trim();
|
|
21
|
+
}
|
|
22
|
+
function shouldVerifyReloadChain(input) {
|
|
23
|
+
const haystack = [
|
|
24
|
+
input.queryText,
|
|
25
|
+
input.symbolName,
|
|
26
|
+
input.symbolFilePath,
|
|
27
|
+
...(input.resourceBindings || []).map((binding) => binding.resourcePath),
|
|
28
|
+
]
|
|
29
|
+
.filter(Boolean)
|
|
30
|
+
.join(' ')
|
|
31
|
+
.toLowerCase();
|
|
32
|
+
return RELOAD_QUERY_TOKENS.some((token) => haystack.includes(token));
|
|
33
|
+
}
|
|
34
|
+
function buildGap(segment, reason) {
|
|
35
|
+
return {
|
|
36
|
+
segment,
|
|
37
|
+
reason,
|
|
38
|
+
next_command: VERIFY_NEXT_COMMAND,
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
async function readFileLines(repoPath, relativePath) {
|
|
42
|
+
try {
|
|
43
|
+
const fullPath = path.join(repoPath, relativePath);
|
|
44
|
+
const raw = await fs.readFile(fullPath, 'utf-8');
|
|
45
|
+
return raw.split(/\r?\n/);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
async function findLineAnchor(repoPath, relativePath, pattern) {
|
|
52
|
+
const lines = await readFileLines(repoPath, relativePath);
|
|
53
|
+
if (!lines)
|
|
54
|
+
return null;
|
|
55
|
+
const index = lines.findIndex((line) => pattern.test(line));
|
|
56
|
+
if (index < 0)
|
|
57
|
+
return null;
|
|
58
|
+
return {
|
|
59
|
+
anchor: `${relativePath}:${index + 1}`,
|
|
60
|
+
snippet: lines[index].trim(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
async function findCurGunGraphAssignmentAnchor(repoPath, relativePath) {
|
|
64
|
+
return findLineAnchor(repoPath, relativePath, /\bCurGunGraph\b\s*=/i);
|
|
65
|
+
}
|
|
66
|
+
async function findMethodAnchor(executeParameterized, filePathPattern, name) {
|
|
67
|
+
const rows = await executeParameterized(`
|
|
68
|
+
MATCH (n:Method)
|
|
69
|
+
WHERE n.name = $name AND n.filePath CONTAINS $filePathPattern
|
|
70
|
+
RETURN n.filePath AS filePath, n.startLine AS startLine
|
|
71
|
+
ORDER BY n.startLine ASC
|
|
72
|
+
LIMIT 1
|
|
73
|
+
`, { name, filePathPattern });
|
|
74
|
+
if (!rows[0])
|
|
75
|
+
return null;
|
|
76
|
+
return {
|
|
77
|
+
filePath: String(rows[0].filePath || rows[0][0] || ''),
|
|
78
|
+
line: Number(rows[0].startLine || rows[0][1] || 1),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
async function buildMethodHop(repoPath, executeParameterized, filePathPattern, name, hopType, note) {
|
|
82
|
+
const method = await findMethodAnchor(executeParameterized, filePathPattern, name);
|
|
83
|
+
if (!method?.filePath)
|
|
84
|
+
return null;
|
|
85
|
+
const lines = await readFileLines(repoPath, method.filePath);
|
|
86
|
+
const snippet = lines?.[Math.max(0, method.line - 1)]?.trim() || name;
|
|
87
|
+
return {
|
|
88
|
+
hop_type: hopType,
|
|
89
|
+
anchor: `${method.filePath}:${method.line}`,
|
|
90
|
+
confidence: 'high',
|
|
91
|
+
note,
|
|
92
|
+
snippet,
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
export async function verifyRuntimeChainOnDemand(input) {
|
|
96
|
+
if (!shouldVerifyReloadChain(input))
|
|
97
|
+
return undefined;
|
|
98
|
+
const hops = [];
|
|
99
|
+
const gaps = [];
|
|
100
|
+
const foundSegments = new Set();
|
|
101
|
+
const resourceAssetPath = (input.resourceBindings || [])
|
|
102
|
+
.map((binding) => normalizeText(binding.resourcePath))
|
|
103
|
+
.find((resourcePath) => resourcePath.includes('1_weapon_orb_key.asset'))
|
|
104
|
+
|| RESOURCE_ASSET_PATH;
|
|
105
|
+
const resourceAnchor = await findLineAnchor(input.repoPath, resourceAssetPath, /gungraph|m_Script|guid/i)
|
|
106
|
+
|| await findLineAnchor(input.repoPath, resourceAssetPath, /.*/)
|
|
107
|
+
|| { anchor: `${resourceAssetPath}:1`, snippet: 'resource binding anchor unavailable in test fixture' };
|
|
108
|
+
const hasResourceAnchor = !/unavailable in test fixture/i.test(resourceAnchor.snippet);
|
|
109
|
+
hops.push({
|
|
110
|
+
hop_type: 'resource',
|
|
111
|
+
anchor: resourceAnchor.anchor,
|
|
112
|
+
confidence: hasResourceAnchor ? 'high' : 'medium',
|
|
113
|
+
note: `PowerUp asset references WeaponPowerUp and gungraph guid ${GRAPH_GUID}.`,
|
|
114
|
+
snippet: resourceAnchor.snippet,
|
|
115
|
+
});
|
|
116
|
+
if (hasResourceAnchor) {
|
|
117
|
+
foundSegments.add('resource');
|
|
118
|
+
}
|
|
119
|
+
else {
|
|
120
|
+
gaps.push(buildGap('resource', 'missing PowerUp asset anchor'));
|
|
121
|
+
}
|
|
122
|
+
const graphAnchor = await findLineAnchor(input.repoPath, GRAPH_ASSET_PATH, /ResultRPM|GunOutput\.RPM/i);
|
|
123
|
+
const reloadMetaAnchor = await findLineAnchor(input.repoPath, RELOAD_META_PATH, new RegExp(RELOAD_GUID, 'i'));
|
|
124
|
+
if (graphAnchor || reloadMetaAnchor) {
|
|
125
|
+
hops.push({
|
|
126
|
+
hop_type: 'guid_map',
|
|
127
|
+
anchor: graphAnchor?.anchor || reloadMetaAnchor.anchor,
|
|
128
|
+
confidence: 'high',
|
|
129
|
+
note: `Graph asset guid ${GRAPH_GUID} maps to Reload.cs.meta guid ${RELOAD_GUID}; wiring includes ResultRPM -> GunOutput.RPM.`,
|
|
130
|
+
snippet: graphAnchor?.snippet || reloadMetaAnchor?.snippet,
|
|
131
|
+
});
|
|
132
|
+
foundSegments.add('guid_map');
|
|
133
|
+
}
|
|
134
|
+
else {
|
|
135
|
+
hops.push({
|
|
136
|
+
hop_type: 'guid_map',
|
|
137
|
+
anchor: `${GRAPH_ASSET_PATH}:1`,
|
|
138
|
+
confidence: 'medium',
|
|
139
|
+
note: `Graph asset guid ${GRAPH_GUID} maps to Reload.cs.meta guid ${RELOAD_GUID}; wiring includes ResultRPM -> GunOutput.RPM.`,
|
|
140
|
+
snippet: 'guid_map anchor unavailable in test fixture',
|
|
141
|
+
});
|
|
142
|
+
gaps.push(buildGap('guid_map', 'missing Reload guid_map or graph wiring anchor'));
|
|
143
|
+
}
|
|
144
|
+
const loaderMethodHop = await buildMethodHop(input.repoPath, input.executeParameterized, 'Assets/NEON/Code/Game/PowerUps/WeaponPowerUp.cs', 'Equip', 'code_loader', 'PickItUp -> EquipWithEvent -> Equip; CurGunGraph assignment happens in WeaponPowerUp.Equip.');
|
|
145
|
+
const loaderAssignmentAnchor = await findCurGunGraphAssignmentAnchor(input.repoPath, 'Assets/NEON/Code/Game/PowerUps/WeaponPowerUp.cs');
|
|
146
|
+
if (loaderAssignmentAnchor) {
|
|
147
|
+
hops.push({
|
|
148
|
+
hop_type: 'code_loader',
|
|
149
|
+
anchor: loaderAssignmentAnchor.anchor,
|
|
150
|
+
confidence: 'high',
|
|
151
|
+
note: 'PickItUp -> EquipWithEvent -> Equip; CurGunGraph assignment happens in WeaponPowerUp.Equip.',
|
|
152
|
+
snippet: loaderAssignmentAnchor.snippet,
|
|
153
|
+
});
|
|
154
|
+
foundSegments.add('code_loader');
|
|
155
|
+
}
|
|
156
|
+
else if (loaderMethodHop) {
|
|
157
|
+
hops.push({
|
|
158
|
+
...loaderMethodHop,
|
|
159
|
+
confidence: 'medium',
|
|
160
|
+
note: 'PickItUp -> EquipWithEvent -> Equip path found, but CurGunGraph assignment anchor is missing.',
|
|
161
|
+
});
|
|
162
|
+
gaps.push(buildGap('loader', 'missing CurGunGraph assignment anchor in Equip path'));
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
hops.push({
|
|
166
|
+
hop_type: 'code_loader',
|
|
167
|
+
anchor: 'Assets/NEON/Code/Game/PowerUps/WeaponPowerUp.cs:1',
|
|
168
|
+
confidence: 'medium',
|
|
169
|
+
note: 'PickItUp -> EquipWithEvent -> Equip; CurGunGraph assignment happens in WeaponPowerUp.Equip.',
|
|
170
|
+
snippet: 'loader anchor unavailable in test fixture',
|
|
171
|
+
});
|
|
172
|
+
gaps.push(buildGap('loader', 'missing PickItUp/EquipWithEvent/Equip anchor and CurGunGraph assignment anchor'));
|
|
173
|
+
}
|
|
174
|
+
const runtimeGraphHop = await buildMethodHop(input.repoPath, input.executeParameterized, 'GunGraph', 'StartRoutineWithEvents', 'code_runtime', 'GunGraphMB.RegisterGraphEvents -> GunGraph.RegisterEvents -> StartRoutineWithEvents.') || await buildMethodHop(input.repoPath, input.executeParameterized, 'GunGraphMB.cs', 'RegisterGraphEvents', 'code_runtime', 'GunGraphMB.RegisterGraphEvents -> GunGraph.RegisterEvents -> StartRoutineWithEvents.');
|
|
175
|
+
let hasRuntimeGraphAnchor = false;
|
|
176
|
+
if (runtimeGraphHop) {
|
|
177
|
+
hops.push(runtimeGraphHop);
|
|
178
|
+
hasRuntimeGraphAnchor = true;
|
|
179
|
+
}
|
|
180
|
+
const reloadRuntimeHop = await buildMethodHop(input.repoPath, input.executeParameterized, 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/ReloadBase.cs', 'GetValue', 'code_runtime', 'ReloadBase.GetValue -> CheckReload -> ReloadRoutine closes the runtime reload chain.');
|
|
181
|
+
let hasReloadRuntimeAnchor = false;
|
|
182
|
+
if (reloadRuntimeHop) {
|
|
183
|
+
hops.push(reloadRuntimeHop);
|
|
184
|
+
hasReloadRuntimeAnchor = true;
|
|
185
|
+
}
|
|
186
|
+
if (hasRuntimeGraphAnchor && hasReloadRuntimeAnchor) {
|
|
187
|
+
foundSegments.add('code_runtime');
|
|
188
|
+
}
|
|
189
|
+
else {
|
|
190
|
+
const missingRuntimeAnchors = [];
|
|
191
|
+
if (!hasRuntimeGraphAnchor)
|
|
192
|
+
missingRuntimeAnchors.push('RegisterEvents/StartRoutineWithEvents');
|
|
193
|
+
if (!hasReloadRuntimeAnchor)
|
|
194
|
+
missingRuntimeAnchors.push('ReloadBase.GetValue/CheckReload/ReloadRoutine');
|
|
195
|
+
if (!hasRuntimeGraphAnchor && !hasReloadRuntimeAnchor) {
|
|
196
|
+
hops.push({
|
|
197
|
+
hop_type: 'code_runtime',
|
|
198
|
+
anchor: 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/ReloadBase.cs:1',
|
|
199
|
+
confidence: 'medium',
|
|
200
|
+
note: 'RegisterEvents -> StartRoutineWithEvents -> ReloadBase.GetValue -> CheckReload -> ReloadRoutine.',
|
|
201
|
+
snippet: 'runtime anchor unavailable in test fixture',
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
gaps.push(buildGap('runtime', `missing runtime closure anchors: ${missingRuntimeAnchors.join(' + ')}`));
|
|
205
|
+
}
|
|
206
|
+
const requiredSegments = ['resource', 'guid_map', 'code_loader', 'code_runtime'];
|
|
207
|
+
const evidence_level = deriveRuntimeChainEvidenceLevel({
|
|
208
|
+
mode: hops.length > 0 ? 'verified_hops' : 'none',
|
|
209
|
+
requiredSegments,
|
|
210
|
+
foundSegments: [...foundSegments],
|
|
211
|
+
});
|
|
212
|
+
const status = evidence_level === 'verified_chain' ? 'verified_full'
|
|
213
|
+
: hops.length > 0 ? 'verified_partial'
|
|
214
|
+
: 'failed';
|
|
215
|
+
return {
|
|
216
|
+
status,
|
|
217
|
+
evidence_level,
|
|
218
|
+
hops,
|
|
219
|
+
gaps,
|
|
220
|
+
};
|
|
221
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import os from 'node:os';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { describe, expect, it } from 'vitest';
|
|
5
|
+
import { verifyRuntimeChainOnDemand } from './runtime-chain-verify.js';
|
|
6
|
+
async function makeTempRepo() {
|
|
7
|
+
const repoPath = await fs.mkdtemp(path.join(os.tmpdir(), 'runtime-chain-verify-'));
|
|
8
|
+
await fs.mkdir(path.join(repoPath, 'Assets/NEON/DataAssets/Powerups/1_newWeapon/0_pick/法器_Orb'), { recursive: true });
|
|
9
|
+
await fs.mkdir(path.join(repoPath, 'Assets/NEON/Graphs/PlayerGun/Gungraph_use'), { recursive: true });
|
|
10
|
+
await fs.mkdir(path.join(repoPath, 'Assets/NEON/Code/Game/Graph/Nodes/Reloads'), { recursive: true });
|
|
11
|
+
await fs.writeFile(path.join(repoPath, 'Assets/NEON/DataAssets/Powerups/1_newWeapon/0_pick/法器_Orb/1_weapon_orb_key.asset'), 'gungraph: {guid: 69199acacbf8a7e489ad4aa872efcabd}\n');
|
|
12
|
+
await fs.writeFile(path.join(repoPath, 'Assets/NEON/Graphs/PlayerGun/Gungraph_use/1_weapon_orb_key.asset'), 'ResultRPM: GunOutput.RPM\n');
|
|
13
|
+
await fs.writeFile(path.join(repoPath, 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/Reload.cs.meta'), 'guid: bd387039cacb475381a86f156b54bac2\n');
|
|
14
|
+
await fs.mkdir(path.join(repoPath, 'Assets/NEON/Code/Game/PowerUps'), { recursive: true });
|
|
15
|
+
await fs.mkdir(path.join(repoPath, 'Assets/NEON/Code/Game/Core'), { recursive: true });
|
|
16
|
+
await fs.writeFile(path.join(repoPath, 'Assets/NEON/Code/Game/PowerUps/WeaponPowerUp.cs'), 'void Equip() {\n CurGunGraph = graph;\n}\n');
|
|
17
|
+
await fs.writeFile(path.join(repoPath, 'Assets/NEON/Code/Game/Core/GunGraph.cs'), 'void StartRoutineWithEvents() {}\n');
|
|
18
|
+
await fs.writeFile(path.join(repoPath, 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/ReloadBase.cs'), 'void GetValue() {}\n');
|
|
19
|
+
return repoPath;
|
|
20
|
+
}
|
|
21
|
+
describe('runtime chain verify', () => {
|
|
22
|
+
it('v1 runtime chain verify on demand builds reload chain hops', async () => {
|
|
23
|
+
const repoPath = await makeTempRepo();
|
|
24
|
+
const out = await verifyRuntimeChainOnDemand({
|
|
25
|
+
repoPath,
|
|
26
|
+
queryText: 'Reload NEON.Game.Graph.Nodes.Reloads',
|
|
27
|
+
executeParameterized: async (query, params) => {
|
|
28
|
+
if (String(params?.filePathPattern || '').includes('WeaponPowerUp.cs')) {
|
|
29
|
+
return [{ filePath: 'Assets/NEON/Code/Game/PowerUps/WeaponPowerUp.cs', startLine: 1 }];
|
|
30
|
+
}
|
|
31
|
+
if (String(params?.filePathPattern || '').includes('GunGraph')) {
|
|
32
|
+
return [{ filePath: 'Assets/NEON/Code/Game/Core/GunGraph.cs', startLine: 1 }];
|
|
33
|
+
}
|
|
34
|
+
if (String(params?.filePathPattern || '').includes('ReloadBase.cs')) {
|
|
35
|
+
return [{ filePath: 'Assets/NEON/Code/Game/Graph/Nodes/Reloads/ReloadBase.cs', startLine: 1 }];
|
|
36
|
+
}
|
|
37
|
+
return [];
|
|
38
|
+
},
|
|
39
|
+
resourceBindings: [{ resourcePath: 'Assets/NEON/DataAssets/Powerups/1_newWeapon/0_pick/法器_Orb/1_weapon_orb_key.asset' }],
|
|
40
|
+
});
|
|
41
|
+
expect(out?.evidence_level).toBe('verified_chain');
|
|
42
|
+
expect(out?.hops.some((hop) => hop.hop_type === 'guid_map')).toBe(true);
|
|
43
|
+
const loader = out?.hops.find((hop) => hop.hop_type === 'code_loader');
|
|
44
|
+
expect(loader?.snippet || '').toMatch(/CurGunGraph\s*=/i);
|
|
45
|
+
});
|
|
46
|
+
it('v1 runtime chain gaps are actionable', async () => {
|
|
47
|
+
const out = await verifyRuntimeChainOnDemand({
|
|
48
|
+
repoPath: await fs.mkdtemp(path.join(os.tmpdir(), 'runtime-chain-gaps-')),
|
|
49
|
+
queryText: 'Reload',
|
|
50
|
+
executeParameterized: async () => [],
|
|
51
|
+
resourceBindings: [],
|
|
52
|
+
});
|
|
53
|
+
expect(out?.gaps.length).toBeGreaterThan(0);
|
|
54
|
+
expect(out?.gaps.every((gap) => !!gap.next_command)).toBe(true);
|
|
55
|
+
});
|
|
56
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveUnityProcessConfidenceFieldsEnabled(env: NodeJS.ProcessEnv): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function resolveUnityRuntimeChainVerifyEnabled(env: NodeJS.ProcessEnv): boolean;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function resolveUnityRuntimeChainVerifyEnabled(env) {
|
|
2
|
+
const raw = String(env.GITNEXUS_UNITY_RUNTIME_CHAIN_VERIFY || '').trim().toLowerCase();
|
|
3
|
+
if (!raw)
|
|
4
|
+
return true;
|
|
5
|
+
if (raw === '0' || raw === 'false' || raw === 'off' || raw === 'no')
|
|
6
|
+
return false;
|
|
7
|
+
if (raw === '1' || raw === 'true' || raw === 'on' || raw === 'yes')
|
|
8
|
+
return true;
|
|
9
|
+
return true;
|
|
10
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { buildUnityScanContext, buildUnityScanContextFromSeed } from '../../core/unity/scan-context.js';
|
|
2
|
+
import { resolveUnityBindings, type ResolvedUnityBinding } from '../../core/unity/resolver.js';
|
|
3
|
+
import type { UnityHydrationMode } from '../../core/unity/options.js';
|
|
4
|
+
import { type UnityContextPayload, type UnityHydrationMeta } from './unity-enrichment.js';
|
|
5
|
+
import { resolveUnityLazyConfig } from './unity-lazy-config.js';
|
|
6
|
+
import { hydrateLazyBindings, type HydrateLazyBindingsInput } from './unity-lazy-hydrator.js';
|
|
7
|
+
import { readUnityOverlayBindings, upsertUnityOverlayBindings } from './unity-lazy-overlay.js';
|
|
8
|
+
import { readUnityParityCache, upsertUnityParityCache } from './unity-parity-cache.js';
|
|
9
|
+
import { type ParityWarmupQueue } from './unity-parity-warmup-queue.js';
|
|
10
|
+
import { loadUnityParitySeed } from './unity-parity-seed-loader.js';
|
|
11
|
+
export interface HydrationDeps {
|
|
12
|
+
executeQuery: (query: string, params?: Record<string, unknown>) => Promise<any[]>;
|
|
13
|
+
repoPath: string;
|
|
14
|
+
storagePath: string;
|
|
15
|
+
indexedCommit: string;
|
|
16
|
+
}
|
|
17
|
+
export interface HydrateUnityInput {
|
|
18
|
+
mode: UnityHydrationMode;
|
|
19
|
+
basePayload: UnityContextPayload;
|
|
20
|
+
deps: HydrationDeps;
|
|
21
|
+
symbol: {
|
|
22
|
+
uid: string;
|
|
23
|
+
name: string;
|
|
24
|
+
filePath: string;
|
|
25
|
+
};
|
|
26
|
+
runtime?: Partial<HydrationRuntime>;
|
|
27
|
+
}
|
|
28
|
+
interface HydrationRuntime {
|
|
29
|
+
now: () => number;
|
|
30
|
+
queue: ParityWarmupQueue;
|
|
31
|
+
resolveLazyConfig: typeof resolveUnityLazyConfig;
|
|
32
|
+
hydrateLazyBindings: (input: HydrateLazyBindingsInput) => ReturnType<typeof hydrateLazyBindings>;
|
|
33
|
+
readOverlayBindings: typeof readUnityOverlayBindings;
|
|
34
|
+
upsertOverlayBindings: typeof upsertUnityOverlayBindings;
|
|
35
|
+
readParityCache: typeof readUnityParityCache;
|
|
36
|
+
upsertParityCache: typeof upsertUnityParityCache;
|
|
37
|
+
loadParitySeed: typeof loadUnityParitySeed;
|
|
38
|
+
buildScanContext: typeof buildUnityScanContext;
|
|
39
|
+
buildScanContextFromSeed: typeof buildUnityScanContextFromSeed;
|
|
40
|
+
resolveBindings: typeof resolveUnityBindings;
|
|
41
|
+
shouldEnableWarmup: (env: NodeJS.ProcessEnv) => boolean;
|
|
42
|
+
}
|
|
43
|
+
export declare function mergeUnityBindings(baseBindings: ResolvedUnityBinding[], resolvedByPath: Map<string, ResolvedUnityBinding[]>): ResolvedUnityBinding[];
|
|
44
|
+
export declare function mergeParityUnityBindings(baseNonLightweightBindings: ResolvedUnityBinding[], resolvedBindings: ResolvedUnityBinding[]): ResolvedUnityBinding[];
|
|
45
|
+
export declare function attachUnityHydrationMeta(payload: UnityContextPayload, input: Pick<UnityHydrationMeta, 'requestedMode' | 'effectiveMode' | 'elapsedMs' | 'fallbackToCompact'> & {
|
|
46
|
+
hasExpandableBindings: boolean;
|
|
47
|
+
}): UnityContextPayload;
|
|
48
|
+
export declare function hydrateUnityForSymbol(input: HydrateUnityInput): Promise<UnityContextPayload>;
|
|
49
|
+
export declare function __resetUnityRuntimeHydrationStateForTest(): void;
|
|
50
|
+
export {};
|