rea-agents 3.0.0 → 3.1.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 (219) hide show
  1. package/README.md +14 -16
  2. package/dist/application/AnalysisContextQueries.js +21 -9
  3. package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
  4. package/dist/application/ArtifactInventory/policy.js +17 -0
  5. package/dist/application/ArtifactInventory/reader.js +1 -4
  6. package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
  7. package/dist/application/ArtifactInventory/scanReader.js +7 -7
  8. package/dist/application/ArtifactInventory/types.js +1 -5
  9. package/dist/application/BinarySession.js +14 -16
  10. package/dist/application/BinarySessionRecords.js +31 -5
  11. package/dist/application/BinarySessionStatus.js +11 -5
  12. package/dist/application/BrowserEvidence.js +3 -5
  13. package/dist/application/CapabilityClientRequirements.js +26 -0
  14. package/dist/application/CapabilityInventory.js +134 -63
  15. package/dist/application/CrossVersionInventory.js +7 -6
  16. package/dist/application/ElectronActiveEvidence.js +55 -0
  17. package/dist/application/ElectronActiveObservationPort.js +1 -0
  18. package/dist/application/ElectronActiveObservationService.js +81 -0
  19. package/dist/application/EnhancedTools.js +22 -20
  20. package/dist/application/EvidenceBundleCommands.js +5 -1
  21. package/dist/application/EvidenceLedger.js +8 -1
  22. package/dist/application/JavaScriptReplayPermission.js +1 -1
  23. package/dist/application/JavaScriptReplayService.js +23 -15
  24. package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
  25. package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
  26. package/dist/application/ProcessCaptureLifecycle.js +5 -0
  27. package/dist/application/ProcessCli.js +2 -1
  28. package/dist/application/ProcessHarness.js +8 -3
  29. package/dist/application/ProcessNormalization.js +2 -1
  30. package/dist/application/ProjectPermissionStore.js +1 -0
  31. package/dist/application/ReferenceSourceImport.js +2 -2
  32. package/dist/application/SetupClientConfiguration.js +6 -1
  33. package/dist/application/WindowsCapabilities.js +5 -4
  34. package/dist/artifacts/ArtifactProvider.js +8 -10
  35. package/dist/artifacts/SafeOutputTree.js +7 -8
  36. package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
  37. package/dist/browser/CdpElectronInspection.js +3 -1
  38. package/dist/browser/JavaScriptRuntimeScope.js +5 -0
  39. package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
  40. package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
  41. package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
  42. package/dist/browser/PlaywrightScenarioSession.js +4 -4
  43. package/dist/browser/SensitiveTextCapture.js +1 -1
  44. package/dist/browser/V8InspectorCaptureProjection.js +1 -0
  45. package/dist/browser/V8InspectorProvider.js +3 -3
  46. package/dist/catalogIdentity.js +12 -6
  47. package/dist/cli/managedCommands.js +1 -1
  48. package/dist/cliApplicationCommands.js +2 -2
  49. package/dist/cliBrowserAdvancedCommands.js +11 -5
  50. package/dist/cliBrowserCommands.js +14 -7
  51. package/dist/cliCommandNames.js +1 -0
  52. package/dist/cliElectronCommands.js +46 -4
  53. package/dist/cliJavaScriptRuntimeCommands.js +14 -6
  54. package/dist/cliObservationOptions.js +4 -0
  55. package/dist/cliPolicyCommands.js +1 -0
  56. package/dist/config/browserScenario.js +77 -0
  57. package/dist/config/electronAutomation.js +35 -0
  58. package/dist/config/environment.js +6 -0
  59. package/dist/config/javascriptReplay.js +41 -0
  60. package/dist/config/managedRuntime.js +25 -0
  61. package/dist/config/parseConfig.js +56 -200
  62. package/dist/config/parsers.js +10 -1
  63. package/dist/config/passiveObservation.js +157 -0
  64. package/dist/config/processCapture.js +47 -0
  65. package/dist/contracts/applicationToolContracts.js +2 -5
  66. package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
  67. package/dist/contracts/artifactToolContracts.js +27 -34
  68. package/dist/contracts/browserToolContracts.js +2 -2
  69. package/dist/contracts/electronToolContracts.js +30 -1
  70. package/dist/contracts/enhancedInputs.js +13 -29
  71. package/dist/contracts/functionWorkflowToolContracts.js +2 -3
  72. package/dist/contracts/managedToolContracts.js +4 -9
  73. package/dist/contracts/managedWorkflowExamples.js +12 -9
  74. package/dist/contracts/managedWorkflowToolContracts.js +30 -27
  75. package/dist/contracts/nativeToolContracts.js +2 -3
  76. package/dist/contracts/sessionToolSchemas.js +61 -0
  77. package/dist/contracts/toolContractExamples.js +1 -0
  78. package/dist/contracts/toolContractHelpers.js +23 -0
  79. package/dist/contracts/toolContracts.js +5 -77
  80. package/dist/contracts/toolEffects.js +15 -0
  81. package/dist/contracts/toolOutputSchemaGroups.js +17 -2
  82. package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
  83. package/dist/contracts/toolSchemaMetadata.js +128 -0
  84. package/dist/doctorRuntime.js +1 -1
  85. package/dist/domain/androidApplication.js +2 -0
  86. package/dist/domain/appleApplication.js +2 -0
  87. package/dist/domain/binaryTarget.js +7 -5
  88. package/dist/domain/binaryTargetTypes.js +1 -0
  89. package/dist/domain/browserCaptureComparison.js +21 -69
  90. package/dist/domain/browserObservation.js +22 -9
  91. package/dist/domain/bytecodeProvider.js +33 -35
  92. package/dist/domain/callPath.js +3 -2
  93. package/dist/domain/conformanceReplay.js +3 -3
  94. package/dist/domain/conformanceTrustGate.js +151 -16
  95. package/dist/domain/customProtocolCapture.js +3 -3
  96. package/dist/domain/electronActiveObservation.js +277 -0
  97. package/dist/domain/electronObservation.js +15 -11
  98. package/dist/domain/electronStaticAnalysisValues.js +4 -1
  99. package/dist/domain/eventProcessTree.js +82 -79
  100. package/dist/domain/functionComparisonNormalization.js +15 -8
  101. package/dist/domain/functionDossierEvidence.js +9 -4
  102. package/dist/domain/hopperValues.js +68 -71
  103. package/dist/domain/inputIssueProjection.js +4 -1
  104. package/dist/domain/investigationWorkspace.js +16 -15
  105. package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
  106. package/dist/domain/javascriptReplay.js +79 -63
  107. package/dist/domain/javascriptRuntimeObservation.js +1 -0
  108. package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
  109. package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
  110. package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
  111. package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
  112. package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
  113. package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
  114. package/dist/domain/knownPageCoverage.js +15 -7
  115. package/dist/domain/nativeApiBoundary.js +15 -7
  116. package/dist/domain/nodeRuntimeCharacterization.js +14 -13
  117. package/dist/domain/processCaptureReactiveValidation.js +8 -3
  118. package/dist/domain/processCaptureValidation.js +7 -3
  119. package/dist/domain/processComparison.js +12 -7
  120. package/dist/domain/processObservation.js +5 -6
  121. package/dist/domain/processReactiveMatching.js +14 -7
  122. package/dist/domain/processReactiveTransition.js +9 -3
  123. package/dist/domain/processScenario.js +6 -3
  124. package/dist/domain/processTraceComparison.js +3 -2
  125. package/dist/domain/protocolCapture.js +8 -6
  126. package/dist/domain/reconstructionReadinessSchemas.js +30 -2
  127. package/dist/domain/referenceSourceImportParsing.js +2 -2
  128. package/dist/domain/replayMachineRuntime.js +5 -3
  129. package/dist/domain/sourceToBundleComparison.js +2 -2
  130. package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
  131. package/dist/domain/sourceToBundleSignals.js +7 -1
  132. package/dist/domain/staticRuntimeCorrelation.js +7 -5
  133. package/dist/domain/webBundleAnalysis.js +14 -14
  134. package/dist/domain/webCaptureDiff.js +15 -12
  135. package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
  136. package/dist/generatedMcpToolCatalog.js +1 -1
  137. package/dist/generatedPackageMetadata.js +1 -1
  138. package/dist/ghidra/GhidraClient.js +1 -1
  139. package/dist/ghidra/GhidraClientStartup.js +1 -1
  140. package/dist/ghidra/GhidraFunctionValues.js +17 -15
  141. package/dist/ghidra/GhidraInventoryValues.js +57 -47
  142. package/dist/ghidra/GhidraProvider.js +18 -10
  143. package/dist/ghidra/GhidraProviderCapabilities.js +5 -1
  144. package/dist/ghidra/GhidraSocketConnection.js +1 -1
  145. package/dist/ghidra/protocol.js +19 -42
  146. package/dist/hopper/BridgeLauncher.js +3 -1
  147. package/dist/hopper/HopperAnalysisProfile.js +2 -4
  148. package/dist/hopper/HopperCleanup.js +5 -6
  149. package/dist/hopper/HopperClient.js +1 -1
  150. package/dist/hopper/HopperProvider.js +0 -14
  151. package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
  152. package/dist/main/reload.js +1 -6
  153. package/dist/main/state.js +0 -14
  154. package/dist/main/transport.js +30 -37
  155. package/dist/main.js +17 -15
  156. package/dist/mcpDoctor.js +2 -24
  157. package/dist/process/PrivateRuntimeRoot.js +17 -0
  158. package/dist/process/ProcessOwnership.js +64 -128
  159. package/dist/process/ProcessOwnershipIdentity.js +13 -0
  160. package/dist/process/ProcessOwnershipObservation.js +88 -0
  161. package/dist/process/ProcessOwnershipProcessTree.js +22 -0
  162. package/dist/process/ProviderDeadline.js +8 -12
  163. package/dist/process/WindowsAuthority.js +32 -0
  164. package/dist/reference/ReferenceSourceReader.js +3 -3
  165. package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
  166. package/dist/replay/JavaScriptReplayWorker.js +95 -11
  167. package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
  168. package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
  169. package/dist/replay/ReplayOutcome.js +26 -15
  170. package/dist/replay/ReplayWorkerProtocol.js +34 -29
  171. package/dist/server/createServer.js +158 -94
  172. package/dist/server/mcpClientMetadata.js +32 -0
  173. package/dist/server/registerApplicationTools/characterization.js +6 -13
  174. package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
  175. package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
  176. package/dist/server/registerApplicationTools/compareVersions.js +3 -8
  177. package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
  178. package/dist/server/registerApplicationTools/coverage.js +13 -19
  179. package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
  180. package/dist/server/registerApplicationTools/readiness.js +1 -6
  181. package/dist/server/registerApplicationTools/traceFeature.js +3 -8
  182. package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
  183. package/dist/server/registerArtifactComparisonTool.js +12 -16
  184. package/dist/server/registerBrowserScenarioTool.js +1 -6
  185. package/dist/server/registerBrowserTools.js +37 -79
  186. package/dist/server/registerBundleComparisonTool.js +10 -14
  187. package/dist/server/registerCloseLifecycleTool.js +6 -14
  188. package/dist/server/registerElectronTools.js +30 -47
  189. package/dist/server/registerEnhancedTools.js +114 -122
  190. package/dist/server/registerEvidenceTools.js +5 -9
  191. package/dist/server/registerFunctionComparisonTool.js +11 -15
  192. package/dist/server/registerInvestigationTools.js +41 -57
  193. package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
  194. package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
  195. package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
  196. package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
  197. package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
  198. package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
  199. package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
  200. package/dist/server/registerOfficialTools.js +8 -9
  201. package/dist/server/registerProcessComparisonTool.js +19 -24
  202. package/dist/server/registerReplayMachineTool.js +4 -10
  203. package/dist/server/registerSessionRecordTools.js +69 -40
  204. package/dist/server/registerSessionStatusTool.js +13 -28
  205. package/dist/server/registerSessionTools.js +36 -52
  206. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  207. package/dist/server/sessionToolPolicies.js +1 -5
  208. package/dist/server/toolRegistrationOptions.js +4 -192
  209. package/dist/server/toolResult.js +2 -18
  210. package/package.json +22 -14
  211. package/scripts/electron-active-hook-boundaries.cjs +394 -0
  212. package/scripts/electron-active-hook.cjs +501 -0
  213. package/scripts/rea.mjs +1 -11
  214. package/skills/reverse-engineer-anything/SKILL.md +2 -2
  215. package/dist/server/DynamicToolAvailability.js +0 -70
  216. package/dist/server/LazyToolCatalog.js +0 -134
  217. package/dist/server/hydrateServerTools.js +0 -191
  218. package/dist/server/toolInputValidation.js +0 -77
  219. package/scripts/package-runner-bootstrap.mjs +0 -72
