rea-agents 2.4.0 → 3.0.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.
Files changed (231) hide show
  1. package/README.md +91 -19
  2. package/bridge/ghidra/ReaGhidraBridge.java +524 -4
  3. package/bridge/hopper_bridge.py +313 -28
  4. package/dist/application/AnalysisClientCleanup.js +14 -0
  5. package/dist/application/AnalysisContextQueries.js +130 -0
  6. package/dist/application/AnalysisSnapshotCache.js +4 -2
  7. package/dist/application/ApplicationWorkflowEvidenceResolver.js +31 -13
  8. package/dist/application/ArtifactInventory/scanCanonical.js +1 -1
  9. package/dist/application/BinarySession.js +20 -8
  10. package/dist/application/BinarySessionComposition.js +21 -0
  11. package/dist/application/BinarySessionRecords.js +79 -9
  12. package/dist/application/BinarySessionStatus.js +31 -1
  13. package/dist/application/BrowserEvidence.js +14 -0
  14. package/dist/application/BrowserScenarioCapturePort.js +1 -0
  15. package/dist/application/BrowserScenarioCaptureService.js +53 -0
  16. package/dist/application/BrowserScenarioEvidence.js +40 -0
  17. package/dist/application/CallPathTracing.js +160 -0
  18. package/dist/application/CapabilityInventory.js +84 -14
  19. package/dist/application/ClientRegistrationStatus.js +4 -1
  20. package/dist/application/CompositeProvider.js +10 -1
  21. package/dist/application/DirectAnalysis.js +13 -4
  22. package/dist/application/EnhancedLiteralTracing.js +118 -0
  23. package/dist/application/EnhancedTools.js +71 -127
  24. package/dist/application/EvidenceLedger.js +45 -16
  25. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +13 -0
  26. package/dist/application/JavaScriptApplicationWorkflowService.js +27 -1
  27. package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
  28. package/dist/application/JavaScriptRuntimeObservationEvidence.js +34 -0
  29. package/dist/application/JavaScriptRuntimeObservationPort.js +1 -0
  30. package/dist/application/JavaScriptRuntimeObservationService.js +46 -0
  31. package/dist/application/JavaScriptSemanticGraphAsyncProjection.js +147 -0
  32. package/dist/application/JavaScriptSemanticGraphBuilder.js +34 -6
  33. package/dist/application/JavaScriptSemanticGraphChildProcessProjection.js +156 -0
  34. package/dist/application/JavaScriptSemanticGraphConstruction.js +2 -2
  35. package/dist/application/JavaScriptSemanticGraphDataProjection.js +203 -0
  36. package/dist/application/JavaScriptSemanticGraphFingerprintProjection.js +25 -0
  37. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +129 -8
  38. package/dist/application/JavaScriptSemanticGraphObjectProjection.js +81 -0
  39. package/dist/application/JavaScriptSemanticGraphProjection.js +14 -7
  40. package/dist/application/JavaScriptSemanticGraphResourceProjection.js +59 -0
  41. package/dist/application/JavaScriptSemanticGraphValueProjection.js +77 -0
  42. package/dist/application/LazyAnalysisProvider.js +77 -0
  43. package/dist/application/LoopbackReplay.js +1 -1
  44. package/dist/application/NativeApiInspection.js +80 -0
  45. package/dist/application/ProcessReactiveEffects.js +6 -0
  46. package/dist/application/ProcessReactiveHarness.js +16 -1
  47. package/dist/application/ProjectPermissionStore.js +1 -0
  48. package/dist/application/ReconstructionObligationAuthority.js +72 -0
  49. package/dist/application/ReconstructionObligationCandidates.js +265 -0
  50. package/dist/application/ReconstructionObligationLedgerDiagnostics.js +47 -0
  51. package/dist/application/ReconstructionObligationLedgerEvaluation.js +263 -0
  52. package/dist/application/ReconstructionObligationLedgerProjection.js +86 -0
  53. package/dist/application/ReconstructionObligationLedgerService.js +72 -0
  54. package/dist/application/ReconstructionObligationOriginalCases.js +33 -0
  55. package/dist/application/ReconstructionObligationPolicies.js +132 -0
  56. package/dist/application/ReconstructionReadinessService.js +48 -0
  57. package/dist/application/SessionProviderRouter.js +6 -6
  58. package/dist/application/SetupClientConfiguration.js +4 -2
  59. package/dist/application/runtime.js +26 -9
  60. package/dist/artifacts/ArtifactProvider.js +87 -22
  61. package/dist/browser/BrowserScenarioSecrets.js +53 -0
  62. package/dist/browser/BrowserScenarioSessionPort.js +1 -0
  63. package/dist/browser/CdpBrowserProvider.js +2 -2
  64. package/dist/browser/CdpCaptureDocuments.js +57 -0
  65. package/dist/browser/CdpCaptureStorage.js +71 -29
  66. package/dist/browser/CdpCaptureStorageFingerprints.js +328 -0
  67. package/dist/browser/CdpEndpoint.js +8 -6
  68. package/dist/browser/CdpPageCapture.js +2 -0
  69. package/dist/browser/JavaScriptRuntimeScope.js +38 -0
  70. package/dist/browser/PlaywrightBrowserScenarioProvider.js +259 -0
  71. package/dist/browser/PlaywrightExecutionBoundary.js +42 -0
  72. package/dist/browser/PlaywrightScenarioActions.js +62 -0
  73. package/dist/browser/PlaywrightScenarioArtifacts.js +238 -0
  74. package/dist/browser/PlaywrightScenarioBrowser.js +144 -0
  75. package/dist/browser/PlaywrightScenarioEvents.js +301 -0
  76. package/dist/browser/PlaywrightScenarioSession.js +300 -0
  77. package/dist/browser/V8InspectorCaptureProjection.js +110 -0
  78. package/dist/browser/V8InspectorEndpoint.js +72 -0
  79. package/dist/browser/V8InspectorProvider.js +267 -0
  80. package/dist/catalogIdentity.js +11 -3
  81. package/dist/cli/artifactCommands.js +44 -3
  82. package/dist/cli/coreAnalysisCommands.js +78 -0
  83. package/dist/cli.js +4 -0
  84. package/dist/cliApplicationCommands.js +30 -2
  85. package/dist/cliBrowserAdvancedCommands.js +17 -5
  86. package/dist/cliBrowserCommands.js +1 -0
  87. package/dist/cliBrowserScenarioCommands.js +43 -0
  88. package/dist/cliCommandNames.js +9 -0
  89. package/dist/cliJavaScriptRuntimeCommands.js +164 -0
  90. package/dist/cliObservationOptions.js +4 -0
  91. package/dist/cliPolicyCommands.js +1 -0
  92. package/dist/config/environment.js +12 -0
  93. package/dist/config/parseConfig.js +88 -17
  94. package/dist/contracts/analysisSearchContract.js +14 -0
  95. package/dist/contracts/applicationToolContracts.js +86 -2
  96. package/dist/contracts/applicationWorkflowInputContracts.js +18 -0
  97. package/dist/contracts/artifactToolContracts.js +29 -2
  98. package/dist/contracts/browserProviderToolContracts.js +7 -0
  99. package/dist/contracts/browserScenarioToolContracts.js +81 -0
  100. package/dist/contracts/browserToolContracts.js +88 -98
  101. package/dist/contracts/enhancedInputs.js +35 -6
  102. package/dist/contracts/functionInstructionContract.js +8 -0
  103. package/dist/contracts/functionWorkflowToolContracts.js +30 -0
  104. package/dist/contracts/hopperMemoryContracts.js +22 -0
  105. package/dist/contracts/javascriptApplicationWorkflowExamples.js +42 -0
  106. package/dist/contracts/javascriptRuntimeObservationToolContracts.js +58 -0
  107. package/dist/contracts/promptContracts.js +14 -15
  108. package/dist/contracts/reconstructionReadinessExample.js +436 -0
  109. package/dist/contracts/toolContractExamples.js +8 -0
  110. package/dist/contracts/toolContractTypes.js +1 -0
  111. package/dist/contracts/toolContracts.js +34 -25
  112. package/dist/contracts/toolEffects.js +25 -0
  113. package/dist/contracts/toolOutputSchemaGroups.js +120 -30
  114. package/dist/contracts/toolOutputSchemaPrimitives.js +37 -0
  115. package/dist/domain/analysisErrorPresentation.js +8 -2
  116. package/dist/domain/analysisErrorProjection.js +9 -0
  117. package/dist/domain/artifactInspection.js +347 -0
  118. package/dist/domain/browserCaptureComparison.js +82 -0
  119. package/dist/domain/browserObservation.js +8 -1
  120. package/dist/domain/browserObservationErrors.js +1 -0
  121. package/dist/domain/browserObservationSchemas.js +26 -0
  122. package/dist/domain/browserScenario.js +165 -0
  123. package/dist/domain/browserScenarioCapture.js +57 -0
  124. package/dist/domain/browserScenarioCaptureValues.js +204 -0
  125. package/dist/domain/browserScenarioDiff.js +324 -0
  126. package/dist/domain/browserScenarioDiffValues.js +157 -0
  127. package/dist/domain/browserScenarioNormalization.js +45 -0
  128. package/dist/domain/browserScenarioValues.js +372 -0
  129. package/dist/domain/bytecodeProvider.js +179 -0
  130. package/dist/domain/conformancePackage.js +169 -0
  131. package/dist/domain/conformanceReplay.js +104 -0
  132. package/dist/domain/conformanceTrustGate.js +193 -0
  133. package/dist/domain/customProtocolCapture.js +137 -0
  134. package/dist/domain/eventProcessTree.js +214 -0
  135. package/dist/domain/evidenceBundle.js +47 -0
  136. package/dist/domain/hopperStartupFailure.js +1 -1
  137. package/dist/domain/hopperValues.js +14 -1
  138. package/dist/domain/inputIssueProjection.js +7 -1
  139. package/dist/domain/javascriptRuntimeObservation.js +170 -0
  140. package/dist/domain/javascriptRuntimeReconciliationParsing.js +120 -2
  141. package/dist/domain/javascriptRuntimeReconciliationResult.js +3 -3
  142. package/dist/domain/javascriptRuntimeReconciliationRuntime.js +2 -2
  143. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  144. package/dist/domain/javascriptSemanticAnalysis.js +13 -16
  145. package/dist/domain/javascriptSemanticAsyncEffects.js +253 -0
  146. package/dist/domain/javascriptSemanticChildProcesses.js +237 -0
  147. package/dist/domain/javascriptSemanticDataEffectHelpers.js +125 -0
  148. package/dist/domain/javascriptSemanticDataEffects.js +284 -0
  149. package/dist/domain/javascriptSemanticDerivedAnalysis.js +41 -0
  150. package/dist/domain/javascriptSemanticFingerprints.js +174 -0
  151. package/dist/domain/javascriptSemanticIr.js +21 -1
  152. package/dist/domain/javascriptSemanticObjects.js +115 -0
  153. package/dist/domain/javascriptSemanticPromises.js +290 -0
  154. package/dist/domain/javascriptSemanticResources.js +136 -0
  155. package/dist/domain/javascriptSourceParser.js +15 -0
  156. package/dist/domain/javascriptStaticAnalysis.js +12 -15
  157. package/dist/domain/javascriptStaticAnalysisBundler.js +38 -0
  158. package/dist/domain/javascriptStaticAnalysisCalls.js +23 -1
  159. package/dist/domain/javascriptStaticAnalysisHelpers.js +8 -0
  160. package/dist/domain/mobileApplicationInvestigation.js +159 -0
  161. package/dist/domain/nativeApiBoundary.js +130 -0
  162. package/dist/domain/objcSwiftMetadata.js +150 -0
  163. package/dist/domain/packageAnalysis.js +123 -0
  164. package/dist/domain/peInspection.js +196 -0
  165. package/dist/domain/processCapture.js +8 -2
  166. package/dist/domain/processReactiveScenario.js +1 -0
  167. package/dist/domain/processReactiveTransition.js +9 -4
  168. package/dist/domain/protocolCapture.js +243 -0
  169. package/dist/domain/providerCleanupError.js +11 -0
  170. package/dist/domain/reconstructionObligationLedgerSchemas.js +278 -0
  171. package/dist/domain/reconstructionReadiness.js +121 -0
  172. package/dist/domain/reconstructionReadinessFindingHelpers.js +17 -0
  173. package/dist/domain/reconstructionReadinessIntegrityFindings.js +118 -0
  174. package/dist/domain/reconstructionReadinessJourneyFindings.js +193 -0
  175. package/dist/domain/reconstructionReadinessSchemas.js +240 -0
  176. package/dist/domain/sourceToBundleComparison.js +335 -0
  177. package/dist/domain/sourceToBundleComparisonSchemas.js +133 -0
  178. package/dist/domain/sourceToBundleSignals.js +202 -0
  179. package/dist/domain/webCaptureDiff.js +141 -27
  180. package/dist/domain/webScreenshot.js +1 -1
  181. package/dist/dotnet/ManagedStaticProvider.js +34 -5
  182. package/dist/generatedMcpToolCatalog.js +37 -0
  183. package/dist/generatedPackageMetadata.js +4 -4
  184. package/dist/ghidra/GhidraDefaults.js +1 -1
  185. package/dist/ghidra/GhidraFunctionValues.js +40 -2
  186. package/dist/ghidra/GhidraProviderCapabilities.js +47 -38
  187. package/dist/hopper/HopperCleanup.js +158 -0
  188. package/dist/hopper/HopperClient.js +93 -99
  189. package/dist/hopper/HopperProvider.js +61 -30
  190. package/dist/hopper/HopperRequestQueue.js +215 -0
  191. package/dist/hopper/HopperResponseStream.js +46 -0
  192. package/dist/hopper/protocol.js +63 -20
  193. package/dist/main/transport.js +24 -27
  194. package/dist/main.js +14 -6
  195. package/dist/mcpDoctor.js +27 -4
  196. package/dist/mcpStartupPolicy.js +14 -0
  197. package/dist/process/ProcessCommandIdentity.js +19 -0
  198. package/dist/process/ProcessOwnership.js +11 -8
  199. package/dist/server/DynamicToolAvailability.js +70 -0
  200. package/dist/server/LazyToolCatalog.js +134 -0
  201. package/dist/server/createServer.js +92 -154
  202. package/dist/server/hydrateServerTools.js +191 -0
  203. package/dist/server/lifecycleProgress.js +10 -0
  204. package/dist/server/permissionFailure.js +12 -0
  205. package/dist/server/registerApplicationTools/compareSourceToBundle.js +35 -0
  206. package/dist/server/registerApplicationTools/helpers.js +11 -7
  207. package/dist/server/registerApplicationTools/obligationLedger.js +27 -0
  208. package/dist/server/registerApplicationTools/readiness.js +55 -0
  209. package/dist/server/registerApplicationTools.js +6 -0
  210. package/dist/server/registerArtifactTools.js +9 -1
  211. package/dist/server/registerBrowserScenarioTool.js +25 -0
  212. package/dist/server/registerBrowserTools.js +2 -2
  213. package/dist/server/registerCloseLifecycleTool.js +57 -0
  214. package/dist/server/registerEnhancedTools.js +28 -7
  215. package/dist/server/registerEvidenceResources.js +54 -101
  216. package/dist/server/registerEvidenceTools.js +9 -2
  217. package/dist/server/registerInvestigationTools.js +1 -2
  218. package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
  219. package/dist/server/registerJavaScriptRuntimeObservationTools.js +37 -0
  220. package/dist/server/registerReconstructionObligationLedgerResource.js +32 -0
  221. package/dist/server/registerReconstructionReadinessResource.js +32 -0
  222. package/dist/server/registerSessionRecordTools.js +82 -12
  223. package/dist/server/registerSessionStatusTool.js +11 -8
  224. package/dist/server/registerSessionTools.js +32 -58
  225. package/dist/server/sessionAvailabilityPolicy.js +10 -8
  226. package/dist/server/toolRegistrationOptions.js +21 -6
  227. package/dist/server/toolResult.js +12 -0
  228. package/package.json +28 -11
  229. package/scripts/package-runner-bootstrap.mjs +72 -0
  230. package/scripts/rea.mjs +11 -1
  231. package/skills/reverse-engineer-anything/SKILL.md +10 -3
