rea-agents 2.1.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 +84 -18
- package/dist/application/AndroidApplicationService.js +17 -0
- package/dist/application/AppleApplicationService.js +17 -0
- 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/ClientRegistrationStatus.js +11 -4
- 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/InventoryProjectionEvidence.js +41 -0
- package/dist/application/InvestigationProviders.js +12 -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/ProcessPairedExperiment.js +72 -0
- 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 +14 -13
- package/dist/application/SetupClientConfiguration.js +10 -6
- package/dist/application/SetupPlan.js +4 -3
- package/dist/application/SetupRegistrationEnvironment.js +12 -0
- package/dist/application/SetupSkill.js +44 -40
- package/dist/application/TerminalRenderer.js +3 -1
- package/dist/application/Uninstall.js +7 -1
- package/dist/application/Upgrade.js +16 -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 +84 -30
- 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 +55 -29
- package/dist/contracts/applicationToolContracts.js +54 -7
- package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
- package/dist/contracts/electronToolContracts.js +73 -4
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
- package/dist/contracts/managedToolContracts.js +7 -2
- package/dist/contracts/processCaptureExample.js +1 -0
- package/dist/contracts/replayMachineExample.js +37 -0
- package/dist/contracts/sessionStatusContract.js +26 -0
- package/dist/contracts/toolContractExamples.js +2 -0
- package/dist/contracts/toolContractTypes.js +12 -1
- package/dist/contracts/toolContracts.js +8 -11
- package/dist/contracts/toolEffects.js +3 -0
- package/dist/contracts/toolOutputSchemaGroups.js +53 -9
- package/dist/contracts/toolOutputSchemaPrimitives.js +73 -32
- package/dist/doctorRuntime.js +41 -0
- package/dist/domain/analysisErrorPresentation.js +5 -3
- package/dist/domain/analysisErrorProjection.js +7 -1
- package/dist/domain/androidApplication.js +206 -0
- package/dist/domain/appleApplication.js +221 -0
- package/dist/domain/boundedCartesianProjection.js +15 -0
- 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 +96 -24
- package/dist/domain/processObservation.js +153 -0
- package/dist/domain/processPairedExperiment.js +128 -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 +332 -0
- package/dist/domain/replayMachineRun.js +216 -0
- package/dist/domain/replayMachineRuntime.js +294 -0
- package/dist/domain/runtimeIdentification.js +210 -0
- package/dist/domain/staticRuntimeCorrelation.js +4 -2
- package/dist/evaluation/CodexAgentEval.js +156 -0
- package/dist/generatedPackageMetadata.js +2 -2
- 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/identity.js +2 -1
- 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 +8 -2
- package/dist/server/javascriptApplicationResult.js +106 -0
- 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/registerElectronTools.js +19 -5
- package/dist/server/registerEvidenceResources.js +7 -1
- package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
- package/dist/server/registerManagedTools.js +18 -1
- package/dist/server/registerProcessComparisonTool.js +17 -7
- package/dist/server/registerReplayMachineTool.js +20 -0
- package/dist/server/registerSessionStatusTool.js +95 -25
- package/dist/server/registerSessionTools.js +12 -7
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/toolResult.js +10 -4
- package/dist/serverIdentity.js +19 -0
- package/package.json +62 -29
- 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 +69 -228
- package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
- package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
- package/skills/reverse-engineer-anything/references/javascript-applications.md +35 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
- package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
|
@@ -64,11 +64,50 @@ const providerCapability = z.object({
|
|
|
64
64
|
}),
|
|
65
65
|
limitations: z.array(z.string()),
|
|
66
66
|
});
|
|
67
|
-
const providerIdentity = z.object({
|
|
67
|
+
export const providerIdentity = z.object({
|
|
68
68
|
id: z.string(),
|
|
69
69
|
name: z.string(),
|
|
70
70
|
version: z.string().nullable(),
|
|
71
71
|
});
|
|
72
|
+
const processCoordinates = {
|
|
73
|
+
launcher_pid: z.number().int().min(1),
|
|
74
|
+
process_group_id: z.number().int().min(1),
|
|
75
|
+
};
|
|
76
|
+
const processLineageObservation = z.discriminatedUnion("status", [
|
|
77
|
+
z.object({
|
|
78
|
+
status: z.literal("unavailable"),
|
|
79
|
+
observed_at: z.iso.datetime(),
|
|
80
|
+
...processCoordinates,
|
|
81
|
+
reason: z.string().min(1),
|
|
82
|
+
}),
|
|
83
|
+
z.object({
|
|
84
|
+
status: z.literal("verified"),
|
|
85
|
+
observed_at: z.iso.datetime(),
|
|
86
|
+
schema_version: z.literal(1),
|
|
87
|
+
...processCoordinates,
|
|
88
|
+
launcher_parent_pid: z.number().int().min(0),
|
|
89
|
+
descendants: z.array(z.object({
|
|
90
|
+
pid: z.number().int().min(1),
|
|
91
|
+
parent_pid: z.number().int().min(0),
|
|
92
|
+
process_group_id: z.number().int().min(1),
|
|
93
|
+
})),
|
|
94
|
+
}),
|
|
95
|
+
]);
|
|
96
|
+
const analysisRun = z
|
|
97
|
+
.object({
|
|
98
|
+
run_id: z.string().uuid(),
|
|
99
|
+
process_lineage: z.discriminatedUnion("status", [
|
|
100
|
+
z.object({ status: z.literal("not_observed") }),
|
|
101
|
+
z.object({
|
|
102
|
+
status: z.literal("snapshots"),
|
|
103
|
+
snapshots: z.array(z.object({
|
|
104
|
+
provider: providerIdentity,
|
|
105
|
+
observation: processLineageObservation,
|
|
106
|
+
})),
|
|
107
|
+
}),
|
|
108
|
+
]),
|
|
109
|
+
})
|
|
110
|
+
.nullable();
|
|
72
111
|
const providerRejectionCode = z.enum(PROVIDER_REJECTION_CODES);
|
|
73
112
|
const providerDiagnostics = z.record(z.string(), z.json());
|
|
74
113
|
const providerAvailability = z.discriminatedUnion("status", [
|
|
@@ -111,10 +150,42 @@ const providerTargetSupport = z.discriminatedUnion("status", [
|
|
|
111
150
|
diagnostics: providerDiagnostics,
|
|
112
151
|
}),
|
|
113
152
|
]);
|
|
153
|
+
export const toolAvailability = z.object({
|
|
154
|
+
name: z.string(),
|
|
155
|
+
surface: z.string(),
|
|
156
|
+
available: z.boolean(),
|
|
157
|
+
reason: z.enum([
|
|
158
|
+
"available",
|
|
159
|
+
"target_required",
|
|
160
|
+
"provider_missing",
|
|
161
|
+
"provider_unavailable",
|
|
162
|
+
"target_unsupported",
|
|
163
|
+
"unsupported_host",
|
|
164
|
+
"policy_disabled",
|
|
165
|
+
]),
|
|
166
|
+
remediation: z.string().nullable(),
|
|
167
|
+
effects: z.strictObject({
|
|
168
|
+
mutatesTarget: z.boolean(),
|
|
169
|
+
mutatesSession: z.boolean(),
|
|
170
|
+
writesFilesystem: z.boolean(),
|
|
171
|
+
launchesProcess: z.boolean(),
|
|
172
|
+
accessesNetwork: z.boolean(),
|
|
173
|
+
changesUiState: z.boolean(),
|
|
174
|
+
mayDiscardData: z.boolean(),
|
|
175
|
+
idempotent: z.boolean(),
|
|
176
|
+
}),
|
|
177
|
+
annotations: z.object({
|
|
178
|
+
read_only: z.boolean(),
|
|
179
|
+
destructive: z.boolean(),
|
|
180
|
+
idempotent: z.boolean(),
|
|
181
|
+
open_world: z.boolean(),
|
|
182
|
+
}),
|
|
183
|
+
});
|
|
114
184
|
export const sessionProvider = z.object({
|
|
115
185
|
provider: providerIdentity,
|
|
116
186
|
providers: z.array(providerIdentity),
|
|
117
187
|
capabilities: z.array(providerCapability),
|
|
188
|
+
analysis_run: analysisRun,
|
|
118
189
|
analysis_provider_binding: z
|
|
119
190
|
.object({
|
|
120
191
|
provider: providerIdentity,
|
|
@@ -133,37 +204,7 @@ export const sessionProvider = z.object({
|
|
|
133
204
|
selected: z.boolean(),
|
|
134
205
|
capabilities: z.array(providerCapability),
|
|
135
206
|
})),
|
|
136
|
-
tool_availability: z.array(
|
|
137
|
-
name: z.string(),
|
|
138
|
-
surface: z.string(),
|
|
139
|
-
available: z.boolean(),
|
|
140
|
-
reason: z.enum([
|
|
141
|
-
"available",
|
|
142
|
-
"target_required",
|
|
143
|
-
"provider_missing",
|
|
144
|
-
"provider_unavailable",
|
|
145
|
-
"target_unsupported",
|
|
146
|
-
"unsupported_host",
|
|
147
|
-
"policy_disabled",
|
|
148
|
-
]),
|
|
149
|
-
remediation: z.string().nullable(),
|
|
150
|
-
effects: z.strictObject({
|
|
151
|
-
mutatesTarget: z.boolean(),
|
|
152
|
-
mutatesSession: z.boolean(),
|
|
153
|
-
writesFilesystem: z.boolean(),
|
|
154
|
-
launchesProcess: z.boolean(),
|
|
155
|
-
accessesNetwork: z.boolean(),
|
|
156
|
-
changesUiState: z.boolean(),
|
|
157
|
-
mayDiscardData: z.boolean(),
|
|
158
|
-
idempotent: z.boolean(),
|
|
159
|
-
}),
|
|
160
|
-
annotations: z.object({
|
|
161
|
-
read_only: z.boolean(),
|
|
162
|
-
destructive: z.boolean(),
|
|
163
|
-
idempotent: z.boolean(),
|
|
164
|
-
open_world: z.boolean(),
|
|
165
|
-
}),
|
|
166
|
-
})),
|
|
207
|
+
tool_availability: z.array(toolAvailability),
|
|
167
208
|
client_features: z.object({
|
|
168
209
|
elicitation_form: z.boolean(),
|
|
169
210
|
elicitation_url: z.boolean(),
|
package/dist/doctorRuntime.js
CHANGED
|
@@ -1,12 +1,53 @@
|
|
|
1
1
|
import { systemDoctorHost, } from "./application/Doctor.js";
|
|
2
|
+
import { fileURLToPath } from "node:url";
|
|
2
3
|
import { inspectSystemGhidraProvider } from "./ghidra/GhidraDoctor.js";
|
|
4
|
+
import { selectLinuxPrivateDisplayStrategy } from "./hopper/LinuxPrivateDisplayProbe.js";
|
|
3
5
|
import { parseConfig } from "./config.js";
|
|
4
6
|
import { SystemJavaScriptReplayHost } from "./replay/SystemJavaScriptReplayHost.js";
|
|
5
7
|
/** Compose provider diagnostics at the outer CLI adapter boundary. */
|
|
6
8
|
export const createSystemDoctorHost = () => systemDoctorHost({
|
|
7
9
|
providerInspections: async () => [await inspectSystemGhidraProvider()],
|
|
8
10
|
javascriptReplayCheck: inspectJavaScriptReplay,
|
|
11
|
+
linuxDemoRuntimeCheck: inspectLinuxPrivateDisplay,
|
|
9
12
|
});
|
|
13
|
+
const HOPPER_DEMO_HELPER_PATH = fileURLToPath(new URL("../scripts/hopper-demo-x11.py", import.meta.url));
|
|
14
|
+
const inspectLinuxPrivateDisplay = async () => {
|
|
15
|
+
const selection = await selectLinuxPrivateDisplayStrategy({
|
|
16
|
+
helperPath: HOPPER_DEMO_HELPER_PATH,
|
|
17
|
+
});
|
|
18
|
+
const value = selection.diagnostic;
|
|
19
|
+
const detail = [
|
|
20
|
+
`strategy=${selection.strategy}`,
|
|
21
|
+
`socket_directory=${value.socket_directory}`,
|
|
22
|
+
`mode=${value.socket_directory_mode ?? "unknown"}`,
|
|
23
|
+
`mount_read_only=${String(value.mount_read_only)}`,
|
|
24
|
+
`effective_mode=${value.effective_socket_directory_mode ?? "unknown"}`,
|
|
25
|
+
`effective_mount_read_only=${String(value.effective_mount_read_only)}`,
|
|
26
|
+
`wsl=${String(value.wsl)}`,
|
|
27
|
+
].join("; ");
|
|
28
|
+
if (selection.ok)
|
|
29
|
+
return {
|
|
30
|
+
name: "hopper-demo-runtime",
|
|
31
|
+
ok: true,
|
|
32
|
+
classification: "healthy",
|
|
33
|
+
detail,
|
|
34
|
+
details: { private_display: { ...value } },
|
|
35
|
+
};
|
|
36
|
+
const missingDependency = value.failure_code === "runtime_dependency_unavailable" ||
|
|
37
|
+
value.failure_code === "x11_authorization_failed";
|
|
38
|
+
return {
|
|
39
|
+
name: "hopper-demo-runtime",
|
|
40
|
+
ok: false,
|
|
41
|
+
classification: missingDependency ? "missing_dependency" : "config_drift",
|
|
42
|
+
detail,
|
|
43
|
+
details: { private_display: { ...value } },
|
|
44
|
+
remediation: value.failure_code === "x11_socket_directory_unusable"
|
|
45
|
+
? "Enable unprivileged user and mount namespaces, or provide a writable mode-1777 /tmp/.X11-unix directory. Do not mutate the current host mount with sudo; then rerun rea doctor --provider hopper."
|
|
46
|
+
: missingDependency
|
|
47
|
+
? "Install Xvfb, xauth, Python 3, libX11, and libXtst, then rerun rea doctor --provider hopper."
|
|
48
|
+
: "Inspect the private-display diagnostic, correct the reported local condition, and rerun rea doctor --provider hopper.",
|
|
49
|
+
};
|
|
50
|
+
};
|
|
10
51
|
const inspectJavaScriptReplay = async () => {
|
|
11
52
|
const config = parseConfig(process.env);
|
|
12
53
|
if (!config.ok)
|
|
@@ -5,9 +5,11 @@ export const analysisErrorRemediationAction = (error) => {
|
|
|
5
5
|
if (error instanceof ReplayPlanStaleError)
|
|
6
6
|
return "Review the rebuilt replay plan and explicitly approve its new digest.";
|
|
7
7
|
if (error instanceof PermissionRequiredError)
|
|
8
|
-
return error.
|
|
9
|
-
? "
|
|
10
|
-
:
|
|
8
|
+
return error.restartRequired
|
|
9
|
+
? "Add the exact missing scope to the administrator configuration, then restart the registered MCP server or client."
|
|
10
|
+
: error.elicitationSupported
|
|
11
|
+
? "Approve the exact missing scope, then retry the operation."
|
|
12
|
+
: "Add the exact missing scope beneath the administrator ceiling, then retry.";
|
|
11
13
|
return analysisErrorUserMessage(error);
|
|
12
14
|
};
|
|
13
15
|
export const analysisErrorCategory = (error) => {
|
|
@@ -230,7 +230,13 @@ const providerErrorDetails = (error) => {
|
|
|
230
230
|
if (error instanceof HopperRemoteError)
|
|
231
231
|
return { provider_code: error.code, diagnostic_type: error.diagnosticType };
|
|
232
232
|
if (error instanceof HopperProcessError && error.failureCode !== undefined)
|
|
233
|
-
return {
|
|
233
|
+
return {
|
|
234
|
+
failure_code: error.failureCode,
|
|
235
|
+
exit_code: error.exitCode,
|
|
236
|
+
...(error.diagnostic === undefined
|
|
237
|
+
? {}
|
|
238
|
+
: { diagnostics: { ...error.diagnostic } }),
|
|
239
|
+
};
|
|
234
240
|
return undefined;
|
|
235
241
|
};
|
|
236
242
|
const lifecycleErrorDetails = (error) => {
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import canonicalize from "canonicalize";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { parseArtifactInventoryEvidence } from "./artifactInventoryEvidence.js";
|
|
5
|
+
import { projectBoundedCartesian } from "./boundedCartesianProjection.js";
|
|
6
|
+
import { evidenceSchema } from "./evidence.js";
|
|
7
|
+
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
8
|
+
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
9
|
+
const pathSchema = z.string().min(1).max(4_096);
|
|
10
|
+
const componentSchema = z.strictObject({
|
|
11
|
+
path: pathSchema,
|
|
12
|
+
artifact_id: z.string().regex(/^art_[a-f0-9]{64}$/u),
|
|
13
|
+
sha256: digestSchema,
|
|
14
|
+
format: z.string().min(1).max(100),
|
|
15
|
+
});
|
|
16
|
+
/** Authenticated APK inventory pages projected as one Android application. */
|
|
17
|
+
export const androidApplicationProjectionInputSchema = z.strictObject({
|
|
18
|
+
inventory_evidence: z.array(evidenceSchema).min(1).max(100),
|
|
19
|
+
limits: z
|
|
20
|
+
.strictObject({
|
|
21
|
+
max_components: z.number().int().min(1).max(10_000).default(1_000),
|
|
22
|
+
})
|
|
23
|
+
.default({ max_components: 1_000 }),
|
|
24
|
+
});
|
|
25
|
+
/** Deterministic, execution-free Android application inventory projection. */
|
|
26
|
+
export const androidApplicationProjectionResultSchema = z.strictObject({
|
|
27
|
+
schema_version: z.literal(1),
|
|
28
|
+
projection_id: z.string().regex(/^adp_[a-f0-9]{64}$/u),
|
|
29
|
+
root_sha256: digestSchema,
|
|
30
|
+
root_format: z.literal("apk"),
|
|
31
|
+
source_evidence_ids: z.array(evidenceIdSchema).min(1).max(100),
|
|
32
|
+
components: z.strictObject({
|
|
33
|
+
manifests: z.array(componentSchema),
|
|
34
|
+
resources: z.array(componentSchema),
|
|
35
|
+
dex: z.array(componentSchema),
|
|
36
|
+
jvm_classes: z.array(componentSchema),
|
|
37
|
+
native_libraries: z.array(componentSchema),
|
|
38
|
+
javascript: z.array(componentSchema),
|
|
39
|
+
signing: z.array(componentSchema),
|
|
40
|
+
}),
|
|
41
|
+
runtime_families: z.array(z.enum([
|
|
42
|
+
"dalvik-art",
|
|
43
|
+
"java-kotlin",
|
|
44
|
+
"native",
|
|
45
|
+
"javascript",
|
|
46
|
+
"react-native",
|
|
47
|
+
"flutter",
|
|
48
|
+
"unity",
|
|
49
|
+
])),
|
|
50
|
+
bridge_candidates: z.array(z.strictObject({
|
|
51
|
+
managed_path: pathSchema,
|
|
52
|
+
native_path: pathSchema,
|
|
53
|
+
basis: z.enum([
|
|
54
|
+
"managed-and-native-content",
|
|
55
|
+
"jni-library-convention",
|
|
56
|
+
"react-native-convention",
|
|
57
|
+
"flutter-convention",
|
|
58
|
+
"unity-convention",
|
|
59
|
+
]),
|
|
60
|
+
})),
|
|
61
|
+
coverage: z.strictObject({
|
|
62
|
+
status: z.enum(["complete-within-inventory", "partial", "truncated"]),
|
|
63
|
+
inventory_complete: z.boolean(),
|
|
64
|
+
omitted_components: z.number().int().min(0),
|
|
65
|
+
omitted_bridge_candidates: z.number().int().min(0),
|
|
66
|
+
}),
|
|
67
|
+
limitations: z.array(z.string().min(1).max(4_096)).max(100),
|
|
68
|
+
});
|
|
69
|
+
/** Project exact APK paths and hashes without decoding or executing target code. */
|
|
70
|
+
export const projectAndroidApplication = (input) => {
|
|
71
|
+
const parsed = androidApplicationProjectionInputSchema.parse(input);
|
|
72
|
+
const { evidence, inventory } = parseArtifactInventoryEvidence(parsed.inventory_evidence);
|
|
73
|
+
if (inventory.manifest.root_format !== "apk")
|
|
74
|
+
throw new TypeError("Android application projection requires APK Evidence");
|
|
75
|
+
const nodes = new Map(inventory.nodes.map((node) => [node.artifact_id, node]));
|
|
76
|
+
const all = inventory.occurrences
|
|
77
|
+
.filter((occurrence) => occurrence.artifact_id !== null && occurrence.logical_path !== ".")
|
|
78
|
+
.map((occurrence) => {
|
|
79
|
+
const node = nodes.get(occurrence.artifact_id ?? "");
|
|
80
|
+
if (node === undefined)
|
|
81
|
+
throw new TypeError("Android application occurrence has no artifact node");
|
|
82
|
+
return {
|
|
83
|
+
path: occurrence.logical_path,
|
|
84
|
+
artifact_id: node.artifact_id,
|
|
85
|
+
sha256: node.sha256,
|
|
86
|
+
format: node.format,
|
|
87
|
+
};
|
|
88
|
+
});
|
|
89
|
+
const classified = classify(all);
|
|
90
|
+
const components = retain(classified, parsed.limits.max_components);
|
|
91
|
+
const omittedComponents = count(classified) - count(components);
|
|
92
|
+
const bridgeProjection = bridgeCandidates([...components.dex, ...components.jvm_classes], components.native_libraries, parsed.limits.max_components);
|
|
93
|
+
const limitations = [
|
|
94
|
+
...(!inventory.complete
|
|
95
|
+
? ["Source inventory pages are incomplete; absence is unknown."]
|
|
96
|
+
: []),
|
|
97
|
+
...(omittedComponents > 0
|
|
98
|
+
? [
|
|
99
|
+
`${String(omittedComponents)} component observations were omitted by the projection limit.`,
|
|
100
|
+
]
|
|
101
|
+
: []),
|
|
102
|
+
...(bridgeProjection.omitted > 0
|
|
103
|
+
? [
|
|
104
|
+
`${String(bridgeProjection.omitted)} bridge hypotheses were omitted by the projection limit.`,
|
|
105
|
+
]
|
|
106
|
+
: []),
|
|
107
|
+
"Manifest, resource, signing, and bytecode semantics require a dedicated Android provider; this projection reports exact inventory paths and hashes only.",
|
|
108
|
+
"Bridge candidates are path-based hypotheses, not decoded JNI declarations or observed runtime calls.",
|
|
109
|
+
];
|
|
110
|
+
const withoutId = {
|
|
111
|
+
schema_version: 1,
|
|
112
|
+
root_sha256: inventory.manifest.root_sha256,
|
|
113
|
+
root_format: "apk",
|
|
114
|
+
source_evidence_ids: evidence
|
|
115
|
+
.map(({ evidence_id: id }) => id)
|
|
116
|
+
.sort(compare),
|
|
117
|
+
components,
|
|
118
|
+
runtime_families: runtimeFamilies(all),
|
|
119
|
+
bridge_candidates: bridgeProjection.candidates,
|
|
120
|
+
coverage: {
|
|
121
|
+
status: omittedComponents > 0 || bridgeProjection.omitted > 0
|
|
122
|
+
? "truncated"
|
|
123
|
+
: inventory.complete
|
|
124
|
+
? "complete-within-inventory"
|
|
125
|
+
: "partial",
|
|
126
|
+
inventory_complete: inventory.complete,
|
|
127
|
+
omitted_components: omittedComponents,
|
|
128
|
+
omitted_bridge_candidates: bridgeProjection.omitted,
|
|
129
|
+
},
|
|
130
|
+
limitations,
|
|
131
|
+
};
|
|
132
|
+
return androidApplicationProjectionResultSchema.parse({
|
|
133
|
+
...withoutId,
|
|
134
|
+
projection_id: `adp_${digest(withoutId)}`,
|
|
135
|
+
});
|
|
136
|
+
};
|
|
137
|
+
const classify = (all) => ({
|
|
138
|
+
manifests: all.filter(({ path, format }) => format === "android-manifest" ||
|
|
139
|
+
/(?:^|\/)AndroidManifest\.xml$/u.test(path)),
|
|
140
|
+
resources: all.filter(({ path, format }) => format === "android-resources" || /(?:^|\/)resources\.arsc$/u.test(path)),
|
|
141
|
+
dex: all.filter(({ path, format }) => format === "dex" || /(?:^|\/)[^/]+\.dex$/iu.test(path)),
|
|
142
|
+
jvm_classes: all.filter(({ path, format }) => format === "jvm-class" || /(?:^|\/)[^/]+\.class$/iu.test(path)),
|
|
143
|
+
native_libraries: all.filter(({ path, format }) => format === "elf" || /(?:^|\/)lib\/[^/]+\/[^/]+\.so$/iu.test(path)),
|
|
144
|
+
javascript: all.filter(({ format }) => format === "javascript-bundle"),
|
|
145
|
+
signing: all.filter(({ path }) => /^META-INF\/[^/]+\.(?:MF|RSA|DSA|EC|SF)$/iu.test(path)),
|
|
146
|
+
});
|
|
147
|
+
const retain = (groups, maximum) => {
|
|
148
|
+
let remaining = maximum;
|
|
149
|
+
return Object.fromEntries(Object.entries(groups).map(([key, values]) => {
|
|
150
|
+
const selected = [...values]
|
|
151
|
+
.sort((left, right) => compare(left.path, right.path))
|
|
152
|
+
.slice(0, remaining);
|
|
153
|
+
remaining -= selected.length;
|
|
154
|
+
return [key, selected];
|
|
155
|
+
}));
|
|
156
|
+
};
|
|
157
|
+
const count = (groups) => Object.values(groups).reduce((total, values) => total + values.length, 0);
|
|
158
|
+
const runtimeFamilies = (all) => {
|
|
159
|
+
const paths = all.map(({ path }) => path.toLowerCase());
|
|
160
|
+
const families = new Set();
|
|
161
|
+
if (all.some(({ path, format }) => format === "dex" || path.endsWith(".dex")))
|
|
162
|
+
families.add("dalvik-art");
|
|
163
|
+
if (all.some(({ path, format }) => format === "jvm-class" || path.endsWith(".class")))
|
|
164
|
+
families.add("java-kotlin");
|
|
165
|
+
if (all.some(({ format }) => format === "elf"))
|
|
166
|
+
families.add("native");
|
|
167
|
+
if (all.some(({ format }) => format === "javascript-bundle"))
|
|
168
|
+
families.add("javascript");
|
|
169
|
+
if (paths.some((path) => path.includes("reactnative") || path.includes("hermes")))
|
|
170
|
+
families.add("react-native");
|
|
171
|
+
if (paths.some((path) => path.includes("libflutter.so")))
|
|
172
|
+
families.add("flutter");
|
|
173
|
+
if (paths.some((path) => path.includes("libunity.so")))
|
|
174
|
+
families.add("unity");
|
|
175
|
+
return [...families].sort(compare);
|
|
176
|
+
};
|
|
177
|
+
const bridgeCandidates = (managed, native, maximum) => {
|
|
178
|
+
const projection = projectBoundedCartesian(managed, native, maximum, (source, target) => ({
|
|
179
|
+
managed_path: source.path,
|
|
180
|
+
native_path: target.path,
|
|
181
|
+
basis: bridgeBasis(target.path),
|
|
182
|
+
}));
|
|
183
|
+
return {
|
|
184
|
+
candidates: projection.values,
|
|
185
|
+
omitted: projection.omitted,
|
|
186
|
+
};
|
|
187
|
+
};
|
|
188
|
+
const bridgeBasis = (path) => {
|
|
189
|
+
const lower = path.toLowerCase();
|
|
190
|
+
if (lower.includes("react") || lower.includes("hermes"))
|
|
191
|
+
return "react-native-convention";
|
|
192
|
+
if (lower.includes("flutter"))
|
|
193
|
+
return "flutter-convention";
|
|
194
|
+
if (lower.includes("unity"))
|
|
195
|
+
return "unity-convention";
|
|
196
|
+
if (/lib\/[^/]+\/lib[^/]+\.so$/u.test(lower))
|
|
197
|
+
return "jni-library-convention";
|
|
198
|
+
return "managed-and-native-content";
|
|
199
|
+
};
|
|
200
|
+
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
201
|
+
const digest = (value) => {
|
|
202
|
+
const encoded = canonicalize(value);
|
|
203
|
+
if (encoded === undefined)
|
|
204
|
+
throw new TypeError("Android application projection is not canonical JSON");
|
|
205
|
+
return createHash("sha256").update(encoded).digest("hex");
|
|
206
|
+
};
|
|
@@ -0,0 +1,221 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import canonicalize from "canonicalize";
|
|
3
|
+
import { z } from "zod";
|
|
4
|
+
import { parseArtifactInventoryEvidence } from "./artifactInventoryEvidence.js";
|
|
5
|
+
import { projectBoundedCartesian } from "./boundedCartesianProjection.js";
|
|
6
|
+
import { evidenceSchema } from "./evidence.js";
|
|
7
|
+
const digestSchema = z.string().regex(/^[a-f0-9]{64}$/u);
|
|
8
|
+
const evidenceIdSchema = z.string().regex(/^ev_[a-f0-9]{64}$/u);
|
|
9
|
+
const boundedPathSchema = z.string().min(1).max(4_096);
|
|
10
|
+
const componentSchema = z.strictObject({
|
|
11
|
+
path: boundedPathSchema,
|
|
12
|
+
artifact_id: z.string().regex(/^art_[a-f0-9]{64}$/u),
|
|
13
|
+
sha256: digestSchema,
|
|
14
|
+
format: z.string().min(1).max(100),
|
|
15
|
+
});
|
|
16
|
+
/** Authenticated artifact inventory pages projected as one Apple application. */
|
|
17
|
+
export const appleApplicationProjectionInputSchema = z.strictObject({
|
|
18
|
+
inventory_evidence: z.array(evidenceSchema).min(1).max(100),
|
|
19
|
+
limits: z
|
|
20
|
+
.strictObject({
|
|
21
|
+
max_components: z.number().int().min(1).max(10_000).default(1_000),
|
|
22
|
+
})
|
|
23
|
+
.default({ max_components: 1_000 }),
|
|
24
|
+
});
|
|
25
|
+
/** Deterministic, execution-free Apple application inventory projection. */
|
|
26
|
+
export const appleApplicationProjectionResultSchema = z.strictObject({
|
|
27
|
+
schema_version: z.literal(1),
|
|
28
|
+
projection_id: z.string().regex(/^aap_[a-f0-9]{64}$/u),
|
|
29
|
+
root_sha256: digestSchema,
|
|
30
|
+
root_format: z.literal("ipa"),
|
|
31
|
+
source_evidence_ids: z.array(evidenceIdSchema).min(1).max(100),
|
|
32
|
+
application_roots: z.array(boundedPathSchema),
|
|
33
|
+
components: z.strictObject({
|
|
34
|
+
bundle_metadata: z.array(componentSchema),
|
|
35
|
+
executables: z.array(componentSchema),
|
|
36
|
+
frameworks: z.array(componentSchema),
|
|
37
|
+
native_libraries: z.array(componentSchema),
|
|
38
|
+
javascript: z.array(componentSchema),
|
|
39
|
+
signing: z.array(componentSchema),
|
|
40
|
+
}),
|
|
41
|
+
runtime_families: z.array(z.enum([
|
|
42
|
+
"native",
|
|
43
|
+
"swift-objective-c",
|
|
44
|
+
"javascript",
|
|
45
|
+
"react-native",
|
|
46
|
+
"flutter",
|
|
47
|
+
"unity",
|
|
48
|
+
])),
|
|
49
|
+
bridge_candidates: z.array(z.strictObject({
|
|
50
|
+
source_path: boundedPathSchema,
|
|
51
|
+
native_path: boundedPathSchema,
|
|
52
|
+
basis: z.enum([
|
|
53
|
+
"javascript-and-native-content",
|
|
54
|
+
"react-native-convention",
|
|
55
|
+
"flutter-convention",
|
|
56
|
+
"unity-convention",
|
|
57
|
+
]),
|
|
58
|
+
})),
|
|
59
|
+
coverage: z.strictObject({
|
|
60
|
+
status: z.enum(["complete-within-inventory", "partial", "truncated"]),
|
|
61
|
+
inventory_complete: z.boolean(),
|
|
62
|
+
omitted_components: z.number().int().min(0),
|
|
63
|
+
omitted_bridge_candidates: z.number().int().min(0),
|
|
64
|
+
}),
|
|
65
|
+
limitations: z.array(z.string().min(1).max(4_096)).max(100),
|
|
66
|
+
});
|
|
67
|
+
/** Project exact IPA paths and hashes without parsing or executing target code. */
|
|
68
|
+
export const projectAppleApplication = (input) => {
|
|
69
|
+
const parsed = appleApplicationProjectionInputSchema.parse(input);
|
|
70
|
+
const { evidence, inventory } = parseArtifactInventoryEvidence(parsed.inventory_evidence);
|
|
71
|
+
if (inventory.manifest.root_format !== "ipa")
|
|
72
|
+
throw new TypeError("Apple application projection requires IPA Evidence");
|
|
73
|
+
const nodes = new Map(inventory.nodes.map((node) => [node.artifact_id, node]));
|
|
74
|
+
const all = inventory.occurrences
|
|
75
|
+
.filter((occurrence) => occurrence.artifact_id !== null && occurrence.logical_path !== ".")
|
|
76
|
+
.map((occurrence) => {
|
|
77
|
+
const node = nodes.get(occurrence.artifact_id ?? "");
|
|
78
|
+
if (node === undefined)
|
|
79
|
+
throw new TypeError("Apple application occurrence has no artifact node");
|
|
80
|
+
return {
|
|
81
|
+
path: occurrence.logical_path,
|
|
82
|
+
artifact_id: node.artifact_id,
|
|
83
|
+
sha256: node.sha256,
|
|
84
|
+
format: node.format,
|
|
85
|
+
};
|
|
86
|
+
});
|
|
87
|
+
const roots = [
|
|
88
|
+
...new Set(inventory.occurrences.flatMap(({ logical_path: path }) => {
|
|
89
|
+
const match = /^(Payload\/[^/]+\.app)(?:\/|$)/u.exec(path);
|
|
90
|
+
return match?.[1] === undefined ? [] : [match[1]];
|
|
91
|
+
})),
|
|
92
|
+
].sort(compare);
|
|
93
|
+
const classified = classifyComponents(all, roots);
|
|
94
|
+
const retained = retainComponents(classified, parsed.limits.max_components);
|
|
95
|
+
const omitted = componentCount(classified) - componentCount(retained);
|
|
96
|
+
const runtimeFamilies = identifyRuntimeFamilies(all);
|
|
97
|
+
const bridgeProjection = identifyBridgeCandidates(retained.javascript, deduplicateComponents([
|
|
98
|
+
...retained.executables,
|
|
99
|
+
...retained.native_libraries,
|
|
100
|
+
]), parsed.limits.max_components);
|
|
101
|
+
const limitations = projectionLimitations(inventory.complete, omitted, bridgeProjection.omitted, roots);
|
|
102
|
+
const withoutId = {
|
|
103
|
+
schema_version: 1,
|
|
104
|
+
root_sha256: inventory.manifest.root_sha256,
|
|
105
|
+
root_format: "ipa",
|
|
106
|
+
source_evidence_ids: evidence
|
|
107
|
+
.map(({ evidence_id: id }) => id)
|
|
108
|
+
.sort(compare),
|
|
109
|
+
application_roots: roots,
|
|
110
|
+
components: retained,
|
|
111
|
+
runtime_families: runtimeFamilies,
|
|
112
|
+
bridge_candidates: bridgeProjection.candidates,
|
|
113
|
+
coverage: {
|
|
114
|
+
status: omitted > 0 || bridgeProjection.omitted > 0
|
|
115
|
+
? "truncated"
|
|
116
|
+
: inventory.complete
|
|
117
|
+
? "complete-within-inventory"
|
|
118
|
+
: "partial",
|
|
119
|
+
inventory_complete: inventory.complete,
|
|
120
|
+
omitted_components: omitted,
|
|
121
|
+
omitted_bridge_candidates: bridgeProjection.omitted,
|
|
122
|
+
},
|
|
123
|
+
limitations,
|
|
124
|
+
};
|
|
125
|
+
return appleApplicationProjectionResultSchema.parse({
|
|
126
|
+
...withoutId,
|
|
127
|
+
projection_id: `aap_${digest(withoutId)}`,
|
|
128
|
+
});
|
|
129
|
+
};
|
|
130
|
+
const classifyComponents = (all, roots) => {
|
|
131
|
+
const withinApp = (path) => roots.some((root) => path.startsWith(`${root}/`));
|
|
132
|
+
return {
|
|
133
|
+
bundle_metadata: all.filter(({ path }) => /(?:^|\/)Info\.plist$/u.test(path)),
|
|
134
|
+
executables: all.filter(({ path, format }) => withinApp(path) && ["mach-o", "mach-o-universal"].includes(format)),
|
|
135
|
+
frameworks: all.filter(({ path }) => /\.framework\//u.test(path)),
|
|
136
|
+
native_libraries: all.filter(({ path }) => /\.(?:dylib|so)$/iu.test(path)),
|
|
137
|
+
javascript: all.filter(({ format }) => format === "javascript-bundle"),
|
|
138
|
+
signing: all.filter(({ path }) => /(?:^|\/)(?:embedded\.mobileprovision|_CodeSignature\/CodeResources)$/u.test(path)),
|
|
139
|
+
};
|
|
140
|
+
};
|
|
141
|
+
const retainComponents = (groups, maximum) => {
|
|
142
|
+
let remaining = maximum;
|
|
143
|
+
return Object.fromEntries(Object.entries(groups).map(([key, values]) => {
|
|
144
|
+
const retained = [...values]
|
|
145
|
+
.sort((left, right) => compare(left.path, right.path))
|
|
146
|
+
.slice(0, remaining);
|
|
147
|
+
remaining -= retained.length;
|
|
148
|
+
return [key, retained];
|
|
149
|
+
}));
|
|
150
|
+
};
|
|
151
|
+
const componentCount = (groups) => Object.values(groups).reduce((total, values) => total + values.length, 0);
|
|
152
|
+
const deduplicateComponents = (values) => [...new Map(values.map((value) => [value.path, value])).values()].sort((left, right) => compare(left.path, right.path));
|
|
153
|
+
const identifyRuntimeFamilies = (all) => {
|
|
154
|
+
const paths = all.map(({ path }) => path.toLowerCase());
|
|
155
|
+
const families = new Set();
|
|
156
|
+
if (all.some(({ format }) => ["mach-o", "mach-o-universal"].includes(format)))
|
|
157
|
+
families.add("native");
|
|
158
|
+
if (paths.some((path) => /\.(?:dylib|framework\/[^/]+)$/u.test(path)))
|
|
159
|
+
families.add("swift-objective-c");
|
|
160
|
+
if (all.some(({ format }) => format === "javascript-bundle"))
|
|
161
|
+
families.add("javascript");
|
|
162
|
+
if (paths.some((path) => path.includes("reactnative") ||
|
|
163
|
+
path.includes("react.framework") ||
|
|
164
|
+
path.includes("hermes")))
|
|
165
|
+
families.add("react-native");
|
|
166
|
+
if (paths.some((path) => path.includes("flutter.framework") || path.includes("app.framework")))
|
|
167
|
+
families.add("flutter");
|
|
168
|
+
if (paths.some((path) => path.includes("unityframework.framework")))
|
|
169
|
+
families.add("unity");
|
|
170
|
+
return [...families].sort(compare);
|
|
171
|
+
};
|
|
172
|
+
const identifyBridgeCandidates = (scripts, native, maximum) => {
|
|
173
|
+
const projection = projectBoundedCartesian(scripts, native, maximum, (script, item) => ({
|
|
174
|
+
source_path: script.path,
|
|
175
|
+
native_path: item.path,
|
|
176
|
+
basis: bridgeBasis(item.path),
|
|
177
|
+
}));
|
|
178
|
+
return {
|
|
179
|
+
candidates: projection.values,
|
|
180
|
+
omitted: projection.omitted,
|
|
181
|
+
};
|
|
182
|
+
};
|
|
183
|
+
const bridgeBasis = (path) => {
|
|
184
|
+
const lower = path.toLowerCase();
|
|
185
|
+
if (lower.includes("react"))
|
|
186
|
+
return "react-native-convention";
|
|
187
|
+
if (lower.includes("flutter") || lower.includes("app.framework"))
|
|
188
|
+
return "flutter-convention";
|
|
189
|
+
if (lower.includes("unity"))
|
|
190
|
+
return "unity-convention";
|
|
191
|
+
return "javascript-and-native-content";
|
|
192
|
+
};
|
|
193
|
+
const projectionLimitations = (complete, omitted, omittedBridges, roots) => [
|
|
194
|
+
...(!complete
|
|
195
|
+
? ["Source inventory pages are incomplete; absence is unknown."]
|
|
196
|
+
: []),
|
|
197
|
+
...(omitted > 0
|
|
198
|
+
? [
|
|
199
|
+
`${String(omitted)} component observations were omitted by the projection limit.`,
|
|
200
|
+
]
|
|
201
|
+
: []),
|
|
202
|
+
...(omittedBridges > 0
|
|
203
|
+
? [
|
|
204
|
+
`${String(omittedBridges)} bridge hypotheses were omitted by the projection limit.`,
|
|
205
|
+
]
|
|
206
|
+
: []),
|
|
207
|
+
...(roots.length === 0
|
|
208
|
+
? [
|
|
209
|
+
"No Payload/*.app directory was present in the supplied inventory pages.",
|
|
210
|
+
]
|
|
211
|
+
: []),
|
|
212
|
+
"Bundle identifiers and signing claims require dedicated plist and CMS parsing; this projection reports only exact paths and hashes.",
|
|
213
|
+
"Bridge candidates are path-based hypotheses, not observed runtime calls.",
|
|
214
|
+
];
|
|
215
|
+
const compare = (left, right) => left < right ? -1 : left > right ? 1 : 0;
|
|
216
|
+
const digest = (value) => {
|
|
217
|
+
const encoded = canonicalize(value);
|
|
218
|
+
if (encoded === undefined)
|
|
219
|
+
throw new TypeError("Apple application projection is not canonical JSON");
|
|
220
|
+
return createHash("sha256").update(encoded).digest("hex");
|
|
221
|
+
};
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Project a Cartesian product without materializing values beyond the output limit. */
|
|
2
|
+
export const projectBoundedCartesian = (left, right, maximum, project) => {
|
|
3
|
+
const values = [];
|
|
4
|
+
for (const leftValue of left) {
|
|
5
|
+
for (const rightValue of right) {
|
|
6
|
+
if (values.length === maximum)
|
|
7
|
+
return {
|
|
8
|
+
values,
|
|
9
|
+
omitted: left.length * right.length - values.length,
|
|
10
|
+
};
|
|
11
|
+
values.push(project(leftValue, rightValue));
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
return { values, omitted: 0 };
|
|
15
|
+
};
|