@@ -1,7 +1,7 @@
1
1
  /** Generated from package.json and package-lock.json; do not edit. */
2
2
  export const PACKAGE_METADATA = {
3
3
  name: "rea-agents",
4
- version: "3.0.0", // x-release-please-version
4
+ version: "3.1.0", // x-release-please-version
5
5
  serverSdkVersion: "2.0.0",
6
6
  clientSdkVersion: "2.0.0",
7
7
  coreSdkVersion: "2.0.0",
@@ -369,7 +369,7 @@ export class GhidraClient {
369
369
  return err(failure);
370
370
  }
371
371
  #interruptionFailure(deadline) {
372
- return deadline.cancelled
372
+ return deadline.interruption === "cancelled"
373
373
  ? this.#failure("cancelled", "Ghidra startup was cancelled")
374
374
  : this.#failure("timeout", "Ghidra startup deadline elapsed", undefined, {
375
375
  timeoutMs: deadline.timeoutMs,
@@ -22,7 +22,7 @@ export async function completeGhidraStartupHandshake(options) {
22
22
  }
23
23
  return parsed;
24
24
  }
25
- const interruptionFailure = (options) => options.deadline.cancelled
25
+ const interruptionFailure = (options) => options.deadline.interruption === "cancelled"
26
26
  ? options.failure("cancelled", "Ghidra startup was cancelled")
