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
@@ -1,7 +1,134 @@
1
1
  import { createJavaScriptSemanticGraphUnknown } from "../domain/javascriptSemanticGraph.js";
2
- import { addSemanticGraphRelation, addSemanticGraphUnknown, } from "./JavaScriptSemanticGraphConstruction.js";
2
+ import { sourceRangesEqual } from "../domain/javascriptStaticAnalysisHelpers.js";
3
+ import { addSemanticGraphNode, addSemanticGraphRelation, addSemanticGraphUnknown, constructSemanticGraphNode, } from "./JavaScriptSemanticGraphConstruction.js";
3
4
  import { inferredSemanticEvidenceAt, unknownSemanticEvidence, } from "./JavaScriptSemanticGraphEvidence.js";
4
5
  import { semanticNodesWithinRange } from "./JavaScriptSemanticGraphProjection.js";
6
+ /** Find the retained call-site node at one exact semantic source range. */
7
+ export const semanticCallSiteAt = (context, location) => {
8
+ const call = context.ir.callSites.find(({ location: candidate }) => sourceRangesEqual(candidate, location));
9
+ return call === undefined
10
+ ? undefined
11
+ : context.callSiteNodes.get(call.callSiteId);
12
+ };
13
+ /** Project explicit static Promise/task ownership without runtime claims. */
14
+ export const projectSemanticPromises = (context) => {
15
+ const promiseNodes = new Map(context.ir.promiseOperations.flatMap((operation) => {
16
+ const owner = operation.ownerCallableId === null
17
+ ? undefined
18
+ : context.callableNodes.get(operation.ownerCallableId);
19
+ const node = addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
20
+ kind: operation.kind === "awaited-expression" ? "task" : "promise",
21
+ roleKey: operation.promiseId,
22
+ location: operation.location,
23
+ label: promiseLabel(operation),
24
+ functionNodeId: owner?.node_id ?? null,
25
+ properties: {
26
+ method: operation.method,
27
+ operation_kind: operation.kind,
28
+ ownership: operation.ownership,
29
+ source_resolution: operation.sourceResolution,
30
+ },
31
+ }, context.state));
32
+ return node === null ? [] : [[operation.promiseId, node]];
33
+ }));
34
+ for (const operation of context.ir.promiseOperations) {
35
+ const promise = promiseNodes.get(operation.promiseId);
36
+ if (promise === undefined)
37
+ continue;
38
+ projectPromiseCreation(context, operation, promise);
39
+ projectPromiseSources(context, operation, promise, promiseNodes);
40
+ projectPromiseOwnership(context, operation, promise);
41
+ if (operation.sourceResolution !== "complete" &&
42
+ ["chain", "aggregate", "awaited-expression"].includes(operation.kind))
43
+ addPromiseUnknown(context, operation, promise, promiseNodes);
44
+ }
45
+ };
46
+ const promiseLabel = (operation) => operation.kind === "awaited-expression"
47
+ ? "awaited expression"
48
+ : `Promise.${operation.method}`;
49
+ const projectPromiseCreation = (context, operation, promise) => {
50
+ if (operation.kind === "awaited-expression")
51
+ return;
52
+ addSemanticGraphRelation(context.state, {
53
+ source: semanticCallSiteAt(context, operation.location),
54
+ target: promise,
55
+ relation: "creates-promise",
56
+ resolution: operation.kind === "chain" || operation.sourceResolution !== "complete"
57
+ ? "candidate"
58
+ : "resolved",
59
+ });
60
+ };
61
+ const projectPromiseSources = (context, operation, promise, promiseNodes) => {
62
+ for (const sourceId of operation.sourcePromiseIds) {
63
+ const source = promiseNodes.get(sourceId);
64
+ if (operation.kind === "aggregate")
65
+ addSemanticGraphRelation(context.state, {
66
+ source: promise,
67
+ target: source,
68
+ relation: "aggregates",
69
+ resolution: operation.sourceResolution === "complete" ? "resolved" : "candidate",
70
+ });
71
+ else
72
+ addSemanticGraphRelation(context.state, {
73
+ source,
74
+ target: promise,
75
+ relation: "chains",
76
+ resolution: operation.sourceResolution === "complete" ? "resolved" : "candidate",
77
+ });
78
+ }
79
+ };
80
+ const projectPromiseOwnership = (context, operation, promise) => {
81
+ const owner = operation.ownerCallableId === null
82
+ ? context.moduleNode
83
+ : context.callableNodes.get(operation.ownerCallableId);
84
+ if (operation.ownership === "awaited")
85
+ addSemanticGraphRelation(context.state, {
86
+ source: owner,
87
+ target: promise,
88
+ relation: "awaits",
89
+ resolution: "resolved",
90
+ });
91
+ else if (operation.ownership === "assigned")
92
+ addSemanticGraphRelation(context.state, {
93
+ source: operation.ownerBindingId === null
94
+ ? undefined
95
+ : context.bindingNodes.get(operation.ownerBindingId),
96
+ target: promise,
97
+ relation: "owns",
98
+ resolution: "resolved",
99
+ });
100
+ else if (operation.ownership === "returned")
101
+ addSemanticGraphRelation(context.state, {
102
+ source: operation.returnSiteId === null
103
+ ? undefined
104
+ : context.returnSiteNodes.get(operation.returnSiteId),
105
+ target: promise,
106
+ relation: "returns-task",
107
+ resolution: "resolved",
108
+ });
109
+ else if (operation.ownership === "detached")
110
+ addSemanticGraphRelation(context.state, {
111
+ source: owner,
112
+ target: promise,
113
+ relation: "detaches-task",
114
+ resolution: "resolved",
115
+ });
116
+ };
117
+ const addPromiseUnknown = (context, operation, promise, promiseNodes) => {
118
+ const relation = operation.kind === "aggregate" ? "aggregates" : "chains";
119
+ addSemanticGraphUnknown(context.state, createJavaScriptSemanticGraphUnknown({
120
+ node_id: promise.node_id,
121
+ family: "promise-ownership",
122
+ relation_kinds: [relation],
123
+ reason: "ambiguous-target",
124
+ detail: `Static ${operation.method} source resolution was ${operation.sourceResolution}.`,
125
+ candidate_node_ids: operation.sourcePromiseIds.flatMap((identifier) => {
126
+ const candidate = promiseNodes.get(identifier);
127
+ return candidate === undefined ? [] : [candidate.node_id];
128
+ }),
129
+ evidence: unknownSemanticEvidence(context.file, operation.location),
130
+ }));
131
+ };
5
132
  /** Link direct return expressions to their retained semantic references. */
