rea-agents 2.2.0 → 2.3.0
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/README.md +56 -9
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
- package/dist/application/BinarySession.js +9 -2
- package/dist/application/BinarySessionStatus.js +39 -1
- package/dist/application/CapabilityInventory.js +15 -0
- package/dist/application/CommandShimReplay.js +6 -3
- package/dist/application/CompositeProvider.js +5 -2
- package/dist/application/DirectAnalysis.js +1 -20
- package/dist/application/DirectAnalysisStatus.js +83 -0
- package/dist/application/Doctor.js +34 -25
- package/dist/application/DoctorDiagnostics.js +1 -4
- package/dist/application/DoctorProjection.js +43 -0
- package/dist/application/DoctorScope.js +102 -0
- package/dist/application/EvidenceReferenceResolver.js +26 -0
- package/dist/application/JavaScriptApplicationEvidence.js +1 -1
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
- package/dist/application/JavaScriptApplicationService.js +3 -2
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
- package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
- package/dist/application/JavaScriptModuleRelationships.js +25 -1
- package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
- package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
- package/dist/application/JavaScriptSemanticTraceService.js +45 -0
- package/dist/application/LoopbackReplay.js +277 -133
- package/dist/application/LoopbackReplayRecorder.js +101 -0
- package/dist/application/PermissionAuthority.js +7 -3
- package/dist/application/ProcessCaptureJournal.js +95 -0
- package/dist/application/ProcessCaptureLifecycle.js +24 -13
- package/dist/application/ProcessCheckpoints.js +30 -4
- package/dist/application/ProcessCli.js +26 -4
- package/dist/application/ProcessHarness.js +20 -50
- package/dist/application/ProcessNormalization.js +3 -2
- package/dist/application/ProcessReactiveCoordinator.js +218 -0
- package/dist/application/ProcessReactiveEffects.js +133 -0
- package/dist/application/ProcessReactiveObservations.js +20 -0
- package/dist/application/ProcessSampling.js +2 -0
- package/dist/application/SessionProviderRouter.js +7 -6
- package/dist/application/Setup.js +11 -10
- package/dist/application/SetupPlan.js +1 -1
- package/dist/application/SetupRegistrationEnvironment.js +12 -0
- package/dist/application/TerminalRenderer.js +3 -1
- package/dist/browser/CdpEndpoint.js +37 -4
- package/dist/catalogIdentity.js +16 -7
- package/dist/cli/coreAnalysisCommands.js +34 -2
- package/dist/cli/javascriptApplicationAnalysis.js +19 -0
- package/dist/cli/setupCommands.js +81 -32
- package/dist/cli/utilityCommands.js +10 -2
- package/dist/cliApplicationCommands.js +79 -16
- package/dist/cliCommandNames.js +3 -0
- package/dist/cliElectronCommands.js +23 -33
- package/dist/cliObservationOptions.js +1 -1
- package/dist/cliOutput.js +56 -0
- package/dist/cliProcessCommands.js +32 -1
- package/dist/cliSetup.js +30 -21
- package/dist/contracts/applicationToolContracts.js +54 -7
- package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
- package/dist/contracts/electronToolContracts.js +53 -32
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
- package/dist/contracts/processCaptureExample.js +1 -0
- package/dist/contracts/replayMachineExample.js +37 -0
- package/dist/contracts/toolContractExamples.js +2 -0
- package/dist/contracts/toolContracts.js +5 -1
- package/dist/contracts/toolEffects.js +3 -0
- package/dist/contracts/toolOutputSchemaGroups.js +2 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +40 -0
- package/dist/doctorRuntime.js +41 -0
- package/dist/domain/analysisErrorPresentation.js +5 -3
- package/dist/domain/analysisErrorProjection.js +7 -1
- package/dist/domain/changedBehavior.js +5 -4
- package/dist/domain/completionLedgerGeneration.js +190 -0
- package/dist/domain/errors.js +4 -2
- package/dist/domain/evidenceCompletionLedger.js +113 -0
- package/dist/domain/hopperStartupFailure.js +9 -0
- package/dist/domain/javascriptApplicationAnalysis.js +44 -2
- package/dist/domain/javascriptExportShapeComparison.js +145 -0
- package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
- package/dist/domain/javascriptExportShapeSelection.js +132 -0
- package/dist/domain/javascriptExportShapeVariants.js +272 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
- package/dist/domain/javascriptSemanticAnalysis.js +17 -36
- package/dist/domain/javascriptSemanticCallResolution.js +129 -0
- package/dist/domain/javascriptSemanticCalls.js +269 -0
- package/dist/domain/javascriptSemanticGraph.js +356 -0
- package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
- package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
- package/dist/domain/javascriptSemanticIr.js +14 -1
- package/dist/domain/javascriptSemanticPrimitives.js +36 -0
- package/dist/domain/javascriptSemanticProjection.js +36 -4
- package/dist/domain/javascriptSemanticProvenance.js +29 -0
- package/dist/domain/javascriptSemanticQuery.js +294 -0
- package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
- package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
- package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
- package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
- package/dist/domain/javascriptSemanticReturns.js +187 -0
- package/dist/domain/javascriptSemanticState.js +32 -0
- package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
- package/dist/domain/javascriptSemanticValues.js +54 -70
- package/dist/domain/processCapture.js +36 -0
- package/dist/domain/processCaptureValidation.js +101 -12
- package/dist/domain/processComparison.js +78 -25
- package/dist/domain/processObservation.js +153 -0
- package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
- package/dist/domain/processReactiveMatching.js +210 -0
- package/dist/domain/processReactiveRuntime.js +109 -0
- package/dist/domain/processReactiveScenario.js +361 -0
- package/dist/domain/processReactiveScenarioPreflight.js +120 -0
- package/dist/domain/processReactiveTransition.js +159 -0
- package/dist/domain/processScenario.js +12 -0
- package/dist/domain/processTraceComparison.js +43 -0
- package/dist/domain/processTraceDimensionProjection.js +50 -0
- package/dist/domain/processTraceEvaluation.js +312 -0
- package/dist/domain/processTraceSpecification.js +373 -0
- package/dist/domain/reconstructionVerification.js +5 -4
- package/dist/domain/replayMachine.js +18 -2
- package/dist/domain/replayMachineRun.js +216 -0
- package/dist/domain/replayMachineRuntime.js +88 -9
- package/dist/domain/staticRuntimeCorrelation.js +4 -2
- package/dist/evaluation/CodexAgentEval.js +24 -0
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +13 -2
- package/dist/ghidra/GhidraDiagnostics.js +1 -0
- package/dist/ghidra/GhidraLauncher.js +7 -3
- package/dist/ghidra/GhidraProvider.js +8 -1
- package/dist/hopper/BridgeLauncher.js +56 -14
- package/dist/hopper/HopperClient.js +23 -10
- package/dist/hopper/HopperDiagnostics.js +14 -0
- package/dist/hopper/HopperProcessDiagnostic.js +14 -0
- package/dist/hopper/HopperProvider.js +8 -1
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
- package/dist/main/transport.js +2 -0
- package/dist/mcpDoctor.js +310 -0
- package/dist/process/ProcessOwnership.js +200 -53
- package/dist/process/ProviderRunLineage.js +21 -0
- package/dist/server/createServer.js +4 -1
- package/dist/server/javascriptApplicationResult.js +22 -1
- package/dist/server/registerApplicationTools/characterization.js +3 -3
- package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
- package/dist/server/registerApplicationTools/compareVersions.js +12 -6
- package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -3
- package/dist/server/registerApplicationTools/helpers.js +37 -25
- package/dist/server/registerApplicationTools/traceFeature.js +9 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
- package/dist/server/registerApplicationTools.js +4 -0
- package/dist/server/registerEvidenceResources.js +5 -1
- package/dist/server/registerProcessComparisonTool.js +17 -7
- package/dist/server/registerReplayMachineTool.js +20 -0
- package/dist/server/registerSessionTools.js +12 -7
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/serverIdentity.js +19 -0
- package/package.json +62 -30
- package/scripts/hopper-demo-x11.py +459 -61
- package/scripts/prepack.mjs +55 -0
- package/scripts/prepare.mjs +28 -0
- package/scripts/rea.mjs +26 -5
- package/skills/reverse-engineer-anything/SKILL.md +2 -2
- package/skills/reverse-engineer-anything/references/javascript-applications.md +10 -0
|
@@ -12,25 +12,42 @@ import { PRODUCT_IDENTITY, SDK_IDENTITY } from "../identity.js";
|
|
|
12
12
|
import { readClientRegistrationStatuses, } from "./ClientRegistrationStatus.js";
|
|
13
13
|
import { inspectRuntimeExecutables, } from "./RuntimeExecutableDiagnostics.js";
|
|
14
14
|
import { collectDoctorDiagnostics, doctorHealthy, } from "./DoctorDiagnostics.js";
|
|
15
|
+
import { normalizeDoctorScope, scopeDoctorChecks, } from "./DoctorScope.js";
|
|
15
16
|
const execFileAsync = promisify(execFile);
|
|
17
|
+
/** Deep provider IDs whose readiness can be selected explicitly by doctor. */
|
|
18
|
+
export const DOCTOR_PROVIDER_IDS = ["hopper", "ghidra"];
|
|
16
19
|
/**
|
|
17
20
|
* Check requirements and an optional target without mutating the host.
|
|
18
21
|
* Every failed check includes remediation suitable for either the one-shot CLI
|
|
19
22
|
* or an agent consuming the structured result.
|
|
20
23
|
*/
|
|
21
|
-
export const runDoctor = async (target, host = systemDoctorHost()) => {
|
|
24
|
+
export const runDoctor = async (target, host = systemDoctorHost(), requestedScope) => {
|
|
22
25
|
const { checks: diagnosticChecks, hopperPath, providerInspections, runtimeExecutables, } = await collectDoctorDiagnostics(target, host);
|
|
23
26
|
const identity = await collectDoctorIdentity(host, runtimeExecutables);
|
|
24
27
|
const checks = [...diagnosticChecks, ...identity.checks];
|
|
28
|
+
const providers = {
|
|
29
|
+
hopperAvailable: hopperPath !== undefined &&
|
|
30
|
+
checks
|
|
31
|
+
.filter(({ name }) => name.startsWith("hopper"))
|
|
32
|
+
.every(({ ok }) => ok),
|
|
33
|
+
hopperConfigured: host.configuredHopperPath !== undefined,
|
|
34
|
+
providerInspections,
|
|
35
|
+
};
|
|
36
|
+
const environmentHealthy = doctorHealthy(checks, providers);
|
|
37
|
+
const scope = normalizeDoctorScope(requestedScope, target);
|
|
38
|
+
const scoped = scopeDoctorChecks({
|
|
39
|
+
checks,
|
|
40
|
+
registrations: identity.value.registrations,
|
|
41
|
+
skillState: identity.value.skill.state,
|
|
42
|
+
providers,
|
|
43
|
+
scope,
|
|
44
|
+
});
|
|
25
45
|
return {
|
|
26
|
-
healthy:
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
hopperConfigured: host.configuredHopperPath !== undefined,
|
|
32
|
-
providerInspections,
|
|
33
|
-
}),
|
|
46
|
+
healthy: scope.mode === "audit-wide" ? environmentHealthy : scoped.healthy,
|
|
47
|
+
environment_healthy: environmentHealthy,
|
|
48
|
+
scope,
|
|
49
|
+
scope_checks: scope.mode === "audit-wide" ? checks : scoped.scopeChecks,
|
|
50
|
+
informational_checks: scope.mode === "audit-wide" ? [] : scoped.informationalChecks,
|
|
34
51
|
...(hopperPath === undefined ? {} : { hopperPath }),
|
|
35
52
|
...(providerInspections === undefined ? {} : { providerInspections }),
|
|
36
53
|
checks,
|
|
@@ -127,7 +144,7 @@ export const systemDoctorHost = (options = {}) => ({
|
|
|
127
144
|
return (await parseBinaryTarget(path)).ok;
|
|
128
145
|
},
|
|
129
146
|
executable: executableAvailable,
|
|
130
|
-
|
|
147
|
+
linuxDemoRuntimeCheck: options.linuxDemoRuntimeCheck ?? uncomposedLinuxDemoRuntimeCheck,
|
|
131
148
|
supportedLinuxHopper: linuxHopperBinarySupported,
|
|
132
149
|
async brewHopperPath() {
|
|
133
150
|
return probeHomebrew(async (command) => {
|
|
@@ -202,21 +219,13 @@ const executableAvailable = async (path) => {
|
|
|
202
219
|
return false;
|
|
203
220
|
}
|
|
204
221
|
};
|
|
205
|
-
const
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
"import ctypes; ctypes.CDLL('libX11.so.6'); ctypes.CDLL('libXtst.so.6')",
|
|
213
|
-
]);
|
|
214
|
-
return true;
|
|
215
|
-
}
|
|
216
|
-
catch {
|
|
217
|
-
return false;
|
|
218
|
-
}
|
|
219
|
-
};
|
|
222
|
+
const uncomposedLinuxDemoRuntimeCheck = () => Promise.resolve({
|
|
223
|
+
name: "hopper-demo-runtime",
|
|
224
|
+
ok: false,
|
|
225
|
+
classification: "config_drift",
|
|
226
|
+
detail: "Linux Hopper private-display diagnostics were not composed",
|
|
227
|
+
remediation: "Run rea doctor through the production CLI adapter.",
|
|
228
|
+
});
|
|
220
229
|
const manualHopperPaths = async () => {
|
|
221
230
|
const paths = [];
|
|
222
231
|
for (const root of ["/Applications", join(homedir(), "Applications")]) {
|
|
@@ -134,10 +134,7 @@ const optionalHopperVersionCheck = async (host, hopperPath) => {
|
|
|
134
134
|
};
|
|
135
135
|
const optionalHopperDemoCheck = async (host, hopperPath) => host.platform !== "linux" || hopperPath === undefined
|
|
136
136
|
? undefined
|
|
137
|
-
:
|
|
138
|
-
remediation: "Rerun rea setup to install the Xvfb, xauth, Python, X11, and XTEST packages required for Linux demo sessions.",
|
|
139
|
-
classification: "missing_dependency",
|
|
140
|
-
});
|
|
137
|
+
: host.linuxDemoRuntimeCheck();
|
|
141
138
|
const optionalIlspyCheck = async (host) => {
|
|
142
139
|
if (host.configuredIlspyCmdPath === undefined)
|
|
143
140
|
return undefined;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
/** Project doctor diagnostics for concise CLI output or explicit full detail. */
|
|
2
|
+
export const projectDoctorReport = (report, detail) => detail === "full" ? report : doctorSummary(report);
|
|
3
|
+
const doctorSummary = (report) => ({
|
|
4
|
+
healthy: report.healthy,
|
|
5
|
+
environment_healthy: report.environment_healthy,
|
|
6
|
+
scope: report.scope,
|
|
7
|
+
...(report.hopperPath === undefined
|
|
8
|
+
? {}
|
|
9
|
+
: { hopper_path: report.hopperPath }),
|
|
10
|
+
providers: (report.providerInspections ?? []).map((provider) => ({
|
|
11
|
+
id: provider.id,
|
|
12
|
+
configured: provider.configured,
|
|
13
|
+
available: provider.available,
|
|
14
|
+
provider_version: provider.providerVersion,
|
|
15
|
+
failed_checks: provider.checks.filter(({ ok }) => !ok).map(checkSummary),
|
|
16
|
+
})),
|
|
17
|
+
failed_scope_checks: report.scope_checks
|
|
18
|
+
.filter(({ ok }) => !ok)
|
|
19
|
+
.map(checkSummary),
|
|
20
|
+
informational_drift_count: report.informational_checks.filter(({ ok }) => !ok)
|
|
21
|
+
.length,
|
|
22
|
+
identity: report.identity === undefined
|
|
23
|
+
? null
|
|
24
|
+
: {
|
|
25
|
+
cli_package_version: report.identity.cli_package_version,
|
|
26
|
+
expected_skill_version: report.identity.expected_skill_version,
|
|
27
|
+
catalog: {
|
|
28
|
+
counts: report.identity.catalog.counts,
|
|
29
|
+
digests: report.identity.catalog.digests,
|
|
30
|
+
},
|
|
31
|
+
installations: report.identity.installations,
|
|
32
|
+
skill: report.identity.skill,
|
|
33
|
+
registrations: report.identity.registrations,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
const checkSummary = (check) => ({
|
|
37
|
+
name: check.name,
|
|
38
|
+
classification: check.classification,
|
|
39
|
+
...(check.detail === undefined ? {} : { detail: check.detail }),
|
|
40
|
+
...(check.remediation === undefined || check.remediation === null
|
|
41
|
+
? {}
|
|
42
|
+
: { remediation: check.remediation }),
|
|
43
|
+
});
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
import { doctorHealthy } from "./DoctorDiagnostics.js";
|
|
2
|
+
/** Normalize a caller-selected doctor readiness boundary. */
|
|
3
|
+
export const normalizeDoctorScope = (requested, target) => ({
|
|
4
|
+
mode: requested === undefined ? "audit-wide" : "explicit",
|
|
5
|
+
clients: uniqueSorted(requested?.clients ?? []),
|
|
6
|
+
providers: uniqueSorted(requested?.providers ?? []),
|
|
7
|
+
skill: requested?.skill === true,
|
|
8
|
+
target: target ?? null,
|
|
9
|
+
});
|
|
10
|
+
/** Partition diagnostics into required and informational scope checks. */
|
|
11
|
+
export const scopeDoctorChecks = (input) => {
|
|
12
|
+
const providerChecks = input.checks.filter((candidate) => isProviderCheck(candidate.name, input.providers.providerInspections));
|
|
13
|
+
const coreChecks = input.checks.filter(({ name }) => !isProviderCheck(name, input.providers.providerInspections) &&
|
|
14
|
+
name !== "skill:identity" &&
|
|
15
|
+
!name.startsWith("registration:"));
|
|
16
|
+
const clientChecks = input.scope.clients.map((client) => selectedRegistrationCheck(client, input.registrations.find((candidate) => candidate.client === client)));
|
|
17
|
+
const skillChecks = input.scope.skill
|
|
18
|
+
? [selectedSkillCheck(input.skillState, input.checks)]
|
|
19
|
+
: [];
|
|
20
|
+
const selectedProviderChecks = input.scope.providers.length === 0
|
|
21
|
+
? configuredProviderChecks(providerChecks, input.providers)
|
|
22
|
+
: input.scope.providers.flatMap((providerId) => selectedProviderChecksFor(providerId, providerChecks, input.providers));
|
|
23
|
+
const scopeChecks = [
|
|
24
|
+
...coreChecks,
|
|
25
|
+
...selectedProviderChecks,
|
|
26
|
+
...clientChecks,
|
|
27
|
+
...skillChecks,
|
|
28
|
+
];
|
|
29
|
+
const providerHealthy = input.scope.providers.length === 0
|
|
30
|
+
? doctorHealthy([...coreChecks, ...providerChecks, ...clientChecks, ...skillChecks], input.providers)
|
|
31
|
+
: selectedProviderChecks.every(({ ok }) => ok);
|
|
32
|
+
const selectedNames = new Set(scopeChecks.map(({ name }) => name));
|
|
33
|
+
return {
|
|
34
|
+
healthy: coreChecks.every(({ ok }) => ok) &&
|
|
35
|
+
clientChecks.every(({ ok }) => ok) &&
|
|
36
|
+
skillChecks.every(({ ok }) => ok) &&
|
|
37
|
+
providerHealthy,
|
|
38
|
+
scopeChecks,
|
|
39
|
+
informationalChecks: input.checks.filter(({ name }) => !selectedNames.has(name)),
|
|
40
|
+
};
|
|
41
|
+
};
|
|
42
|
+
const isProviderCheck = (name, inspections) => name.startsWith("hopper") ||
|
|
43
|
+
inspections?.some(({ id }) => doctorProviderCheckName(id, name)) === true;
|
|
44
|
+
const configuredProviderChecks = (checks, providers) => checks.filter(({ name }) => name.startsWith("hopper")
|
|
45
|
+
? providers.hopperConfigured
|
|
46
|
+
: providers.providerInspections?.some(({ id, configured }) => configured && doctorProviderCheckName(id, name)) === true);
|
|
47
|
+
const selectedProviderChecksFor = (providerId, checks, providers) => {
|
|
48
|
+
const selected = checks.filter(({ name }) => providerId === "hopper"
|
|
49
|
+
? name.startsWith("hopper")
|
|
50
|
+
: doctorProviderCheckName(providerId, name));
|
|
51
|
+
const available = providerId === "hopper"
|
|
52
|
+
? providers.hopperAvailable
|
|
53
|
+
: providers.providerInspections?.find(({ id }) => id === providerId)
|
|
54
|
+
?.available === true;
|
|
55
|
+
if (available && selected.every(({ ok }) => ok))
|
|
56
|
+
return selected;
|
|
57
|
+
if (selected.some(({ ok }) => !ok))
|
|
58
|
+
return selected;
|
|
59
|
+
return [
|
|
60
|
+
...selected,
|
|
61
|
+
{
|
|
62
|
+
name: `provider:${providerId}`,
|
|
63
|
+
ok: false,
|
|
64
|
+
classification: "missing_analysis_engine",
|
|
65
|
+
detail: `Requested provider ${providerId} is unavailable.`,
|
|
66
|
+
remediation: `Configure the ${providerId} provider, then rerun rea doctor.`,
|
|
67
|
+
},
|
|
68
|
+
];
|
|
69
|
+
};
|
|
70
|
+
const selectedRegistrationCheck = (client, status) => status === undefined
|
|
71
|
+
? {
|
|
72
|
+
name: `registration:${client}`,
|
|
73
|
+
ok: false,
|
|
74
|
+
classification: "config_drift",
|
|
75
|
+
detail: `Requested client ${client} was not detected.`,
|
|
76
|
+
remediation: `Install or select ${client}, then run rea setup --client ${client}.`,
|
|
77
|
+
}
|
|
78
|
+
: status.state === "aligned"
|
|
79
|
+
? {
|
|
80
|
+
name: `registration:${client}`,
|
|
81
|
+
ok: true,
|
|
82
|
+
classification: "healthy",
|
|
83
|
+
detail: status.config_path,
|
|
84
|
+
}
|
|
85
|
+
: registrationCheck(status);
|
|
86
|
+
const registrationCheck = (status) => ({
|
|
87
|
+
name: `registration:${status.client}`,
|
|
88
|
+
ok: false,
|
|
89
|
+
classification: "config_drift",
|
|
90
|
+
detail: status.config_path,
|
|
91
|
+
remediation: status.remediation ?? "Run rea setup, then restart the affected client.",
|
|
92
|
+
});
|
|
93
|
+
const selectedSkillCheck = (state, checks) => checks.find(({ name }) => name === "skill:identity") ?? {
|
|
94
|
+
name: "skill:identity",
|
|
95
|
+
ok: state === "aligned",
|
|
96
|
+
classification: state === "aligned" ? "healthy" : "config_drift",
|
|
97
|
+
...(state === "aligned"
|
|
98
|
+
? { detail: "Installed REA skill identity is aligned." }
|
|
99
|
+
: { remediation: "Run rea setup to update the installed REA skill." }),
|
|
100
|
+
};
|
|
101
|
+
const uniqueSorted = (values) => [...new Set(values)].sort((left, right) => left.localeCompare(right));
|
|
102
|
+
const doctorProviderCheckName = (providerId, name) => name === providerId || name.startsWith(`${providerId}-`);
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { EvidenceReferenceError } from "../domain/errors.js";
|
|
2
|
+
import { err, ok } from "../domain/result.js";
|
|
3
|
+
/** Resolve IDs without accepting the digest-shaped identifier as proof itself. */
|
|
4
|
+
export const resolveEvidenceReferences = (lookup, evidenceIds, expected) => {
|
|
5
|
+
const records = [];
|
|
6
|
+
for (const evidenceId of evidenceIds) {
|
|
7
|
+
const record = lookup?.(evidenceId);
|
|
8
|
+
if (record === undefined)
|
|
9
|
+
return err(new EvidenceReferenceError(evidenceId, "missing", expectationDescription(expected), null));
|
|
10
|
+
if (expected !== undefined) {
|
|
11
|
+
const operations = expected.filter(({ operation }) => operation === record.operation);
|
|
12
|
+
if (operations.length === 0)
|
|
13
|
+
return err(new EvidenceReferenceError(evidenceId, "wrong_operation", unique(expected.map(({ operation }) => operation)).join(" | "), record.operation));
|
|
14
|
+
if (!operations.some(({ predicate }) => predicate === record.predicate_type))
|
|
15
|
+
return err(new EvidenceReferenceError(evidenceId, "wrong_predicate", unique(operations.map(({ predicate }) => predicate)).join(" | "), record.predicate_type));
|
|
16
|
+
}
|
|
17
|
+
records.push(record);
|
|
18
|
+
}
|
|
19
|
+
return ok(records);
|
|
20
|
+
};
|
|
21
|
+
const expectationDescription = (expected) => expected === undefined
|
|
22
|
+
? "Evidence in the current authority"
|
|
23
|
+
: expected
|
|
24
|
+
.map(({ operation, predicate }) => `${operation}:${predicate}`)
|
|
25
|
+
.join(" | ");
|
|
26
|
+
const unique = (values) => [...new Set(values)];
|
|
@@ -7,7 +7,7 @@ export const createJavaScriptApplicationEvidence = (input, result) => createEvid
|
|
|
7
7
|
sha256: result.root_artifact_sha256,
|
|
8
8
|
format: result.format,
|
|
9
9
|
}, JAVASCRIPT_APPLICATION_PROVIDER, {
|
|
10
|
-
predicateType:
|
|
10
|
+
predicateType: `rea.javascript-application-analysis/v${String(result.schema_version)}`,
|
|
11
11
|
operation: "analyze_javascript_application",
|
|
12
12
|
parameters: parameters(input),
|
|
13
13
|
result: jsonValueSchema.parse(result),
|
|
@@ -7,7 +7,10 @@ import { managedApplicationGraphResultSchema } from "../domain/managedApplicatio
|
|
|
7
7
|
export const parseApplicationGraphEvidence = (input) => {
|
|
8
8
|
const evidence = parseEvidence(input);
|
|
9
9
|
if (evidence.operation === "analyze_javascript_application" &&
|
|
10
|
-
|
|
10
|
+
[
|
|
11
|
+
"rea.javascript-application-analysis/v1",
|
|
12
|
+
"rea.javascript-application-analysis/v2",
|
|
13
|
+
].includes(evidence.predicate_type) &&
|
|
11
14
|
providerMatches(evidence, JAVASCRIPT_APPLICATION_PROVIDER))
|
|
12
15
|
return staticApplicationSource(evidence);
|
|
13
16
|
if (evidence.operation === "reconcile_javascript_runtime" &&
|
|
@@ -25,6 +28,9 @@ const staticApplicationSource = (evidence) => {
|
|
|
25
28
|
evidence.confidence !== "derived")
|
|
26
29
|
throw new TypeError("JavaScript application Evidence authority or confidence is invalid");
|
|
27
30
|
const result = javascriptApplicationAnalysisResultSchema.parse(evidence.normalized_result);
|
|
31
|
+
if (evidence.predicate_type !==
|
|
32
|
+
`rea.javascript-application-analysis/v${String(result.schema_version)}`)
|
|
33
|
+
throw new TypeError("JavaScript application Evidence predicate does not match its result schema version");
|
|
28
34
|
analyzeJavaScriptApplicationInputSchema.parse({
|
|
29
35
|
input_path: result.input_path,
|
|
30
36
|
...evidence.parameters,
|
|
@@ -35,6 +41,7 @@ const staticApplicationSource = (evidence) => {
|
|
|
35
41
|
graph: result.graph,
|
|
36
42
|
kind: "static-application",
|
|
37
43
|
rootArtifactSha256: result.root_artifact_sha256,
|
|
44
|
+
semanticGraph: result.schema_version === 2 ? result.semantic_graph : null,
|
|
38
45
|
};
|
|
39
46
|
};
|
|
40
47
|
const staticRuntimeSource = (evidence) => {
|
|
@@ -52,6 +59,7 @@ const staticRuntimeSource = (evidence) => {
|
|
|
52
59
|
graph: result.graph,
|
|
53
60
|
kind: "static-runtime-reconciliation",
|
|
54
61
|
rootArtifactSha256: applicationLayer.root_artifact_sha256,
|
|
62
|
+
semanticGraph: null,
|
|
55
63
|
};
|
|
56
64
|
};
|
|
57
65
|
const managedApplicationSource = (evidence) => {
|
|
@@ -66,6 +74,7 @@ const managedApplicationSource = (evidence) => {
|
|
|
66
74
|
graph: result.graph,
|
|
67
75
|
kind: "managed-application",
|
|
68
76
|
rootArtifactSha256: result.root_artifact_sha256,
|
|
77
|
+
semanticGraph: null,
|
|
69
78
|
};
|
|
70
79
|
};
|
|
71
80
|
const assertApplicationSubject = (evidence, result) => {
|
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { ArtifactReaderFailure } from "../artifacts/ArtifactReader.js";
|
|
3
3
|
import { analyzeJavaScriptApplicationInputSchema, javascriptApplicationAnalysisResultSchema, } from "../domain/javascriptApplicationAnalysis.js";
|
|
4
4
|
import { AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisProtocolError, ArtifactOperationError, PermissionRequiredError, } from "../domain/errors.js";
|
|
5
|
+
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
5
6
|
import { err, ok } from "../domain/result.js";
|
|
6
7
|
import { createJavaScriptApplicationEvidence } from "./JavaScriptApplicationEvidence.js";
|
|
7
8
|
import { reconstructJavaScriptArtifact } from "./JavaScriptArtifactReconstruction.js";
|
|
@@ -10,7 +11,7 @@ const OPERATION = "analyze_javascript_application";
|
|
|
10
11
|
export const analyzeJavaScriptApplication = async (authority, rawInput, options = {}) => {
|
|
11
12
|
const parsed = analyzeJavaScriptApplicationInputSchema.safeParse(rawInput);
|
|
12
13
|
if (!parsed.success)
|
|
13
|
-
return err(new AnalysisInputError(OPERATION));
|
|
14
|
+
return err(new AnalysisInputError(OPERATION, undefined, projectInputIssues(parsed.error.issues, rawInput)));
|
|
14
15
|
return analyzeJavaScriptApplicationValidated(authority, parsed.data, options);
|
|
15
16
|
};
|
|
16
17
|
/** Analyze input already parsed by a trusted adapter boundary. */
|
|
@@ -50,7 +51,7 @@ export const analyzeJavaScriptApplicationValidated = async (authority, input, op
|
|
|
50
51
|
}, options.signal);
|
|
51
52
|
const { electron_summary: summary, ...application } = reconstructed;
|
|
52
53
|
const result = javascriptApplicationAnalysisResultSchema.parse({
|
|
53
|
-
schema_version:
|
|
54
|
+
schema_version: 2,
|
|
54
55
|
...application,
|
|
55
56
|
summary,
|
|
56
57
|
limitations: reconstructed.graph.limitations,
|
|
@@ -14,6 +14,19 @@ export const createApplicationFeatureTraceEvidence = (parameters, result) => cre
|
|
|
14
14
|
limitations: result.limitations,
|
|
15
15
|
evidenceLinks: result.evidence_links,
|
|
16
16
|
});
|
|
17
|
+
/** Create derived Evidence for one bounded JavaScript semantic trace. */
|
|
18
|
+
export const createJavaScriptSemanticTraceEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
|
|
19
|
+
predicateType: "rea.javascript-semantic-trace/v1",
|
|
20
|
+
operation: "trace_javascript_semantics",
|
|
21
|
+
parameters,
|
|
22
|
+
result: jsonValueSchema.parse(result),
|
|
23
|
+
rawResult: null,
|
|
24
|
+
confidence: "inferred",
|
|
25
|
+
authority: "analyst-inference",
|
|
26
|
+
environment: null,
|
|
27
|
+
limitations: result.limitations,
|
|
28
|
+
evidenceLinks: result.evidence_links,
|
|
29
|
+
});
|
|
17
30
|
/** Create derived Evidence for one tiered application version comparison. */
|
|
18
31
|
export const createApplicationVersionComparisonEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
|
|
19
32
|
predicateType: "rea.application-version-comparison/v1",
|
|
@@ -27,3 +40,16 @@ export const createApplicationVersionComparisonEvidence = (parameters, result) =
|
|
|
27
40
|
limitations: result.limitations,
|
|
28
41
|
evidenceLinks: result.evidence_links,
|
|
29
42
|
});
|
|
43
|
+
/** Create derived Evidence for one bounded static export-shape comparison. */
|
|
44
|
+
export const createJavaScriptExportShapeComparisonEvidence = (parameters, result) => createEvidence(undefined, JAVASCRIPT_APPLICATION_WORKFLOW_PROVIDER, {
|
|
45
|
+
predicateType: "rea.javascript-export-shape-comparison/v1",
|
|
46
|
+
operation: "compare_javascript_export_shapes",
|
|
47
|
+
parameters,
|
|
48
|
+
result: jsonValueSchema.parse(result),
|
|
49
|
+
rawResult: null,
|
|
50
|
+
confidence: "inferred",
|
|
51
|
+
authority: "analyst-inference",
|
|
52
|
+
environment: null,
|
|
53
|
+
limitations: result.limitations,
|
|
54
|
+
evidenceLinks: result.evidence_links,
|
|
55
|
+
});
|
|
@@ -3,11 +3,13 @@ import { AnalysisInputError, AnalysisProtocolError, } from "../domain/errors.js"
|
|
|
3
3
|
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
4
4
|
import { compareJavaScriptApplicationVersions } from "../domain/javascriptApplicationVersionComparison.js";
|
|
5
5
|
import { compareApplicationVersionsInputSchema } from "../domain/javascriptApplicationVersionComparisonSchemas.js";
|
|
6
|
+
import { compareJavaScriptExportShapes } from "../domain/javascriptExportShapeComparison.js";
|
|
7
|
+
import { compareJavaScriptExportShapesInputSchema } from "../domain/javascriptExportShapeComparisonSchemas.js";
|
|
6
8
|
import { traceApplicationFeature } from "../domain/javascriptFeatureTrace.js";
|
|
7
9
|
import { traceApplicationFeatureInputSchema } from "../domain/javascriptFeatureTraceSchemas.js";
|
|
8
10
|
import { err, ok } from "../domain/result.js";
|
|
9
11
|
import { parseApplicationGraphEvidence, parseNativeApplicationEvidence, } from "./JavaScriptApplicationEvidenceGraph.js";
|
|
10
|
-
import { createApplicationFeatureTraceEvidence, createApplicationVersionComparisonEvidence, } from "./JavaScriptApplicationWorkflowEvidence.js";
|
|
12
|
+
import { createApplicationFeatureTraceEvidence, createApplicationVersionComparisonEvidence, createJavaScriptExportShapeComparisonEvidence, } from "./JavaScriptApplicationWorkflowEvidence.js";
|
|
11
13
|
/** Authenticate Evidence and derive one bounded cross-layer feature trace. */
|
|
12
14
|
export const traceApplicationFeatureEvidence = (rawInput) => {
|
|
13
15
|
const operation = "trace_application_feature";
|
|
@@ -85,6 +87,52 @@ export const compareApplicationVersionsEvidenceValidated = (input) => {
|
|
|
85
87
|
return workflowFailure(operation, cause);
|
|
86
88
|
}
|
|
87
89
|
};
|
|
90
|
+
/**
|
|
91
|
+
* Authenticate both graphs and compare one exact export return shape.
|
|
92
|
+
* @public
|
|
93
|
+
*/
|
|
94
|
+
export const compareJavaScriptExportShapesEvidence = (rawInput) => {
|
|
95
|
+
const operation = "compare_javascript_export_shapes";
|
|
96
|
+
const parsed = compareJavaScriptExportShapesInputSchema.safeParse(rawInput);
|
|
97
|
+
if (!parsed.success)
|
|
98
|
+
return err(new AnalysisInputError(operation, undefined, projectInputIssues(parsed.error.issues, rawInput)));
|
|
99
|
+
return compareJavaScriptExportShapesEvidenceValidated(parsed.data);
|
|
100
|
+
};
|
|
101
|
+
/** Compare exact export shapes from input parsed by a trusted adapter. */
|
|
102
|
+
export const compareJavaScriptExportShapesEvidenceValidated = (input) => {
|
|
103
|
+
const operation = "compare_javascript_export_shapes";
|
|
104
|
+
try {
|
|
105
|
+
const left = parseApplicationGraphEvidence(input.left);
|
|
106
|
+
const right = parseApplicationGraphEvidence(input.right);
|
|
107
|
+
const result = compareJavaScriptExportShapes({
|
|
108
|
+
left: {
|
|
109
|
+
evidenceId: left.evidence.evidence_id,
|
|
110
|
+
graph: left.graph,
|
|
111
|
+
modulePath: input.left_module_path,
|
|
112
|
+
exportName: input.left_export_name,
|
|
113
|
+
},
|
|
114
|
+
right: {
|
|
115
|
+
evidenceId: right.evidence.evidence_id,
|
|
116
|
+
graph: right.graph,
|
|
117
|
+
modulePath: input.right_module_path,
|
|
118
|
+
exportName: input.right_export_name,
|
|
119
|
+
},
|
|
120
|
+
limits: input.limits,
|
|
121
|
+
});
|
|
122
|
+
return ok(createJavaScriptExportShapeComparisonEvidence({
|
|
123
|
+
left_evidence_id: left.evidence.evidence_id,
|
|
124
|
+
right_evidence_id: right.evidence.evidence_id,
|
|
125
|
+
left_module_path: input.left_module_path,
|
|
126
|
+
left_export_name: input.left_export_name,
|
|
127
|
+
right_module_path: input.right_module_path,
|
|
128
|
+
right_export_name: input.right_export_name,
|
|
129
|
+
limits: input.limits,
|
|
130
|
+
}, result));
|
|
131
|
+
}
|
|
132
|
+
catch (cause) {
|
|
133
|
+
return workflowFailure(operation, cause);
|
|
134
|
+
}
|
|
135
|
+
};
|
|
88
136
|
const workflowFailure = (operation, cause) => err(cause instanceof z.ZodError || cause instanceof TypeError
|
|
89
137
|
? new AnalysisInputError(operation)
|
|
90
138
|
: new AnalysisProtocolError("JavaScript application workflow produced an invalid result", { cause }));
|
|
@@ -9,6 +9,7 @@ import { buildJavaScriptArtifactGraph } from "./JavaScriptArtifactGraphBuilder.j
|
|
|
9
9
|
import { artifactLimitsForReconstruction, javascriptArtifactReconstructionInputSchema, } from "./JavaScriptArtifactReconstructionInput.js";
|
|
10
10
|
import { scanCanonicalArtifactInventory } from "./ArtifactInventory.js";
|
|
11
11
|
import { summarizeElectronBoundaries } from "./ElectronBoundaryAnalysis.js";
|
|
12
|
+
import { buildJavaScriptSemanticGraph } from "./JavaScriptSemanticGraphBuilder.js";
|
|
12
13
|
/** Reconstruct one local ASAR or extracted directory without executing code. */
|
|
13
14
|
export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
14
15
|
const input = javascriptArtifactReconstructionInputSchema.parse(rawInput);
|
|
@@ -24,6 +25,11 @@ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
|
24
25
|
const analysis = analyzeJavaScriptArtifactFiles(files, input, () => performance.now());
|
|
25
26
|
abortIfNeeded(signal);
|
|
26
27
|
const graph = buildJavaScriptArtifactGraph(snapshot, files, analysis, input);
|
|
28
|
+
const semanticGraph = buildJavaScriptSemanticGraph({
|
|
29
|
+
rootArtifactSha256: snapshot.manifest.root_sha256,
|
|
30
|
+
applicationGraph: graph,
|
|
31
|
+
analysis,
|
|
32
|
+
});
|
|
27
33
|
return {
|
|
28
34
|
input_path: path,
|
|
29
35
|
format,
|
|
@@ -31,6 +37,7 @@ export const reconstructJavaScriptArtifact = async (rawInput, signal) => {
|
|
|
31
37
|
inventory_manifest_id: snapshot.manifest.manifest_id,
|
|
32
38
|
inventory_graph_sha256: snapshot.manifest.graph_sha256,
|
|
33
39
|
graph,
|
|
40
|
+
semantic_graph: semanticGraph,
|
|
34
41
|
electron_summary: summarizeElectronBoundaries(analysis),
|
|
35
42
|
statistics: {
|
|
36
43
|
relevant_files: files.files.length,
|
|
@@ -2,6 +2,7 @@ import { posix } from "node:path";
|
|
|
2
2
|
import { addAstContainsEdge, artifactLocalIdentity, } from "./JavaScriptArtifactGraphContext.js";
|
|
3
3
|
import { astObservationEvidence, completeReconstructionCoverage, partialReconstructionCoverage, staticInferenceEvidence, } from "./JavaScriptArtifactGraphEvidence.js";
|
|
4
4
|
import { resolveArtifactPathByContext } from "./JavaScriptArtifactPathResolution.js";
|
|
5
|
+
import { projectJavaScriptExportReturnShapes } from "./JavaScriptReturnShapeProjection.js";
|
|
5
6
|
/** Create one path-scoped source-module identity for every analyzed source file. */
|
|
6
7
|
export const addJavaScriptSourceModules = (context) => {
|
|
7
8
|
for (const analyzed of context.analysis.files) {
|
|
@@ -76,6 +77,13 @@ const addExportRelationship = (input) => {
|
|
|
76
77
|
const { context, file, semantic, source, link } = input;
|
|
77
78
|
if (link.exportedName === null)
|
|
78
79
|
return;
|
|
80
|
+
const baseCoverage = semanticCoverage(semantic);
|
|
81
|
+
const returnShapes = projectJavaScriptExportReturnShapes({
|
|
82
|
+
ir: semantic.ir,
|
|
83
|
+
link,
|
|
84
|
+
modulePath: file.path,
|
|
85
|
+
baseCoverage,
|
|
86
|
+
});
|
|
79
87
|
const exported = context.accumulator.addNode({
|
|
80
88
|
kind: "javascript-module",
|
|
81
89
|
identity: artifactLocalIdentity(file.sha256, "module-export", `${file.container_sha256}:${file.path}:${link.exportedName}`),
|
|
@@ -96,10 +104,26 @@ const addExportRelationship = (input) => {
|
|
|
96
104
|
path: file.path,
|
|
97
105
|
range: link.location,
|
|
98
106
|
operation: "recover-module-export",
|
|
99
|
-
coverage:
|
|
107
|
+
coverage: baseCoverage,
|
|
100
108
|
limitations: semantic.ir.limitations,
|
|
101
109
|
}),
|
|
102
110
|
},
|
|
111
|
+
...(returnShapes === null
|
|
112
|
+
? []
|
|
113
|
+
: [
|
|
114
|
+
{
|
|
115
|
+
label: `${file.path}:${link.exportedName}:return-shapes`,
|
|
116
|
+
properties: returnShapes.properties,
|
|
117
|
+
evidence: staticInferenceEvidence({
|
|
118
|
+
sha256: file.sha256,
|
|
119
|
+
path: file.path,
|
|
120
|
+
range: returnShapes.range,
|
|
121
|
+
operation: "recover-export-return-shapes",
|
|
122
|
+
coverage: returnShapes.coverage,
|
|
123
|
+
limitations: returnShapes.limitations,
|
|
124
|
+
}),
|
|
125
|
+
},
|
|
126
|
+
]),
|
|
103
127
|
],
|
|
104
128
|
});
|
|
105
129
|
context.accumulator.addEdge({
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { jsonObjectSchema, jsonValueSchema } from "../domain/jsonValue.js";
|
|
2
|
+
import { flattenSemanticReturnValue } from "../domain/javascriptSemanticReturns.js";
|
|
3
|
+
import { partialReconstructionCoverage } from "./JavaScriptArtifactGraphEvidence.js";
|
|
4
|
+
const MAX_PROJECTED_RETURN_SHAPES = 32;
|
|
5
|
+
const MAX_PROJECTED_RETURN_FIELDS = 64;
|
|
6
|
+
const MAX_PROJECTED_PROPERTY_COVERAGE = 64;
|
|
7
|
+
/** Project one exact export/callable link into shallow bounded graph values. */
|
|
8
|
+
export const projectJavaScriptExportReturnShapes = (input) => {
|
|
9
|
+
if (input.link.callableId === null || input.link.exportedName === null)
|
|
10
|
+
return null;
|
|
11
|
+
const callable = input.ir.callables.find(({ callableId }) => callableId === input.link.callableId);
|
|
12
|
+
if (callable === undefined)
|
|
13
|
+
return null;
|
|
14
|
+
const projection = projectReturnSites(callable);
|
|
15
|
+
const projectionOmitted = projection.omittedSites +
|
|
16
|
+
projection.omittedFields +
|
|
17
|
+
projection.omittedCoverage;
|
|
18
|
+
const semanticOmitted = callable.returnCoverage.omittedCount;
|
|
19
|
+
const complete = input.baseCoverage.status === "complete" &&
|
|
20
|
+
callable.returnCoverage.status === "complete" &&
|
|
21
|
+
projectionOmitted === 0;
|
|
22
|
+
const coverage = complete
|
|
23
|
+
? input.baseCoverage
|
|
24
|
+
: partialReconstructionCoverage([
|
|
25
|
+
...input.baseCoverage.limits,
|
|
26
|
+
{
|
|
27
|
+
name: "return-shape-sites",
|
|
28
|
+
value: MAX_PROJECTED_RETURN_SHAPES,
|
|
29
|
+
unit: "items",
|
|
30
|
+
},
|
|
31
|
+
{
|
|
32
|
+
name: "return-shape-fields",
|
|
33
|
+
value: MAX_PROJECTED_RETURN_FIELDS,
|
|
34
|
+
unit: "items",
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: "return-shape-property-coverage",
|
|
38
|
+
value: MAX_PROJECTED_PROPERTY_COVERAGE,
|
|
39
|
+
unit: "items",
|
|
40
|
+
},
|
|
41
|
+
], semanticOmitted === null ? null : semanticOmitted + projectionOmitted, callable.returnCoverage.status === "truncated" || projectionOmitted > 0);
|
|
42
|
+
const limitations = [
|
|
43
|
+
...input.ir.limitations,
|
|
44
|
+
"Return shapes are inferred from inert syntax and do not prove runtime behavior.",
|
|
45
|
+
...(callable.returnSites.length === 0
|
|
46
|
+
? [
|
|
47
|
+
"No direct return value was retained; runtime return behavior remains unknown.",
|
|
48
|
+
]
|
|
49
|
+
: []),
|
|
50
|
+
...(projectionOmitted > 0
|
|
51
|
+
? ["Return-shape graph projection reached explicit retention limits."]
|
|
52
|
+
: []),
|
|
53
|
+
];
|
|
54
|
+
return {
|
|
55
|
+
properties: jsonObjectSchema.parse({
|
|
56
|
+
semantic_role: "export-return-shapes",
|
|
57
|
+
module_path: input.modulePath,
|
|
58
|
+
exported_name: input.link.exportedName,
|
|
59
|
+
callable_id: callable.callableId,
|
|
60
|
+
callable_kind: callable.kind,
|
|
61
|
+
static_return_shapes: projection.shapes,
|
|
62
|
+
return_shape_coverage: {
|
|
63
|
+
status: callable.returnCoverage.status,
|
|
64
|
+
retained_return_sites: projection.shapes.length,
|
|
65
|
+
omitted_return_sites: semanticOmitted === null
|
|
66
|
+
? null
|
|
67
|
+
: semanticOmitted + projection.omittedSites,
|
|
68
|
+
omitted_fields: projection.omittedFields,
|
|
69
|
+
omitted_property_coverage: projection.omittedCoverage,
|
|
70
|
+
projection_complete: projectionOmitted === 0,
|
|
71
|
+
},
|
|
72
|
+
}),
|
|
73
|
+
range: callable.location,
|
|
74
|
+
coverage,
|
|
75
|
+
limitations,
|
|
76
|
+
};
|
|
77
|
+
};
|
|
78
|
+
const projectReturnSites = (callable) => {
|
|
79
|
+
let retainedFields = 0;
|
|
80
|
+
let retainedCoverage = 0;
|
|
81
|
+
let omittedFields = 0;
|
|
82
|
+
let omittedCoverage = 0;
|
|
83
|
+
const retainedSites = callable.returnSites.slice(0, MAX_PROJECTED_RETURN_SHAPES);
|
|
84
|
+
const shapes = retainedSites.map((site) => {
|
|
85
|
+
const flattened = flattenSemanticReturnValue(site.value);
|
|
86
|
+
const remainingFields = Math.max(0, MAX_PROJECTED_RETURN_FIELDS - retainedFields);
|
|
87
|
+
const fields = flattened.fields.slice(0, remainingFields).map((field) => ({
|
|
88
|
+
...field,
|
|
89
|
+
value: jsonValueSchema.parse(field.value),
|
|
90
|
+
}));
|
|
91
|
+
retainedFields += fields.length;
|
|
92
|
+
omittedFields += flattened.fields.length - fields.length;
|
|
93
|
+
const remainingCoverage = Math.max(0, MAX_PROJECTED_PROPERTY_COVERAGE - retainedCoverage);
|
|
94
|
+
const propertyCoverage = flattened.propertyCoverage.slice(0, remainingCoverage);
|
|
95
|
+
retainedCoverage += propertyCoverage.length;
|
|
96
|
+
omittedCoverage +=
|
|
97
|
+
flattened.propertyCoverage.length - propertyCoverage.length;
|
|
98
|
+
return {
|
|
99
|
+
source_range: site.location,
|
|
100
|
+
value_status: site.value.status,
|
|
101
|
+
fields,
|
|
102
|
+
property_coverage: propertyCoverage,
|
|
103
|
+
};
|
|
104
|
+
});
|
|
105
|
+
return {
|
|
106
|
+
shapes,
|
|
107
|
+
omittedSites: callable.returnSites.length - retainedSites.length,
|
|
108
|
+
omittedFields,
|
|
109
|
+
omittedCoverage,
|
|
110
|
+
};
|
|
111
|
+
};
|