@@ -0,0 +1,136 @@
1
+ import * as t from "@babel/types";
2
+ import { semanticStaticPropertyName } from "./javascriptSemanticProjection.js";
3
+ import { resolveSemanticBindingState, } from "./javascriptSemanticState.js";
4
+ import { dataEffectLimitReached, outerDataEffectBinding, traverseDataEffects, } from "./javascriptSemanticDataEffectHelpers.js";
5
+ import { range } from "./javascriptStaticAnalysisHelpers.js";
6
+ const ACQUIRE_METHODS = [
7
+ "open",
8
+ "openSync",
9
+ "createReadStream",
10
+ "createWriteStream",
11
+ "connect",
12
+ "createConnection",
13
+ ];
14
+ const RELEASE_METHODS = ["close", "destroy", "end"];
15
+ /** Recover built-in filesystem/network acquisition and local release handles. */
16
+ export const collectJavaScriptSemanticResources = (program, state, callables) => {
17
+ const context = {
18
+ state,
19
+ callableIds: new Set(callables.map(({ callableId }) => callableId)),
20
+ callableStack: [],
21
+ ancestors: [],
22
+ };
23
+ const acquisitions = collectAcquisitions(program, context);
24
+ return [
25
+ ...acquisitions.map(immutableAcquisition),
26
+ ...collectReleases(program, context, acquisitions),
27
+ ];
28
+ };
29
+ const collectAcquisitions = (program, context) => {
30
+ const output = [];
31
+ traverseDataEffects(program, context, (node) => {
32
+ if (!t.isCallExpression(node) && !t.isOptionalCallExpression(node))
33
+ return;
34
+ const method = acquisitionMethod(node.callee, context.state);
35
+ if (method === null)
36
+ return;
37
+ if (resourceLimitReached(output.length, context.state))
38
+ return;
39
+ output.push({
40
+ node,
41
+ method,
42
+ ownerCallableId: context.callableStack.at(-1) ?? null,
43
+ resultBindingId: outerDataEffectBinding(node, context),
44
+ });
45
+ });
46
+ return output;
47
+ };
48
+ const collectReleases = (program, context, acquisitions) => {
49
+ const byBinding = new Map();
50
+ for (const acquisition of acquisitions) {
51
+ if (acquisition.resultBindingId === null)
52
+ continue;
53
+ const existing = byBinding.get(acquisition.resultBindingId) ?? [];
54
+ existing.push(acquisition);
55
+ byBinding.set(acquisition.resultBindingId, existing);
56
+ }
57
+ const output = [];
58
+ traverseDataEffects(program, context, (node) => {
59
+ if (!t.isCallExpression(node) && !t.isOptionalCallExpression(node))
60
+ return;
61
+ const member = memberCallee(node);
62
+ if (member === null || !t.isIdentifier(member.object))
63
+ return;
64
+ const method = RELEASE_METHODS.find((candidate) => candidate ===
65
+ semanticStaticPropertyName(member.property, member.computed));
66
+ if (method === undefined)
67
+ return;
68
+ const binding = resolveSemanticBindingState(context.state, member.object, member.object.name);
69
+ const linked = binding === undefined ? [] : (byBinding.get(binding.bindingId) ?? []);
70
+ if (linked.length === 0)
71
+ return;
72
+ if (resourceLimitReached(acquisitions.length + output.length, context.state))
73
+ return;
74
+ output.push({
75
+ resourceId: `resource:release:${String(node.start ?? -1)}:${String(node.end ?? -1)}`,
76
+ kind: "release",
77
+ method,
78
+ location: range(node),
79
+ ownerCallableId: context.callableStack.at(-1) ?? null,
80
+ resultBindingId: binding?.bindingId ?? null,
81
+ linkedResourceIds: linked.map(resourceCandidateId).sort(),
82
+ resolution: linked.length === 1 ? "complete" : "partial",
83
+ });
84
+ });
85
+ return output;
86
+ };
87
+ const immutableAcquisition = (candidate) => ({
88
+ resourceId: resourceCandidateId(candidate),
89
+ kind: "acquire",
90
+ method: candidate.method,
91
+ location: range(candidate.node),
92
+ ownerCallableId: candidate.ownerCallableId,
93
+ resultBindingId: candidate.resultBindingId,
94
+ linkedResourceIds: [],
95
+ resolution: "complete",
96
+ });
97
+ const acquisitionMethod = (callee, state) => {
98
+ if (t.isIdentifier(callee)) {
99
+ const binding = resolveSemanticBindingState(state, callee, callee.name);
100
+ return methodFromBinding(binding);
101
+ }
102
+ if (!t.isMemberExpression(callee) && !t.isOptionalMemberExpression(callee))
103
+ return null;
104
+ const method = ACQUIRE_METHODS.find((candidate) => candidate ===
105
+ semanticStaticPropertyName(callee.property, callee.computed));
106
+ if (method === undefined || !t.isIdentifier(callee.object))
107
+ return null;
108
+ const binding = resolveSemanticBindingState(state, callee.object, callee.object.name);
109
+ return resourceNamespace(binding) ? method : null;
110
+ };
111
+ const methodFromBinding = (binding) => {
112
+ for (const { specifier, importedPath } of binding?.directOrigins ?? []) {
113
+ if (!resourceModule(specifier))
114
+ continue;
115
+ const method = ACQUIRE_METHODS.find((candidate) => candidate === importedPath.at(-1));
116
+ if (method !== undefined)
117
+ return method;
118
+ }
119
+ return null;
120
+ };
121
+ const resourceNamespace = (binding) => binding?.directOrigins.some(({ specifier, importedPath }) => resourceModule(specifier) && importedPath.length === 0) ?? false;
122
+ const resourceModule = (specifier) => [
123
+ "fs",
124
+ "fs/promises",
125
+ "net",
126
+ "node:fs",
127
+ "node:fs/promises",
128
+ "node:net",
129
+ "node:tls",
130
+ "tls",
131
+ ].includes(specifier);
132
+ const resourceLimitReached = (retained, state) => dataEffectLimitReached(retained, state.limits.maxResourceOperations, "maxResourceOperations", state);
133
+ const resourceCandidateId = (candidate) => `resource:acquire:${String(candidate.node.start ?? -1)}:${String(candidate.node.end ?? -1)}`;
134
+ const memberCallee = (node) => t.isMemberExpression(node.callee) || t.isOptionalMemberExpression(node.callee)
135
+ ? node.callee
136
+ : null;
@@ -0,0 +1,15 @@
1
+ import { parse } from "@babel/parser";
2
+ /** Parse JavaScript or TypeScript once without retaining unused comment nodes. */
3
+ export const parseJavaScriptSource = (source) => {
4
+ try {
5
+ return parse(source, {
6
+ sourceType: "unambiguous",
7
+ errorRecovery: true,
8
+ attachComment: false,
9
+ plugins: ["jsx", "typescript"],
10
+ });
11
+ }
12
+ catch {
13
+ return null;
14
+ }
15
+ };
@@ -1,24 +1,20 @@
1
- import { parse } from "@babel/parser";
2
1
  import * as t from "@babel/types";