6
133
  export const projectSemanticReturnValues = (context) => {
7
134
  for (const callable of context.ir.callables)
@@ -14,18 +141,12 @@ export const projectSemanticReturnValues = (context) => {
14
141
  target: returnNode,
15
142
  relation: "aliases",
16
143
  resolution: site.identityReferenceLocation !== null &&
17
- rangesEqual(reference.identity.source_range, site.identityReferenceLocation)
144
+ sourceRangesEqual(reference.identity.source_range, site.identityReferenceLocation)
18
145
  ? "resolved"
19
146
  : "candidate",
20
147
  });
21
148
  }
22
149
  };
23
- const rangesEqual = (left, right) => left !== null &&
24
- right !== null &&
25
- left.start.line === right.start.line &&
26
- left.start.column === right.start.column &&
27
- left.end.line === right.end.line &&
28
- left.end.column === right.end.column;
29
150
  /** Link each captured binding to the callable at the exact reference site. */
30
151
  export const projectSemanticClosureCaptures = (context) => {
31
152
  for (const capture of context.ir.closureCaptures)
@@ -0,0 +1,81 @@
1
+ import { createJavaScriptSemanticGraphUnknown } from "../domain/javascriptSemanticGraph.js";
2
+ import { addSemanticGraphNode, addSemanticGraphRelation, addSemanticGraphUnknown, constructSemanticGraphNode, } from "./JavaScriptSemanticGraphConstruction.js";
3
+ import { unknownSemanticEvidence } from "./JavaScriptSemanticGraphEvidence.js";
4
+ import { semanticPropertySlot } from "./JavaScriptSemanticGraphValueProjection.js";
5
+ /** Project static object reads, writes, spreads, and destructuring. */
6
+ export const projectSemanticObjects = (context) => {
7
+ for (const operation of context.ir.objectOperations) {
8
+ const occurrence = addObjectOccurrence(context, operation);
9
+ const slot = operation.objectBindingId === null || operation.propertyName === null
10
+ ? null
11
+ : semanticPropertySlot(context, operation.objectBindingId, operation.propertyName);
12
+ if (operation.kind === "read")
13
+ addSemanticGraphRelation(context.state, {
14
+ source: slot,
15
+ target: occurrence,
16
+ relation: "reads-property",
17
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
18
+ });
19
+ else if (operation.kind === "write")
20
+ addSemanticGraphRelation(context.state, {
21
+ source: occurrence,
22
+ target: slot,
23
+ relation: "writes-property",
24
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
25
+ });
26
+ else if (operation.kind === "destructure")
27
+ addSemanticGraphRelation(context.state, {
28
+ source: slot,
29
+ target: operation.targetBindingId === null
30
+ ? undefined
31
+ : context.bindingNodes.get(operation.targetBindingId),
32
+ relation: "destructures",
33
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
34
+ });
35
+ else
36
+ addSemanticGraphRelation(context.state, {
37
+ source: operation.objectBindingId === null
38
+ ? undefined
39
+ : context.bindingNodes.get(operation.objectBindingId),
40
+ target: occurrence,
41
+ relation: "spreads",
42
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
43
+ });
44
+ if (operation.resolution !== "complete")
45
+ addObjectUnknown(context, operation, slot ?? occurrence);
46
+ }
47
+ };
48
+ const addObjectOccurrence = (context, operation) => addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
49
+ kind: "expression",
50
+ roleKey: operation.objectOperationId,
51
+ location: operation.location,
52
+ label: operation.propertyName === null
53
+ ? operation.kind
54
+ : `${operation.kind}:${operation.propertyName}`,
55
+ functionNodeId: operation.ownerCallableId === null
56
+ ? null
57
+ : (context.callableNodes.get(operation.ownerCallableId)?.node_id ??
58
+ null),
59
+ properties: {
60
+ operation_kind: operation.kind,
61
+ property_name: operation.propertyName,
62
+ },
63
+ }, context.state));
64
+ const addObjectUnknown = (context, operation, node) => {
65
+ const relation = operation.kind === "read"
66
+ ? "reads-property"
67
+ : operation.kind === "write"
68
+ ? "writes-property"
69
+ : operation.kind === "spread"
70
+ ? "spreads"
71
+ : "destructures";
72
+ addSemanticGraphUnknown(context.state, createJavaScriptSemanticGraphUnknown({
73
+ node_id: node?.node_id ?? null,
74
+ family: "object-flow",
75
+ relation_kinds: [relation],
76
+ reason: "ambiguous-target",
77
+ detail: `Static ${operation.kind} object identity is partial.`,
78
+ candidate_node_ids: [],
79
+ evidence: unknownSemanticEvidence(context.file, operation.location),
80
+ }));
81
+ };
@@ -15,18 +15,25 @@ export const semanticNodesWithinRange = (nodes, range) => nodes.filter((node) =>
15
15
  contains(range, node.identity.source_range));