27
27
  : options.failure("timeout", "Ghidra startup deadline elapsed", undefined, {
28
28
  timeoutMs: options.startupTimeoutMs,
@@ -1,7 +1,6 @@
1
1
  import { z } from "zod";
2
2
  import { AnalysisInputError, AnalysisOutputError } from "../domain/errors.js";
3
3
  import { functionInstructionWindowSchema, functionDossierSchema, } from "../domain/hopperValues.js";
4
- import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
5
4
  import { nativeApiBoundarySchema } from "../domain/nativeApiBoundary.js";
6
5
  import { err, ok } from "../domain/result.js";
7
6
  import { ghidraBoundedIdentifierSchema, ghidraCanonicalAddressSchema, } from "./GhidraInventoryValues.js";
@@ -90,7 +89,7 @@ const inputSchemas = {
90
89
  export const parseGhidraFunctionInput = (operation, value) => {
91
90
  const parsed = inputSchemas[operation].safeParse(value);
92
91
  return parsed.success
93
- ? ok(jsonObjectSchema.parse(parsed.data))
92
+ ? ok(parsed.data)
94
93
  : err(new AnalysisInputError(operation, { cause: parsed.error }));
95
94
  };
96
95
  const classification = z
@@ -143,15 +142,24 @@ const referenceEdge = z
143
142
  kind: referenceKind,
144
143
  })
145
144
  .strict();
146
- const boundedReferences = z
147
- .object({
145
+ const boundedReferenceFacts = {
148
146
  items: z.array(referenceEdge),
149
147
  total: z.number().int().min(0).nullable(),
150
148
  returned: z.number().int().min(0),
151
- truncated: z.boolean(),
152
- next_offset: z.number().int().min(0).nullable(),
153
- })
154
- .strict()
149
+ };
150
+ const boundedReferences = z
151
+ .discriminatedUnion("truncated", [
152
+ z.strictObject({
153
+ ...boundedReferenceFacts,
154
+ truncated: z.literal(false),
155
+ next_offset: z.null(),
156
+ }),
157
+ z.strictObject({
158
+ ...boundedReferenceFacts,
159
+ truncated: z.literal(true),
160
+ next_offset: z.number().int().min(0).nullable(),
161
+ }),
162
+ ])
155
163
  .superRefine((value, context) => {
156
164
  if (value.returned !== value.items.length)
157
165
  context.addIssue({
@@ -165,12 +173,6 @@ const boundedReferences = z
165
173
  path: ["total"],
166
174
  message: "total cannot be smaller than returned",
167
175
  });
168
- if (value.next_offset !== null && !value.truncated)
169
- context.addIssue({
170
- code: "custom",
171
- path: ["next_offset"],
172
- message: "a continuation requires truncated output",
173
- });
174
176
  });
175
177
  const procedureReferences = z
176
178
  .object({
@@ -287,7 +289,7 @@ const resultSchemas = {
287
289
  export const parseGhidraFunctionResult = (operation, value) => {
288
290
  const parsed = resultSchemas[operation].safeParse(value);
289
291
  return parsed.success
290
- ? ok(jsonValueSchema.parse(parsed.data))
292
+ ? ok(parsed.data)
291
293
  : err(new AnalysisOutputError(operation, "Ghidra bridge output did not match the function-analysis contract", { cause: parsed.error }));
292
294
  };
293
295
  const referenceAddresses = (edge) => [
@@ -1,6 +1,5 @@
1
1
  import { z } from "zod";
2
2
  import { AnalysisInputError, AnalysisOutputError } from "../domain/errors.js";
3
- import { jsonObjectSchema, jsonValueSchema, } from "../domain/jsonValue.js";
4
3
  import { err, ok } from "../domain/result.js";
5
4
  /** Read-only direct operations admitted by the Ghidra v1 adapter. */
6
5
  export const GHIDRA_INVENTORY_OPERATIONS = [
@@ -60,7 +59,7 @@ export const parseGhidraInventoryInput = (operation, value) => {
60
59
  const parsed = inputSchemas[operation].safeParse(value);
61
60
  if (!parsed.success)
62
61
  return err(new AnalysisInputError(operation, { cause: parsed.error }));
63
- return ok(jsonObjectSchema.parse(parsed.data));
62
+ return ok(parsed.data);
64
63
  };
65
64
  export const ghidraCanonicalAddressSchema = z
66
65
  .string()
@@ -104,50 +103,61 @@ const procedureItem = z
104
103
  .strict();
105
104
  const stringItem = z.object({ ...baseItem, string: stringFacts }).strict();
106
105
  const searchItem = z.object(baseItem).strict();
107
- const pageSchema = (item, maximumLimit) => z
108
- .object({
109
- items: z.array(item),
110
- offset: z.number().int().min(0),
111
- limit: z.number().int().min(1).max(maximumLimit),
112
- total: z.number().int().min(0),
113
- next_offset: z.number().int().min(0).nullable(),
114
- has_more: z.boolean(),
115
- })
116
- .strict()
117
- .superRefine((page, context) => {
118
- const next = page.offset + page.items.length;
119
- const hasMore = next < page.total;
120
- if (page.items.length > page.limit)
121
- context.addIssue({
122
- code: "custom",
123
- path: ["items"],
124
- message: "page exceeds its declared limit",
125
- });
126
- if (page.items.length > 0 && next > page.total)
127
- context.addIssue({
128
- code: "custom",
129
- path: ["total"],
130
- message: "page items exceed its exact total",
131
- });
132
- if (hasMore && page.items.length === 0)
133
- context.addIssue({
134
- code: "custom",
135
- path: ["items"],
136
- message: "page continuation must advance its offset",
137
- });
138
- if (page.has_more !== hasMore)
139
- context.addIssue({
140
- code: "custom",
141
- path: ["has_more"],
142
- message: "page continuation does not match its exact total",
143
- });
144
- if (page.next_offset !== (hasMore ? next : null))
145
- context.addIssue({
146
- code: "custom",
147
- path: ["next_offset"],
148
- message: "page continuation offset is inconsistent",
149
- });
150
- });
106
+ const pageSchema = (item, maximumLimit) => {
107
+ const pageFacts = {
108
+ items: z.array(item),
109
+ offset: z.number().int().min(0),
110
+ limit: z.number().int().min(1).max(maximumLimit),
111
+ total: z.number().int().min(0),
112
+ };
113
+ return z
114
+ .discriminatedUnion("has_more", [
115
+ z.strictObject({
116
+ ...pageFacts,
117
+ has_more: z.literal(true),
118
+ next_offset: z.number().int().min(0),
119
+ }),
120
+ z.strictObject({
121
+ ...pageFacts,
122
+ has_more: z.literal(false),
123
+ next_offset: z.null(),
124
+ }),
125
+ ])
126
+ .superRefine((page, context) => {
127
+ const next = page.offset + page.items.length;
128
+ const hasMore = next < page.total;
129
+ if (page.items.length > page.limit)
130
+ context.addIssue({
131
+ code: "custom",
132
+ path: ["items"],
133
+ message: "page exceeds its declared limit",
134
+ });
135
+ if (page.items.length > 0 && next > page.total)
136
+ context.addIssue({
137
+ code: "custom",
138
+ path: ["total"],
139
+ message: "page items exceed its exact total",
140
+ });
141
+ if (hasMore && page.items.length === 0)
142
+ context.addIssue({
143
+ code: "custom",
144
+ path: ["items"],
145
+ message: "page continuation must advance its offset",
146
+ });
147
+ if (page.has_more !== hasMore)
148
+ context.addIssue({
149
+ code: "custom",
150
+ path: ["has_more"],
151
+ message: "page continuation does not match its exact total",
152
+ });
153
+ if (page.next_offset !== (hasMore ? next : null))
154
+ context.addIssue({
155
+ code: "custom",
156
+ path: ["next_offset"],
157
+ message: "page continuation offset is inconsistent",
158
+ });
159
+ });
160
+ };
151
161
  const availablePermissions = z
152
162
  .object({
153
163
  available: z.literal(true),
@@ -212,6 +222,6 @@ const resultSchemas = {
212
222
  export const parseGhidraInventoryResult = (operation, value) => {
213
223
  const parsed = resultSchemas[operation].safeParse(value);
214
224
  return parsed.success
215
- ? ok(jsonValueSchema.parse(parsed.data))
225
+ ? ok(parsed.data)
216
226
  : err(new AnalysisOutputError(operation, "Ghidra bridge output did not match the inventory contract", { cause: parsed.error }));
217
227
  };
@@ -1,5 +1,6 @@
1
1
  import { fileURLToPath } from "node:url";
2
2
  import { createAnalysisExecution, } from "../application/AnalysisProvider.js";
3
+ import { jsonObjectSchema } from "../domain/jsonValue.js";
3
4
  import { AnalysisCancelledError, AnalysisCapabilityUnavailableError, AnalysisInputError, AnalysisTimeoutError, ProviderAdapterError, } from "../domain/errors.js";
4
5
  import { err, ok } from "../domain/result.js";
5
6
  import { GhidraClient } from "./GhidraClient.js";
@@ -10,9 +11,9 @@ import { ghidraInstallationDiagnostics, inspectGhidraInstallation, } from "./Ghi
10
11
  import { GhidraHeadlessLauncher } from "./GhidraLauncher.js";
11
12
  import { resolveGhidraAnalysisProfile } from "./GhidraAnalysisProfile.js";
12
13
  import { CAPABILITIES, WINDOWS_P0_CAPABILITIES, GHIDRA_PROVIDER_IDENTITY, GHIDRA_PROVIDER_TOOL_CONTRACTS, healthLimitations, windowsP0Limitations, limitationsFor, } from "./GhidraProviderCapabilities.js";
14
+ import { WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON, hasWindowsNativeAuthority, windowsNativeCapabilities, } from "../process/WindowsAuthority.js";
13
15
  export { GHIDRA_PROVIDER_IDENTITY, GHIDRA_PROVIDER_TOOL_CONTRACTS };
14
16
  const SUPPORTED_ARCHITECTURES = new Set(["x86", "x86_64", "arm", "arm64"]);
15
- const SUPPORTED_FORMATS = new Set(["elf", "pe", "mach-o"]);
16
17
  /** Ghidra candidate backed by an isolated read-only headless import. */
17
18
  export class GhidraProvider {
18
19
  config;
@@ -37,6 +38,18 @@ export class GhidraProvider {
37
38
  inspectAvailability() {
38
39
  const installation = this.#inspectInstallation();
39
40
  const diagnostics = ghidraInstallationDiagnostics(installation);
41
+ if (installation.available &&
42
+ installation.platform === "win32" &&
43
+ !hasWindowsNativeAuthority(installation.platform))
44
+ return {
45
+ status: "unavailable",
46
+ code: "unsupported_host",
47
+ reason: WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON,
48
+ diagnostics: {
49
+ ...diagnostics,
50
+ windows_security: jsonObjectSchema.parse(windowsNativeCapabilities(installation.platform)),
51
+ },
52
+ };
40
53
  return installation.available
41
54
  ? {
42
55
  status: "available",
@@ -70,15 +83,7 @@ export class GhidraProvider {
70
83
  };
71
84
  if (hostPlatform === "win32")
72
85
  return inspectWindowsP0TargetSupport(target, diagnostics);
73
- if (!SUPPORTED_FORMATS.has(target.format))
74
- return {
75
- status: "unsupported",
76
- code: "target_format_unsupported",
77
- reason: `Ghidra v1 does not import ${target.format} through this adapter.`,
78
- diagnostics,
79
- };
80
- if (target.architecture === undefined ||
81
- !SUPPORTED_ARCHITECTURES.has(target.architecture))
86
+ if (!SUPPORTED_ARCHITECTURES.has(target.architecture))
82
87
  return {
83
88
  status: "unsupported",
84
89
  code: "architecture_unsupported",
@@ -237,6 +242,9 @@ const ghidraClientPrerequisites = (target, profile, installation) => {
237
242
  return err(new ProviderAdapterError("ghidra", "health", {
238
243
  diagnostics: ghidraInstallationDiagnostics(installation),
239
244
  }));
245
+ if (installation.platform === "win32" &&
246
+ !hasWindowsNativeAuthority(installation.platform))
247
+ return err(new AnalysisCapabilityUnavailableError("ghidra", "health", WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON));
240
248
  if (profile === undefined || profile.provider.id !== "ghidra")
241
249
  return err(new ProviderAdapterError("ghidra", "health"));
242
250
  return ok({
@@ -1,3 +1,4 @@
1
+ import { WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON } from "../process/WindowsAuthority.js";
1
2
  import { GENERATED_MCP_TOOL_CATALOG } from "../generatedMcpToolCatalog.js";
2
3
  import { GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS, GHIDRA_MAX_LINE_BYTES, GHIDRA_REQUEST_TIMEOUT_MS, } from "./GhidraDefaults.js";
3
4
  import { GHIDRA_FUNCTION_OPERATIONS } from "./GhidraFunctionValues.js";
@@ -43,7 +44,7 @@ export const healthLimitations = Object.freeze([
43
44
  export const windowsP0Limitations = Object.freeze([
44
45
  "Windows Ghidra P0 accepts approved native x86-64 PE applications only; DLL, managed, hostile, sensitive, and mutable-path targets are unsupported.",
45
46
  "The Windows bridge uses authenticated IPv4 loopback because Node path-based IPC does not expose Java AF_UNIX sockets; the endpoint file contains no bearer token.",
46
- "Windows P0 process-tree cleanup uses bounded taskkill termination and does not claim Job Object ownership, private DACL enforcement, or reparse-point-safe path authority.",
47
+ "Windows P0 is not admitted until a native authority proves Job Object ownership, private DACL enforcement, and reparse-safe path admission; bounded taskkill cleanup and chmod(0700) do not prove those controls.",
47
48
  ]);
48
49
  /** Limitation text for one admitted operation, including the common base. */
49
50
  export const limitationsFor = (operation) => {
@@ -175,6 +176,9 @@ export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((co
175
176
  /** Capabilities advertised for the experimental Windows x64 P0 boundary. */
176
177
  export const WINDOWS_P0_CAPABILITIES = Object.freeze(CAPABILITIES.map((capability) => Object.freeze({
177
178
  ...capability,
179
+ available: false,
180
+ reason: WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON,
181
+ availabilityCode: "unsupported_host",
178
182
  limitations: Object.freeze([
179
183
  ...capability.limitations,
180
184
  ...windowsP0Limitations,
@@ -76,7 +76,7 @@ const connectGhidraSocketOnce = (target, signal) => new Promise((resolve) => {
76
76
  if (signal.aborted)
77
77
  onAbort();
78
78
  });
79
- const interruptionFailure = (options) => options.deadline.cancelled
79
+ const interruptionFailure = (options) => options.deadline.interruption === "cancelled"
80
80
  ? options.failure("cancelled", "Ghidra startup was cancelled")
81
81
  : options.failure("timeout", "Ghidra startup deadline elapsed", undefined, {
82
82
  timeoutMs: options.startupTimeoutMs,
@@ -1,46 +1,23 @@
1
1
  import { z } from "zod";
2
2
  import { jsonValueSchema } from "../domain/jsonValue.js";
3
3
  import { err, ok } from "../domain/result.js";
4
- const responseSchema = z
5
- .object({
6
- id: z.number().int().positive(),
7
- ok: z.boolean(),
8
- result: jsonValueSchema.optional(),
9
- error: z
10
- .object({
11
- code: z.string().min(1).max(128),
12
- message: z.string().min(1).max(4_096),
13
- })
14
- .strict()
15
- .optional(),
16
- })
17
- .strict()
18
- .superRefine((value, context) => {
19
- if (value.ok && value.result === undefined)
20
- context.addIssue({
21
- code: "custom",
22
- path: ["result"],
23
- message: "Successful Ghidra response requires a result",
24
- });
25
- if (!value.ok && value.error === undefined)
26
- context.addIssue({
27
- code: "custom",
28
- path: ["error"],
29
- message: "Failed Ghidra response requires an error",
30
- });
31
- if (!value.ok && value.result !== undefined)
32
- context.addIssue({
33
- code: "custom",
34
- path: ["result"],
35
- message: "Failed Ghidra response cannot include a result",
36
- });
37
- if (value.ok && value.error !== undefined)
38
- context.addIssue({
39
- code: "custom",
40
- path: ["error"],
41
- message: "Successful Ghidra response cannot include an error",
42
- });
43
- });
4
+ const responseSchema = z.discriminatedUnion("ok", [
5
+ z.strictObject({
6
+ id: z.number().int().positive(),
7
+ ok: z.literal(true),
8
+ result: jsonValueSchema,
9
+ }),
10
+ z.strictObject({
11
+ id: z.number().int().positive(),
12
+ ok: z.literal(false),
13
+ error: z
14
+ .object({
15
+ code: z.string().min(1).max(128),
16
+ message: z.string().min(1).max(4_096),
17
+ })
18
+ .strict(),
19
+ }),
20
+ ]);
44
21
  /** Expected operation failure returned by the authenticated Java bridge. */
45
22
  export class GhidraRemoteError extends Error {
46
23
  code;
@@ -65,5 +42,5 @@ export const parseGhidraResponseLine = (line) => {
65
42
  };
66
43
  /** Project one validated response into its result or remote failure. */
67
44
  export const ghidraResponseResult = (response) => response.ok
68
- ? ok(response.result ?? null)
69
- : err(new GhidraRemoteError(response.error?.code ?? "bridge_error", response.error?.message ?? "Ghidra bridge request failed"));
45
+ ? ok(response.result)
46
+ : err(new GhidraRemoteError(response.error.code, response.error.message));
@@ -99,7 +99,9 @@ export class HopperApplicationLauncher {
99
99
  process: child,
100
100
  ownsProcessLifetime: true,
101
101
  ownership: started.ownership,
102
- shutdownByCleanup: ownsProcessLifetime,
102
+ shutdownMode: ownsProcessLifetime
103
+ ? "process-cleanup"
104
+ : "bridge-request",
103
105
  cleanup: () => cleanupOwnedProcessGroup(started.ownership),
104
106
  });
105
107
  }
@@ -49,9 +49,9 @@ export const resolveHopperAnalysisProfile = async (target, options) => {
49
49
  export const hopperLoaderArgsForTarget = (target) => {
50
50
  if (target.kind === "database")
51
51
  return ok([]);
52
- const architecture = target.architecture;
53
- if (architecture === undefined)
52
+ if (target.kind !== "executable")
54
53
  return err(new ProviderAdapterError("hopper", "resolve_analysis_profile"));
54
+ const architecture = target.architecture;
55
55
  const flag = hopperArchitectureFlag(architecture);
56
56
  switch (target.format) {
57
57
  case "mach-o":
@@ -62,8 +62,6 @@ export const hopperLoaderArgsForTarget = (target) => {
62
62
  return ok(["-l", "ELF", flag]);
63
63
  case "pe":
64
64
  return ok(["-l", "WinPE", flag]);
65
- default:
66
- return err(new ProviderAdapterError("hopper", "resolve_analysis_profile"));
67
65
  }
68
66
  };
69
67
  const hopperArchitectureFlag = (architecture) => {
@@ -10,7 +10,6 @@ export const cleanupHopperSession = async (input) => {
10
10
  resources: new Set(),
11
11
  cleanupResult: undefined,
12
12
  shutdownConfirmed: false,
13
- ownedProcessStopped: false,
14
13
  };
15
14
  await report(input.progress, 0, "requesting Hopper document shutdown");
16
15
  await requestShutdown(input, state);
@@ -38,8 +37,7 @@ const requestShutdown = async (input, state) => {
38
37
  .catch(() => err(new HopperProcessError(null)));
39
38
  if (shutdown.ok &&
40
39
  isHopperCleanupRequired(shutdown.value) &&
41
- input.launch?.shutdownByCleanup === true &&
42
- input.launch.cleanup !== undefined) {
40
+ input.launch?.shutdownMode === "process-cleanup") {
43
41
  state.cleanupResult = await input.launch
44
42
  .cleanup()
45
43
  .catch(providerCleanupFailure);
@@ -82,7 +80,9 @@ const stopProcess = async (input, state) => {
82
80
  }
83
81
  input.logger.info(diagnostic, "Owned Hopper launcher shutdown completed");
84
82
  if (stopped.status !== "incomplete") {
85
- state.ownedProcessStopped = stopped.status !== "not-owned";
83
+ if (input.launch?.shutdownMode === "process-cleanup" &&
84
+ stopped.status !== "not-owned")
85
+ state.shutdownConfirmed = true;
86
86
  return;
87
87
  }
88
88
  const processGroupId = supervisor.launch.ownership?.processGroupId;
@@ -95,8 +95,7 @@ const stopProcess = async (input, state) => {
95
95
  };
96
96
  const recordUnconfirmedDocument = (input, state) => {
97
97
  if ((input.socket === undefined && input.launch === undefined) ||
98
- state.shutdownConfirmed ||
99
- state.ownedProcessStopped)
98
+ state.shutdownConfirmed)
100
99
  return;
101
100
  state.resources.add("hopper-document");
102
101
  state.issues.push({
@@ -399,6 +399,6 @@ export class HopperClient {
399
399
  }
400
400
  }
401
401
  const isAborted = (signal) => signal?.aborted === true;
402
- const startupInterruption = (deadline) => deadline.cancelled
402
+ const startupInterruption = (deadline) => deadline.interruption === "cancelled"
403
403
  ? new HopperCancelledError()
404
404
  : new HopperTimeoutError(deadline.timeoutMs);
@@ -129,20 +129,6 @@ export class HopperProvider {
129
129
  reason: null,
130
130
  diagnostics,
131
131
  };
132
- if (!["mach-o", "elf", "pe"].includes(target.format))
133
- return {
134
- status: "unsupported",
135
- code: "target_format_unsupported",
136
- reason: `Hopper cannot open ${target.format} through this adapter.`,
137
- diagnostics,
138
- };
139
- if (target.architecture === undefined)
140
- return {
141
- status: "unsupported",
142
- code: "architecture_unsupported",
143
- reason: "Hopper requires a supported concrete target architecture.",
144
- diagnostics,
145
- };
146
132
  return {
147
133
  status: "supported",
148
134
  code: null,
@@ -42,7 +42,7 @@ export const selectLinuxPrivateDisplayStrategy = async (options) => {
42
42
  /** Run one helper probe in an owned process group with a hard output bound. */
43
43
  export const runLinuxPrivateDisplayProbe = async (strategy, options) => {
44
44
  if (options.signal?.aborted === true)
45
- return emptyProcessResult({ cancelled: true });
45
+ return emptyProcessResult("cancelled");
46
46
  const command = privateDisplayProbeCommand(options.helperPath, strategy);
47
47
  let started;
48
48
  try {
@@ -54,7 +54,7 @@ export const runLinuxPrivateDisplayProbe = async (strategy, options) => {
54
54
  });
55
55
  }
56
56
  catch {
57
- return emptyProcessResult();
57
+ return emptyProcessResult("launch-failed");
58
58
  }
59
59
  const launch = {
60
60
  process: started.process,
@@ -74,12 +74,15 @@ export const runLinuxPrivateDisplayProbe = async (strategy, options) => {
74
74
  supervisor.dispose();
75
75
  const snapshot = supervisor.snapshot();
76
76
  return {
77
+ outcome: outcome === "exit"
78
+ ? "exited"
79
+ : outcome === "timeout"
80
+ ? "timed-out"
81
+ : "cancelled",
77
82
  exitCode: snapshot.exitCode,
78
83
  stderr: snapshot.stderr.text,
79
84
  stderrBytes: snapshot.stderr.bytes,
80
85
  stderrTruncated: snapshot.stderr.truncated,
81
- timedOut: outcome === "timeout",
82
- cancelled: outcome === "cancelled",
83
86
  cleanupIncomplete,
84
87
  };
85
88
  };
@@ -119,16 +122,21 @@ const evaluatedProbe = async (strategy, options, timeoutMs, runner) => {
119
122
  diagnostic: syntheticDiagnostic(strategy, "probe_failed"),
120
123
  };
121
124
  }
122
- if (processResult.cancelled)
125
+ if (processResult.outcome === "cancelled")
123
126
  return {
124
127
  ok: false,
125
128
  diagnostic: syntheticDiagnostic(strategy, "cancelled"),
126
129
  };
127
- if (processResult.timedOut)
130
+ if (processResult.outcome === "timed-out")
128
131
  return {
129
132
  ok: false,
130
133
  diagnostic: syntheticDiagnostic(strategy, "probe_timeout"),
131
134
  };
135
+ if (processResult.outcome === "launch-failed")
136
+ return {
137
+ ok: false,
138
+ diagnostic: syntheticDiagnostic(strategy, "probe_failed"),
139
+ };
132
140
  if (processResult.cleanupIncomplete)
133
141
  return {
134
142
  ok: false,
@@ -182,15 +190,13 @@ const unavailable = (diagnostic) => ({
182
190
  : (hopperStartupExitCode(diagnostic.failure_code) ?? 70),
183
191
  diagnostic: { ...diagnostic, strategy: "unavailable" },
184
192
  });
185
- const emptyProcessResult = (overrides = {}) => ({
193
+ const emptyProcessResult = (outcome) => ({
194
+ outcome,
186
195
  exitCode: undefined,
187
196
  stderr: "",
188
197
  stderrBytes: 0,
189
198
  stderrTruncated: false,
190
- timedOut: false,
191
- cancelled: false,
192
199
  cleanupIncomplete: false,
193
- ...overrides,
194
200
  });
195
201
  const waitForProbeExit = async (supervisor, timeoutMs, signal) => {
196
202
  if (signal?.aborted === true)
@@ -2,7 +2,7 @@ import { parseConfig } from "../config.js";
2
2
  import { readProjectPermissionStore } from "../application/ProjectPermissionStore.js";
3
3
  import { MCP_PERMISSION_RELOAD_FAILED } from "./messages.js";
4
4
  export const registerConfigReload = (input) => {
5
- const { dependencies, permissionAuthority, runtimeState, liveServers, serverLogger, } = input;
5
+ const { dependencies, permissionAuthority, runtimeState, serverLogger } = input;
6
6
  let reloadQueue = Promise.resolve();
7
7
  return (dependencies.registerReload?.(() => {
8
8
  const refreshed = parseConfig(dependencies.env);
@@ -33,14 +33,9 @@ export const registerConfigReload = (input) => {
33
33
  return;
34
34
  }
35
35
  runtimeState.currentConfig = refreshed.value;
36
- Object.assign(runtimeState.processPolicy, refreshed.value.processExecutionPolicy);
37
36
  Object.assign(runtimeState.evidencePolicy, refreshed.value.evidenceFilePolicy);
38
37
  Object.assign(runtimeState.snapshotPolicy, refreshed.value.analysisSnapshotFilePolicy);
39
38
  runtimeState.investigationRoots.splice(0, runtimeState.investigationRoots.length, ...refreshed.value.investigationInputRoots);
40
- Object.assign(runtimeState.javascriptReplayPolicy, refreshed.value.javascriptReplayPolicy);
41
- Object.assign(runtimeState.managedRuntimePolicy, refreshed.value.managedRuntimePolicy);
42
- for (const server of liveServers)
43
- server.sendToolListChanged();
44
39
  })
45
40
  .catch(() => {
46
41
  serverLogger.error(MCP_PERMISSION_RELOAD_FAILED);
@@ -1,11 +1,5 @@
1
1
  export const createRuntimeState = (config) => ({
2
2
  currentConfig: config,
3
- processPolicy: {
4
- ...config.processExecutionPolicy,
5
- executableRoots: [...config.processExecutionPolicy.executableRoots],
6
- workingRoots: [...config.processExecutionPolicy.workingRoots],
7
- allowedEnvironment: [...config.processExecutionPolicy.allowedEnvironment],
8
- },
9
3
  evidencePolicy: {
10
4
  ...config.evidenceFilePolicy,
11
5
  roots: [...config.evidenceFilePolicy.roots],
@@ -15,12 +9,4 @@ export const createRuntimeState = (config) => ({
15
9
  roots: [...config.analysisSnapshotFilePolicy.roots],
16
10
  },
17
11
  investigationRoots: [...config.investigationInputRoots],
18
- javascriptReplayPolicy: {
19
- ...config.javascriptReplayPolicy,
20
- roots: [...config.javascriptReplayPolicy.roots],
21
- },
22
- managedRuntimePolicy: {
23
- ...config.managedRuntimePolicy,
24
- roots: [...config.managedRuntimePolicy.roots],
25
- },
26
12
  });