3
2
  import { inspectElectronStaticNode } from "./electronStaticAnalysis.js";
4
3
  import { detectVendors, failedJavaScriptStaticAnalysis, registrationKey, sortedUnique, stringValue, } from "./javascriptStaticAnalysisHelpers.js";
5
4
  import { addReference, addSourceMapDirectives, inspectCall, inspectRouteProperty, inspectRoleProperty, } from "./javascriptStaticAnalysisCalls.js";
6
- import { inspectBundlerRegistration } from "./javascriptStaticAnalysisBundler.js";
5
+ import { inspectBundlerRegistration, inspectEsbuildWrapper, } from "./javascriptStaticAnalysisBundler.js";
7
6
  import { finalizeLocatedFindings } from "./javascriptStaticAnalysisFindings.js";
8
7
  import { createJavaScriptAnalysisAccumulator, } from "./javascriptStaticAnalysisState.js";
8
+ import { parseJavaScriptSource, } from "./javascriptSourceParser.js";
9
9
  /** Parse one bounded JavaScript artifact and recover static structure only. */
10
10
  export const analyzeJavaScriptStaticSource = (source, limits) => {
11
- let file;
12
- try {
13
- file = parse(source, {
14
- sourceType: "unambiguous",
15
- errorRecovery: true,
16
- plugins: ["jsx", "typescript"],
17
- });
18
- }
19
- catch {
20
- return failedJavaScriptStaticAnalysis();
21
- }
11
+ const file = parseJavaScriptSource(source);
12
+ return file === null
13
+ ? failedJavaScriptStaticAnalysis()
14
+ : analyzeParsedJavaScriptStaticSource(source, file, limits);
15
+ };
16
+ /** Recover static structure from an already parsed JavaScript artifact. */
17
+ export const analyzeParsedJavaScriptStaticSource = (source, file, limits) => {
22
18
  const accumulator = createJavaScriptAnalysisAccumulator();
23
19
  traverseStaticSource(source, file, accumulator, limits);
24
20
  addSourceMapDirectives(source, accumulator, limits.maxFindings);
@@ -100,10 +96,11 @@ const inspectNode = (source, node, accumulator, limits) => {
100
96
  inspectElectronStaticNode(node, findings);
101
97
  if (t.isCallExpression(node)) {
102
98
  inspectBundlerRegistration(source, node, accumulator, limits);
103
- inspectCall(node, findings);
99
+ inspectEsbuildWrapper(source, node, accumulator, limits);
100
+ inspectCall(source, node, findings);
104
101
  }
105
102
  else if (t.isNewExpression(node))
106
- inspectCall(node, findings);
103
+ inspectCall(source, node, findings);
107
104
  if ((t.isImportDeclaration(node) || t.isExportAllDeclaration(node)) &&
108
105
  node.source !== undefined)
109
106
  addReference(findings, {
@@ -61,6 +61,44 @@ export const inspectBundlerRegistration = (source, call, accumulator, limits) =>
61
61
  };
62
62
  addBoundedFinding(accumulator, `registration\0${registrationKey(registration)}`, limits.maxFindings, () => accumulator.registrations.push(registration));
63
63
  };
64
+ /** Inspect esbuild helper wrappers and recover their literal module tables. */
65
+ export const inspectEsbuildWrapper = (source, call, accumulator, limits) => {
66
+ const name = calleeName(call.callee);
67
+ const wrapperKind = name === "__commonJS" || name.endsWith(".__commonJS")
68
+ ? "commonjs"
69
+ : name === "__esm" || name.endsWith(".__esm")
70
+ ? "esm"
71
+ : null;
72
+ const table = call.arguments[0];
73
+ if (wrapperKind === null || !t.isObjectExpression(table))
74
+ return;
75
+ const recovered = recoverBundlerModules(source, table, accumulator, limits);
76
+ if (recovered.modules.length === 0)
77
+ return;
78
+ if (recovered.omittedAsyncChunkKeys > 0) {
79
+ accumulator.droppedFindings += recovered.omittedAsyncChunkKeys;
80
+ accumulator.structuralTruncation = true;
81
+ }
82
+ accumulator.unknownFindings += recovered.unknownAsyncChunkKeys;
83
+ const registration = {
84
+ bundler: "esbuild",
85
+ runtime: `esbuild-${wrapperKind}`,
86
+ chunk_keys: [`${wrapperKind}@${String(call.start ?? 0)}`],
87
+ omitted_chunk_keys: 0,
88
+ unknown_chunk_keys: 0,
89
+ runtime_require_name: null,
90
+ runtime_module_cache_status: "not-observed",
91
+ entry_module_keys: [],
92
+ omitted_entry_module_keys: 0,
93
+ unknown_entry_module_keys: 0,
94
+ async_chunk_keys: recovered.asyncChunkKeys,
95
+ omitted_async_chunk_keys: recovered.omittedAsyncChunkKeys,
96
+ unknown_async_chunk_keys: recovered.unknownAsyncChunkKeys,
97
+ modules: recovered.modules.sort((left, right) => compareCodePoints(left.module_key, right.module_key)),
98
+ location: range(call),
99
+ };
100
+ addBoundedFinding(accumulator, `registration\0${registrationKey(registration)}`, limits.maxFindings, () => accumulator.registrations.push(registration));
101
+ };
64
102
  const recoverBundlerModules = (source, table, accumulator, limits) => {
65
103
  const modules = [];
66
104
  const asyncChunkKeys = [];
@@ -2,7 +2,7 @@ import * as t from "@babel/types";
2
2
  import { addBoundedFinding, addLocatedFinding, moduleAtOffset, } from "./javascriptStaticAnalysisFindings.js";
3
3
  import { STATIC_ROUTE_CALL_NAMES, argumentValue, calleeName, endpointArgument as endpointArgumentHelper, prefixedArgument, propertyName, range, rangeForOffsets, sanitizeCandidate, sourceSlice, staticPath, staticPathResolutionContext, storageKind, stringValue, } from "./javascriptStaticAnalysisHelpers.js";
4
4
  /** Inspect one call or new expression for references, endpoints, storage, and roles. */
5
- export const inspectCall = (node, context) => {
5
+ export const inspectCall = (source, node, context) => {
6
6
  const { accumulator } = context;
7
7
  const name = calleeName(node.callee);
8
8
  const first = stringValue(node.arguments[0]);
@@ -22,6 +22,8 @@ export const inspectCall = (node, context) => {
22
22
  kind: "dynamic-import",
23
23
  specifier: chunkLoad.specifier,
24
24
  });
25
+ for (const specifier of vitePreloadDependencySpecifiers(source, node, name))
26
+ addReference(context, { node, kind: "dynamic-import", specifier });
25
27
  if (name === "Worker" || name.endsWith(".Worker"))
26
28
  addReference(context, { node, kind: "worker", specifier: first });
27
29
  if (name.endsWith("serviceWorker.register"))
@@ -73,6 +75,26 @@ const chunkLoadSpecifier = (node, name, moduleRequireName) => {
73
75
  return null;
74
76
  return { specifier: prefixedArgument("chunk:", node.arguments[0]) };
75
77
  };
78
+ const vitePreloadDependencySpecifiers = (source, node, name) => {
79
+ if (name !== "__vite__mapDeps" || !t.isArrayExpression(node.arguments[0]))
80
+ return [];
81
+ const indexes = node.arguments[0].elements.flatMap((element) => t.isNumericLiteral(element) ? [element.value] : []);
82
+ if (indexes.length !== node.arguments[0].elements.length)
83
+ return [];
84
+ const table = vitePreloadDependencyTable(source);
85
+ return indexes.flatMap((index) => table[index] ?? []);
86
+ };
87
+ const vitePreloadDependencyTable = (source) => {
88
+ const match = /\.\s*f\s*\|\|\s*\(\s*[^)]*?\.f\s*=\s*\[([\s\S]*?)\]\s*\)/u.exec(source);
89
+ const body = match?.[1];
90
+ if (body === undefined)
91
+ return [];
92
+ return [
93
+ ...body.matchAll(/"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'/gu),
94
+ ]
95
+ .map((literal) => (literal[1] ?? literal[2] ?? "").slice(0, 4_096))
96
+ .slice(0, 256);
97
+ };
76
98
  const inspectEndpointCall = (node, name, first, context) => {
77
99
  const route = STATIC_ROUTE_CALL_NAMES.some((candidate) => name === candidate || name.endsWith(`.${candidate}`));
78
100
  if (route && first !== undefined)
@@ -294,6 +294,12 @@ export const rangeForOffsets = (source, start, end) => ({
294
294
  start: pointForOffset(source, start),
295
295
  end: pointForOffset(source, end),
296
296
  });
297
+ /** Compare two exact source ranges. */
298
+ export const sourceRangesEqual = (left, right) => left !== null &&
299
+ left.start.line === right.start.line &&
300
+ left.start.column === right.start.column &&
301
+ left.end.line === right.end.line &&
302
+ left.end.column === right.end.column;
297
303
  const pointForOffset = (source, offset) => {
298
304
  const before = source.slice(0, offset);
299
305
  const lines = before.split("\n");
@@ -335,6 +341,8 @@ const vendorPatterns = [
335
341
  { name: "webpack", patterns: ["__webpack_require__", "webpackChunk"] },
336
342
  { name: "Rspack", patterns: ["__webpack_require__.f", "rspackChunk"] },
337
343
  { name: "Vite", patterns: ["__vite__", "import.meta.hot"] },
344
+ { name: "Rollup", patterns: ["ROLLUP_FILE_URL", "import.meta.ROLLUP"] },
345
+ { name: "esbuild", patterns: ["__commonJS", "__esm"] },
338
346
  { name: "React", patterns: ["React.createElement", "react/jsx-runtime"] },
339
347
  { name: "Vue", patterns: ["__VUE__", "createApp("] },
340
348
  { name: "Next.js", patterns: ["__NEXT_DATA__", "/_next/"] },
@@ -0,0 +1,159 @@
1
+ import { z } from "zod";
2
+ /** Supported mobile artifact formats. */
3
+ export const mobileArtifactFormatSchema = z.enum([
4
+ "apk",
5
+ "aab",
6
+ "ipa",
7
+ "dex",
8
+ "native_lib",
9
+ ]);
10
+ /** Mobile platform. */
11
+ export const mobilePlatformSchema = z.enum([
12
+ "android",
13
+ "ios",
14
+ "cross_platform",
15
+ ]);
16
+ /** Android manifest entry. */
17
+ export const androidManifestSchema = z.strictObject({
18
+ package_name: z.string().min(1),
19
+ version_name: z.string().nullable(),
20
+ version_code: z.number().int().nullable(),
21
+ min_sdk: z.number().int().nullable(),
22
+ target_sdk: z.number().int().nullable(),
23
+ permissions: z.array(z.string()).default([]),
24
+ activities: z.array(z.string()).default([]),
25
+ services: z.array(z.string()).default([]),
26
+ receivers: z.array(z.string()).default([]),
27
+ providers: z.array(z.string()).default([]),
28
+ });
29
+ /** iOS app manifest (Info.plist). */
30
+ export const iosManifestSchema = z.strictObject({
31
+ bundle_identifier: z.string().min(1),
32
+ bundle_version: z.string().nullable(),
33
+ short_version: z.string().nullable(),
34
+ minimum_os_version: z.string().nullable(),
35
+ supported_platforms: z.array(z.string()).default([]),
36
+ ui_required_device_capabilities: z.array(z.string()).default([]),
37
+ app_permissions: z.array(z.string()).default([]),
38
+ });
39
+ /** Signing information. */
40
+ export const signingInfoSchema = z.strictObject({
41
+ is_signed: z.boolean().default(false),
42
+ signer_identity: z.string().nullable(),
43
+ certificate_fingerprint: z.string().nullable(),
44
+ signature_scheme: z.string().nullable(),
45
+ is_debuggable: z.boolean().default(false),
46
+ });
47
+ /** Native library entry. */
48
+ export const nativeLibrarySchema = z.strictObject({
49
+ path: z.string().min(1),
50
+ architecture: z.string().nullable(),
51
+ size: z.number().int().nonnegative(),
52
+ digest: z
53
+ .string()
54
+ .regex(/^[a-f0-9]{64}$/u)
55
+ .nullable(),
56
+ });
57
+ /** Resource entry within a mobile artifact. */
58
+ export const mobileResourceSchema = z.strictObject({
59
+ path: z.string().min(1),
60
+ type: z.enum([
61
+ "layout",
62
+ "drawable",
63
+ "string",
64
+ "asset",
65
+ "raw",
66
+ "native_lib",
67
+ "manifest",
68
+ "entitlements",
69
+ "provisioning",
70
+ "other",
71
+ ]),
72
+ size: z.number().int().nonnegative(),
73
+ });
74
+ /** Static analysis result for a mobile artifact. */
75
+ export const mobileArtifactManifestSchema = z.strictObject({
76
+ format: mobileArtifactFormatSchema,
77
+ platform: mobilePlatformSchema,
78
+ app_name: z.string().nullable(),
79
+ android_manifest: androidManifestSchema.nullable(),
80
+ ios_manifest: iosManifestSchema.nullable(),
81
+ signing: signingInfoSchema,
82
+ resources: z.array(mobileResourceSchema).default([]),
83
+ native_libraries: z.array(nativeLibrarySchema).default([]),
84
+ total_size: z.number().int().nonnegative(),
85
+ architectures: z.array(z.string()).default([]),
86
+ });
87
+ /** Detect mobile artifact format from file extension. */
88
+ export function detectMobileFormat(path) {
89
+ const lower = path.toLowerCase();
90
+ if (lower.endsWith(".apk"))
91
+ return "apk";
92
+ if (lower.endsWith(".aab"))
93
+ return "aab";
94
+ if (lower.endsWith(".ipa"))
95
+ return "ipa";
96
+ if (lower.endsWith(".dex"))
97
+ return "dex";
98
+ if (lower.endsWith(".so") || lower.endsWith(".dylib") || lower.endsWith(".a"))
99
+ return "native_lib";
100
+ return null;
101
+ }
102
+ /** Detect platform from format. */
103
+ export function detectPlatform(format) {
104
+ switch (format) {
105
+ case "apk":
106
+ case "aab":
107
+ case "dex":
108
+ return "android";
109
+ case "ipa":
110
+ return "ios";
111
+ case "native_lib":
112
+ return "cross_platform";
113
+ }
114
+ }
115
+ /** Classify a resource by its path. */
116
+ export function classifyMobileResource(path) {
117
+ const lower = path.toLowerCase();
118
+ if (lower.includes("androidmanifest.xml"))
119
+ return "manifest";
120
+ if (lower.includes(".entitlements"))
121
+ return "entitlements";
122
+ if (lower.includes("provisioning") || lower.includes(".mobileprovision"))
123
+ return "provisioning";
124
+ if (lower.includes("/layout/"))
125
+ return "layout";
126
+ if (lower.includes("/drawable/") || lower.includes("/mipmap/"))
127
+ return "drawable";
128
+ if (lower.includes("/values/"))
129
+ return "string";
130
+ if (lower.includes("assets/") || lower.includes("raw/"))
131
+ return "asset";
132
+ if (lower.endsWith(".so") || lower.endsWith(".dylib"))
133
+ return "native_lib";
134
+ if (lower.endsWith(".xml"))
135
+ return "layout";
136
+ return "other";
137
+ }
138
+ /** Get all native libraries for a specific architecture. */
139
+ export function nativeLibsByArchitecture(manifest, arch) {
140
+ return manifest.native_libraries.filter((l) => l.architecture === arch);
141
+ }
142
+ /** Check if an Android artifact has internet permission. */
143
+ export function hasInternetPermission(manifest) {
144
+ if (!manifest.android_manifest)
145
+ return false;
146
+ return manifest.android_manifest.permissions.some((p) => p.includes("INTERNET") || p.includes("android.permission.INTERNET"));
147
+ }
148
+ /** Get all unique architectures across native libraries. */
149
+ export function getAllArchitectures(manifest) {
150
+ const archs = new Set();
151
+ for (const lib of manifest.native_libraries) {
152
+ if (lib.architecture)
153
+ archs.add(lib.architecture);
154
+ }
155
+ for (const arch of manifest.architectures) {
156
+ archs.add(arch);
157
+ }
158
+ return [...archs];
159
+ }
@@ -0,0 +1,130 @@
1
+ import { z } from "zod";
2
+ const inferenceConfidenceSchema = z.enum(["low", "medium", "high"]);
3
+ const inferenceEvidenceSchema = z
4
+ .object({
5
+ kind: z.enum([
6
+ "signature-source",
7
+ "decompiler-type",
8
+ "type-lock",
9
+ "calling-convention",
10
+ "jump-table",
11
+ ]),
12
+ source: z.string().min(1),
13
+ detail: z.string().min(1),
14
+ })
15
+ .strict();
16
+ const inferredBoundaryTypeSchema = z
17
+ .object({
18
+ role: z.enum(["return", "parameter"]),
19
+ ordinal: z.number().int().min(0).nullable(),
20
+ name: z.string().min(1).nullable(),
21
+ data_type: z.string().min(1),
22
+ size_bytes: z.number().int().min(0).nullable(),
23
+ storage: z.string().min(1).nullable(),
24
+ confidence: inferenceConfidenceSchema,
25
+ evidence: z.array(inferenceEvidenceSchema).min(1),
26
+ decompiler_artifacts: z.array(z.enum([
27
+ "recovered-signature",
28
+ "register-or-stack-storage",
29
+ "compiler-generated-variable",
30
+ ])),
31
+ })
32
+ .strict();
33
+ const jumpTableDataSourceSchema = z
34
+ .object({
35
+ address: z.string().min(1),
36
+ provenance: z.enum([
37
+ "ghidra-decompiler-load-table",
38
+ "ghidra-dispatch-block-data-reference",
39
+ ]),
40
+ entry_size_bytes: z.number().int().min(1).nullable(),
41
+ entry_count: z.number().int().min(0).nullable(),
42
+ confidence: inferenceConfidenceSchema,
43
+ evidence: z.array(inferenceEvidenceSchema).min(1),
44
+ })
45
+ .strict();
46
+ const jumpTableMappingSchema = z
47
+ .object({
48
+ case_value: z.number().int().nullable(),
49
+ target_address: z.string().min(1),
50
+ data_addresses: z.array(z.string().min(1)),
51
+ confidence: inferenceConfidenceSchema,
52
+ evidence: z.array(inferenceEvidenceSchema).min(1),
53
+ })
54
+ .strict();
55
+ const inferredJumpTableSchema = z
56
+ .object({
57
+ dispatch_address: z.string().min(1),
58
+ data_sources: z.array(jumpTableDataSourceSchema),
59
+ data_sources_truncated: z.boolean(),
60
+ mappings: z.array(jumpTableMappingSchema),
61
+ mappings_truncated: z.boolean(),
62
+ limitations: z.array(z.string()),
63
+ })
64
+ .strict();
65
+ const availableNativeApiBoundarySchema = z
66
+ .object({
67
+ available: z.literal(true),
68
+ provenance: z.string().min(1),
69
+ signature_source: z.string().min(1),
70
+ calling_convention: z.string().min(1),
71
+ return_type: inferredBoundaryTypeSchema,
72
+ parameters: z.array(inferredBoundaryTypeSchema),
73
+ parameters_truncated: z.boolean(),
74
+ jump_tables: z.array(inferredJumpTableSchema),
75
+ jump_tables_truncated: z.boolean(),
76
+ pseudocode: z
77
+ .object({
78
+ classification: z.literal("decompiler-generated-non-source"),
79
+ compilable: z.literal(false),
80
+ })
81
+ .strict(),
82
+ decompiler_artifacts: z.array(z.enum([
83
+ "recovered-signature",
84
+ "register-and-stack-variables",
85
+ "compiler-generated-control-flow",
86
+ "pointer-arithmetic",
87
+ "pseudocode",
88
+ ])),
89
+ limitations: z.array(z.string()),
90
+ })
91
+ .strict();
92
+ const unavailableNativeApiBoundarySchema = z
93
+ .object({
94
+ available: z.literal(false),
95
+ reason: z.string().min(1),
96
+ residual_unknowns: z.array(z.string().min(1)).min(1),
97
+ })
98
+ .strict();
99
+ /** Provider-neutral native API boundary observations attached to a function dossier. */
100
+ export const nativeApiBoundarySchema = z.discriminatedUnion("available", [
101
+ unavailableNativeApiBoundarySchema,
102
+ availableNativeApiBoundarySchema,
103
+ ]);
104
+ const nativeApiInspectionSubstepSchema = z
105
+ .object({
106
+ operation: z.enum([
107
+ "analyze_function",
108
+ "project_native_api_boundary",
109
+ "preserve_residual_unknowns",
110
+ ]),
111
+ status: z.enum(["completed", "unsupported"]),
112
+ observations: z.array(z.string().min(1)),
113
+ })
114
+ .strict();
115
+ /** Agent-facing projection of structured native API reconstruction substeps. */
116
+ export const nativeApiInspectionResultSchema = z
117
+ .object({
118
+ schema_version: z.literal(1),
119
+ procedure: z
120
+ .object({
121
+ address: z.string().min(1),
122
+ name: z.string().min(1),
123
+ })
124
+ .strict(),
125
+ boundary: nativeApiBoundarySchema,
126
+ substeps: z.array(nativeApiInspectionSubstepSchema).min(3).max(3),
127
+ unsupported_branches: z.array(z.string().min(1)),
128
+ residual_unknowns: z.array(z.string().min(1)),
129
+ })
130
+ .strict();