16
16
  /** Report extractor support without treating missing families as absence. */
17
17
  export const semanticFamilyStatus = (family, analysis, truncated) => {
18
- if (!["call-flow", "closure", "data-flow", "object-flow"].includes(family))
18
+ if (![
19
+ "call-flow",
20
+ "boundary",
21
+ "child-process",
22
+ "closure",
23
+ "configuration",
24
+ "data-flow",
25
+ "event",
26
+ "object-flow",
27
+ "promise-ownership",
28
+ "request",
29
+ "resource-lifecycle",
30
+ "timer",
31
+ ].includes(family))
19
32
  return "unsupported";
20
33
  if (truncated)
21
34
  return "unknown";
22
35
  return analysis.truncated_scopes === 0 ? "partial" : "unknown";
23
36
  };
24
- /** Compare two exact semantic source ranges. */
25
- export const semanticRangesEqual = (left, right) => left !== null &&
26
- left.start.line === right.start.line &&
27
- left.start.column === right.start.column &&
28
- left.end.line === right.end.line &&
29
- left.end.column === right.end.column;
30
37
  const contains = (outer, inner) => pointCompare(outer.start, inner.start) <= 0 &&
31
38
  pointCompare(outer.end, inner.end) >= 0;
32
39
  const pointCompare = (left, right) => left.line - right.line || left.column - right.column;
@@ -0,0 +1,59 @@
1
+ import { createJavaScriptSemanticGraphUnknown } from "../domain/javascriptSemanticGraph.js";
2
+ import { addSemanticGraphNode, addSemanticGraphRelation, addSemanticGraphUnknown, constructSemanticGraphNode, } from "./JavaScriptSemanticGraphConstruction.js";
3
+ import { unknownSemanticEvidence } from "./JavaScriptSemanticGraphEvidence.js";
4
+ import { semanticCallSiteAt, } from "./JavaScriptSemanticGraphFlowProjection.js";
5
+ /** Project built-in resource acquisition and exact local release handles. */
6
+ export const projectSemanticResources = (context) => {
7
+ const resourceNodes = new Map(context.ir.resourceOperations.flatMap((operation) => {
8
+ if (operation.kind !== "acquire")
9
+ return [];
10
+ const node = addResourceNode(context, operation);
11
+ return node === null ? [] : [[operation.resourceId, node]];
12
+ }));
13
+ for (const operation of context.ir.resourceOperations)
14
+ if (operation.kind === "acquire")
15
+ addSemanticGraphRelation(context.state, {
16
+ source: semanticCallSiteAt(context, operation.location),
17
+ target: resourceNodes.get(operation.resourceId),
18
+ relation: "acquires",
19
+ resolution: "resolved",
20
+ });
21
+ else
22
+ projectRelease(context, operation, resourceNodes);
23
+ };
24
+ const addResourceNode = (context, operation) => addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
25
+ kind: "resource",
26
+ roleKey: operation.resourceId,
27
+ location: operation.location,
28
+ label: operation.method,
29
+ functionNodeId: operation.ownerCallableId === null
30
+ ? null
31
+ : (context.callableNodes.get(operation.ownerCallableId)?.node_id ??
32
+ null),
33
+ properties: { method: operation.method },
34
+ }, context.state));
35
+ const projectRelease = (context, operation, resourceNodes) => {
36
+ const callSite = semanticCallSiteAt(context, operation.location);
37
+ const resources = operation.linkedResourceIds.flatMap((identifier) => {
38
+ const resource = resourceNodes.get(identifier);
39
+ return resource === undefined ? [] : [resource];
40
+ });
41
+ for (const resource of resources)
42
+ addSemanticGraphRelation(context.state, {
43
+ source: callSite,
44
+ target: resource,
45
+ relation: "releases",
46
+ resolution: operation.resolution === "complete" ? "resolved" : "candidate",
47
+ });
48
+ if (operation.resolution === "complete")
49
+ return;
50
+ addSemanticGraphUnknown(context.state, createJavaScriptSemanticGraphUnknown({
51
+ node_id: callSite?.node_id ?? null,
52
+ family: "resource-lifecycle",
53
+ relation_kinds: ["releases"],
54
+ reason: "ambiguous-target",
55
+ detail: `Static ${operation.method} resource ownership is ambiguous.`,
56
+ candidate_node_ids: resources.map(({ node_id: identifier }) => identifier),
57
+ evidence: unknownSemanticEvidence(context.file, operation.location),
58
+ }));
59
+ };
@@ -0,0 +1,77 @@
1
+ import { addSemanticGraphNode, addSemanticGraphRelation, constructSemanticGraphNode, } from "./JavaScriptSemanticGraphConstruction.js";
2
+ /** Project bounded literal values and object slots for exact query seeds. */
3
+ export const projectSemanticValues = (context) => {
4
+ for (const binding of context.ir.bindings) {
5
+ const bindingNode = context.bindingNodes.get(binding.bindingId);
6
+ if (bindingNode === undefined)
7
+ continue;
8
+ projectValue({
9
+ context,
10
+ binding,
11
+ value: binding.value,
12
+ target: bindingNode,
13
+ role: "binding",
14
+ });
15
+ }
16
+ };
17
+ const projectValue = (input) => {
18
+ const { context, binding, value, target, role } = input;
19
+ if (target === null)
20
+ return;
21
+ if (value.status === "literal") {
22
+ const literal = addLiteralNode(context, binding, value.value, role);
23
+ addSemanticGraphRelation(context.state, {
24
+ source: literal,
25
+ target,
26
+ relation: "defines",
27
+ resolution: "resolved",
28
+ });
29
+ }
30
+ else if (value.status === "union")
31
+ for (const primitive of value.values) {
32
+ const literal = addLiteralNode(context, binding, primitive, role);
33
+ addSemanticGraphRelation(context.state, {
34
+ source: literal,
35
+ target,
36
+ relation: "defines",
37
+ resolution: "candidate",
38
+ });
39
+ }
40
+ else if (value.status === "object")
41
+ for (const property of value.properties) {
42
+ const slot = semanticPropertySlot(context, binding.bindingId, property.name);
43
+ addSemanticGraphRelation(context.state, {
44
+ source: target,
45
+ target: slot,
46
+ relation: "writes-property",
47
+ resolution: value.unknownProperties ? "candidate" : "resolved",
48
+ });
49
+ projectValue({
50
+ context,
51
+ binding,
52
+ value: property.value,
53
+ target: slot,
54
+ role: `property:${property.name}`,
55
+ });
56
+ }
57
+ };
58
+ const addLiteralNode = (context, binding, value, role) => addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
59
+ kind: "literal",
60
+ roleKey: `literal:${binding.bindingId}:${role}:${JSON.stringify(value)}`,
61
+ location: binding.definitions[0]?.location ?? null,
62
+ label: JSON.stringify(value),
63
+ functionNodeId: context.bindingNodes.get(binding.bindingId)?.function_node_id ?? null,
64
+ properties: { value },
65
+ }, context.state));
66
+ /** Create one canonical property slot for a binding/property identity. */
67
+ export const semanticPropertySlot = (context, objectBindingId, name) => addSemanticGraphNode(context.state, constructSemanticGraphNode(context.file, {
68
+ kind: "property-slot",
69
+ roleKey: `property:${objectBindingId}:${name}`,
70
+ location: null,
71
+ label: name,
72
+ functionNodeId: context.bindingNodes.get(objectBindingId)?.function_node_id ?? null,
73
+ properties: {
74
+ name,
75
+ object_binding_id: objectBindingId,
76
+ },
77
+ }, context.state));
@@ -0,0 +1,77 @@
1
+ /**
2
+ * Preserve synchronous provider discovery while loading implementation modules
3
+ * only when a target-bound client first executes.
4
+ */
5
+ export class LazyAnalysisProvider {
6
+ #providerIdentity;
7
+ #capabilityDescriptors;
8
+ #loadProvider;
9
+ #provider;
10
+ constructor(options) {
11
+ this.#providerIdentity = options.identity;
12
+ this.#capabilityDescriptors = options.capabilities;
13
+ this.#loadProvider = options.load;
14
+ }
15
+ /** Return generated provider identity without loading its implementation. */
16
+ identity() {
17
+ return this.#providerIdentity;
18
+ }
19
+ /** Return generated capability metadata without loading its implementation. */
20
+ capabilities() {
21
+ return this.#capabilityDescriptors;
22
+ }
23
+ /** Create a client whose implementation is loaded on first execution. */
24
+ createClient(target, profile, context) {
25
+ return new LazyAnalysisClient(async () => {
26
+ const provider = await this.#load();
27
+ return provider.createClient(target, profile, context);
28
+ });
29
+ }
30
+ async #load() {
31
+ this.#provider ??= this.#loadProvider().catch((cause) => {
32
+ this.#provider = undefined;
33
+ throw cause;
34
+ });
35
+ return this.#provider;
36
+ }
37
+ }
38
+ class LazyAnalysisClient {
39
+ #loadClient;
40
+ #client;
41
+ #loading;
42
+ #closed = false;
43
+ constructor(loadClient) {
44
+ this.#loadClient = loadClient;
45
+ }
46
+ execute = async (operation, parameters, options) => {
47
+ const client = await this.#load();
48
+ return client.execute(operation, parameters, options);
49
+ };
50
+ runtimeLineageSnapshots() {
51
+ return this.#client?.runtimeLineageSnapshots?.() ?? [];
52
+ }
53
+ requestActivitySnapshots() {
54
+ return this.#client?.requestActivitySnapshots?.() ?? [];
55
+ }
56
+ async close() {
57
+ this.#closed = true;
58
+ if (this.#loading === undefined)
59
+ return;
60
+ const client = await this.#loading;
61
+ await client.close();
62
+ }
63
+ async #load() {
64
+ if (this.#closed)
65
+ throw new Error("Lazy analysis client is closed");
66
+ this.#loading ??= this.#loadClient()
67
+ .then((client) => {
68
+ this.#client = client;
69
+ return client;
70
+ })
71
+ .catch((cause) => {
72
+ this.#loading = undefined;
73
+ throw cause;
74
+ });
75
+ return this.#loading;
76
+ }
77
+ }
@@ -374,11 +374,11 @@ export const startLoopbackReplay = async (scenario, recordEvent = () => undefine
374
374
  async close() {
375
375
  closePromise ??= (async () => {
376
376
  recorder.stopMachineAdmission();
377
+ await recorder.drainMachine();
377
378
  for (const client of websocket.clients)
378
379
  client.terminate();
379
380
  await new Promise((resolveClose) => websocket.close(() => resolveClose()));
380
381
  await closeReplayServer(server);
381
- await recorder.drainMachine();
382
382
  })();
383
383
  await closePromise;
384
384
  },
@@ -0,0 +1,80 @@
1
+ import { nativeApiInspectionResultSchema, } from "../domain/nativeApiBoundary.js";
2
+ const unavailableBoundary = () => ({
3
+ available: false,
4
+ reason: "The selected provider did not expose a structured native API boundary model.",
5
+ residual_unknowns: [
6
+ "What are the function's return and parameter boundary types?",
7
+ "Does this function dispatch through a jump table with recoverable data addresses?",
8
+ ],
9
+ });
10
+ /** Project one analyzed-function dossier into inspectable native API substeps. */
11
+ export const projectNativeApiInspection = (dossier) => {
12
+ const boundary = dossier.native_api ?? unavailableBoundary();
13
+ const unsupportedBranches = boundary.available
14
+ ? []
15
+ : ["structured-boundary-types", "jump-table-data-mapping"];
16
+ const residualUnknowns = boundary.available
17
+ ? availableResidualUnknowns(boundary)
18
+ : boundary.residual_unknowns;
19
+ return nativeApiInspectionResultSchema.parse({
20
+ schema_version: 1,
21
+ procedure: {
22
+ address: dossier.procedure.address,
23
+ name: dossier.procedure.name,
24
+ },
25
+ boundary,
26
+ substeps: [
27
+ {
28
+ operation: "analyze_function",
29
+ status: "completed",
30
+ observations: [
31
+ "provider function dossier",
32
+ "provider pseudocode classification",
33
+ "provider control-flow observations",
34
+ ],
35
+ },
36
+ {
37
+ operation: "project_native_api_boundary",
38
+ status: boundary.available ? "completed" : "unsupported",
39
+ observations: boundary.available
40
+ ? [
41
+ "return and parameter boundary types",
42
+ "confidence and inference evidence",
43
+ "jump-table dispatch, data, and target addresses",
44
+ ]
45
+ : [boundary.reason],
46
+ },
47
+ {
48
+ operation: "preserve_residual_unknowns",
49
+ status: "completed",
50
+ observations: residualUnknowns.length === 0
51
+ ? ["no additional structured-boundary unknowns"]
52
+ : residualUnknowns,
53
+ },
54
+ ],
55
+ unsupported_branches: unsupportedBranches,
56
+ residual_unknowns: residualUnknowns,
57
+ });
58
+ };
59
+ const availableResidualUnknowns = (boundary) => {
60
+ const unknowns = [];
61
+ if (boundary.parameters_truncated)
62
+ unknowns.push("Which additional parameters were omitted by the native API boundary limit?");
63
+ if (boundary.jump_tables_truncated)
64
+ unknowns.push("Which additional jump tables were omitted by the native API boundary limit?");
65
+ for (const table of boundary.jump_tables) {
66
+ if (table.data_sources_truncated || table.mappings_truncated)
67
+ unknowns.push(`Which additional data sources or targets were omitted for the jump table dispatched at ${table.dispatch_address}?`);
68
+ if (table.data_sources.length === 0)
69
+ unknowns.push(`What backing data address produced the jump table dispatched at ${table.dispatch_address}?`);
70
+ if (table.data_sources.some(({ entry_count: count, entry_size_bytes: size }) => count === null || size === null))
71
+ unknowns.push(`What are the exact entry size and count for candidate jump-table data dispatched at ${table.dispatch_address}?`);
72
+ if (table.mappings.some(({ case_value: value }) => value === null))
73
+ unknowns.push(`Which source-level case values correspond to every target dispatched at ${table.dispatch_address}?`);
74
+ }
75
+ for (const value of [boundary.return_type, ...boundary.parameters]) {
76
+ if (value.confidence === "low")
77
+ unknowns.push(`Can the inferred ${value.role} type ${value.data_type} be confirmed with imported metadata or an ABI probe?`);
78
+ }
79
+ return [...new Set(unknowns)];
80
+ };
@@ -7,6 +7,8 @@ const interactionData = (action) => {
7
7
  : action.data;
8
8
  if (action.type === "resize")
9
9
  return `${String(action.columns)}x${String(action.rows)}`;
10
+ if (action.type === "close_stdin")
11
+ return "";
10
12
  return action.signal;
11
13
  };
12
14
  const interactionType = (action) => {
@@ -14,6 +16,8 @@ const interactionType = (action) => {
14
16
  return "input";
15
17
  if (action.type === "resize")
16
18
  return "resize";
19
+ if (action.type === "close_stdin")
20
+ return "stdin_close";
17
21
  return "signal";
18
22
  };
19
23
  const performTerminalAction = (terminal, renderer, action, atMs) => {
@@ -23,6 +27,8 @@ const performTerminalAction = (terminal, renderer, action, atMs) => {
23
27
  terminal.resize(action.columns, action.rows);
24
28
  renderer.resize(action.columns, action.rows, atMs);
25
29
  }
30
+ else if (action.type === "close_stdin")
31
+ terminal.closeInput();
26
32
  else
27
33
  terminal.kill(action.signal);
28
34
  };
@@ -3,6 +3,21 @@ import { ProcessReactiveCoordinator } from "./ProcessReactiveCoordinator.js";
3
3
  import { executeProcessReactiveEffects, unsupportedProcessReactiveFeatures, } from "./ProcessReactiveEffects.js";
4
4
  import { subscribeProcessReactiveObservations } from "./ProcessReactiveObservations.js";
5
5
  import { normalizeProcessSamples, normalizeProcessShimEvent, redactProtocolEvents, } from "./ProcessNormalization.js";
6
+ const reactiveTerminalFor = (terminal) => {
7
+ if (terminal === undefined)
8
+ return undefined;
9
+ return {
10
+ write: (data) => terminal.write(data),
11
+ resize: (columns, rows) => terminal.resize(columns, rows),
12
+ closeInput: () => {
13
+ const end = Reflect.get(terminal, "end");
14
+ if (typeof end !== "function")
15
+ throw new ProcessCaptureError("PTY backend does not expose an stdin-close operation");
16
+ Reflect.apply(end, terminal, []);
17
+ },
18
+ kill: (signal) => terminal.kill(signal),
19
+ };
20
+ };
6
21
  const controlKind = (input) => input.kind === "observation" ? undefined : input.kind;
7
22
  /** Reject reactive declarations the current process adapter cannot execute. */
8
23
  export const assertSupportedReactiveScenario = (scenario) => {
@@ -27,7 +42,7 @@ export const startProcessReactiveHarness = (options) => {
27
42
  scenario: options.scenario.reactive,
28
43
  executor: {
29
44
  execute: (actions, signal) => executeProcessReactiveEffects({
30
- terminal: options.terminal,
45
+ terminal: () => reactiveTerminalFor(options.terminal()),
31
46
  renderer: options.renderer,
32
47
  checkpoints: options.checkpoints,
33
48
  interactions: options.capture.interactions,
@@ -11,6 +11,7 @@ const grantSchema = z.object({
11
11
  capability: z.enum([
12
12
  "process_capture",
13
13
  "browser_observe",
14
+ "browser_automate",
14
15
  "electron_observe",
15
16
  "evidence_read",
16
17
  "evidence_write",