rea-agents 2.5.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.
- package/README.md +20 -12
- package/bridge/ghidra/ReaGhidraBridge.java +477 -4
- package/bridge/hopper_bridge.py +54 -4
- package/dist/application/AnalysisContextQueries.js +142 -0
- package/dist/application/AnalysisSnapshotCache.js +4 -2
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +19 -11
- package/dist/application/ArtifactInventory/policy.js +17 -0
- package/dist/application/ArtifactInventory/reader.js +1 -4
- package/dist/application/ArtifactInventory/scanCanonical.js +0 -3
- package/dist/application/ArtifactInventory/scanReader.js +7 -7
- package/dist/application/ArtifactInventory/types.js +1 -5
- package/dist/application/BinarySession.js +19 -20
- package/dist/application/BinarySessionComposition.js +21 -0
- package/dist/application/BinarySessionRecords.js +106 -10
- package/dist/application/BinarySessionStatus.js +11 -5
- package/dist/application/BrowserEvidence.js +3 -5
- package/dist/application/CapabilityClientRequirements.js +26 -0
- package/dist/application/CapabilityInventory.js +140 -55
- package/dist/application/ClientRegistrationStatus.js +4 -1
- package/dist/application/CrossVersionInventory.js +7 -6
- package/dist/application/DirectAnalysis.js +6 -2
- package/dist/application/ElectronActiveEvidence.js +55 -0
- package/dist/application/ElectronActiveObservationPort.js +1 -0
- package/dist/application/ElectronActiveObservationService.js +81 -0
- package/dist/application/EnhancedTools.js +49 -17
- package/dist/application/EvidenceBundleCommands.js +5 -1
- package/dist/application/EvidenceLedger.js +53 -17
- package/dist/application/JavaScriptArtifactAnalysis.js +13 -4
- package/dist/application/JavaScriptReplayPermission.js +1 -1
- package/dist/application/JavaScriptReplayService.js +23 -15
- package/dist/application/LazyAnalysisProvider.js +77 -0
- package/dist/application/LoopbackReplay.js +1 -1
- package/dist/application/ManagedRuntimeCorrelationService.js +9 -5
- package/dist/application/NativeApiInspection.js +80 -0
- package/dist/application/NodeRuntimeCharacterizationService.js +8 -9
- package/dist/application/ProcessCaptureLifecycle.js +5 -0
- package/dist/application/ProcessCli.js +2 -1
- package/dist/application/ProcessHarness.js +8 -3
- package/dist/application/ProcessNormalization.js +2 -1
- package/dist/application/ProjectPermissionStore.js +1 -0
- package/dist/application/ReferenceSourceImport.js +2 -2
- package/dist/application/SessionProviderRouter.js +6 -6
- package/dist/application/SetupClientConfiguration.js +10 -3
- package/dist/application/WindowsCapabilities.js +5 -4
- package/dist/application/runtime.js +26 -9
- package/dist/artifacts/ArtifactProvider.js +8 -10
- package/dist/artifacts/SafeOutputTree.js +7 -8
- package/dist/browser/CdpCaptureStorageFingerprints.js +10 -7
- package/dist/browser/CdpElectronInspection.js +3 -1
- package/dist/browser/JavaScriptRuntimeScope.js +5 -0
- package/dist/browser/PlaywrightBrowserScenarioProvider.js +8 -2
- package/dist/browser/PlaywrightElectronActiveActions.js +324 -0
- package/dist/browser/PlaywrightElectronActiveProvider.js +294 -0
- package/dist/browser/PlaywrightScenarioBrowser.js +4 -4
- package/dist/browser/PlaywrightScenarioSession.js +4 -4
- package/dist/browser/SensitiveTextCapture.js +1 -1
- package/dist/browser/V8InspectorCaptureProjection.js +1 -0
- package/dist/browser/V8InspectorProvider.js +3 -3
- package/dist/catalogIdentity.js +15 -9
- package/dist/cli/artifactCommands.js +5 -3
- package/dist/cli/coreAnalysisCommands.js +41 -0
- package/dist/cli/managedCommands.js +1 -1
- package/dist/cliApplicationCommands.js +2 -2
- package/dist/cliBrowserAdvancedCommands.js +11 -5
- package/dist/cliBrowserCommands.js +14 -7
- package/dist/cliCommandNames.js +2 -0
- package/dist/cliElectronCommands.js +46 -4
- package/dist/cliJavaScriptRuntimeCommands.js +14 -6
- package/dist/cliObservationOptions.js +4 -0
- package/dist/cliPolicyCommands.js +1 -0
- package/dist/config/browserScenario.js +77 -0
- package/dist/config/electronAutomation.js +35 -0
- package/dist/config/environment.js +6 -0
- package/dist/config/javascriptReplay.js +41 -0
- package/dist/config/managedRuntime.js +25 -0
- package/dist/config/parseConfig.js +56 -200
- package/dist/config/parsers.js +10 -1
- package/dist/config/passiveObservation.js +157 -0
- package/dist/config/processCapture.js +47 -0
- package/dist/contracts/applicationToolContracts.js +2 -5
- package/dist/contracts/applicationWorkflowInputContracts.js +86 -96
- package/dist/contracts/artifactToolContracts.js +35 -37
- package/dist/contracts/browserToolContracts.js +2 -2
- package/dist/contracts/electronToolContracts.js +30 -1
- package/dist/contracts/enhancedInputs.js +21 -27
- package/dist/contracts/functionWorkflowToolContracts.js +29 -0
- package/dist/contracts/managedToolContracts.js +4 -9
- package/dist/contracts/managedWorkflowExamples.js +12 -9
- package/dist/contracts/managedWorkflowToolContracts.js +30 -27
- package/dist/contracts/nativeToolContracts.js +2 -3
- package/dist/contracts/promptContracts.js +14 -15
- package/dist/contracts/sessionToolSchemas.js +61 -0
- package/dist/contracts/toolContractExamples.js +4 -0
- package/dist/contracts/toolContractHelpers.js +23 -0
- package/dist/contracts/toolContracts.js +12 -67
- package/dist/contracts/toolEffects.js +19 -0
- package/dist/contracts/toolOutputSchemaGroups.js +66 -11
- package/dist/contracts/toolOutputSchemaPrimitives.js +76 -26
- package/dist/contracts/toolSchemaMetadata.js +128 -0
- package/dist/doctorRuntime.js +1 -1
- package/dist/domain/analysisErrorPresentation.js +8 -2
- package/dist/domain/analysisErrorProjection.js +1 -0
- package/dist/domain/androidApplication.js +2 -0
- package/dist/domain/appleApplication.js +2 -0
- package/dist/domain/binaryTarget.js +7 -5
- package/dist/domain/binaryTargetTypes.js +1 -0
- package/dist/domain/browserCaptureComparison.js +21 -69
- package/dist/domain/browserObservation.js +22 -9
- package/dist/domain/bytecodeProvider.js +177 -0
- package/dist/domain/callPath.js +3 -2
- package/dist/domain/conformancePackage.js +169 -0
- package/dist/domain/conformanceReplay.js +104 -0
- package/dist/domain/conformanceTrustGate.js +328 -0
- package/dist/domain/customProtocolCapture.js +137 -0
- package/dist/domain/electronActiveObservation.js +277 -0
- package/dist/domain/electronObservation.js +15 -11
- package/dist/domain/electronStaticAnalysisValues.js +4 -1
- package/dist/domain/eventProcessTree.js +217 -0
- package/dist/domain/evidenceBundle.js +47 -0
- package/dist/domain/functionComparisonNormalization.js +15 -8
- package/dist/domain/functionDossierEvidence.js +9 -4
- package/dist/domain/hopperStartupFailure.js +1 -1
- package/dist/domain/hopperValues.js +68 -68
- package/dist/domain/inputIssueProjection.js +11 -2
- package/dist/domain/investigationWorkspace.js +16 -15
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +2 -2
- package/dist/domain/javascriptReplay.js +79 -63
- package/dist/domain/javascriptRuntimeObservation.js +1 -0
- package/dist/domain/javascriptRuntimeReconciliationActive.js +89 -0
- package/dist/domain/javascriptRuntimeReconciliationGraph.js +11 -10
- package/dist/domain/javascriptRuntimeReconciliationMatching.js +57 -49
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +5 -1
- package/dist/domain/javascriptRuntimeReconciliationResult.js +21 -14
- package/dist/domain/javascriptRuntimeReconciliationSchemas.js +1 -1
- package/dist/domain/javascriptSemanticAnalysis.js +8 -12
- package/dist/domain/javascriptSourceParser.js +15 -0
- package/dist/domain/javascriptStaticAnalysis.js +8 -12
- package/dist/domain/knownPageCoverage.js +15 -7
- package/dist/domain/mobileApplicationInvestigation.js +159 -0
- package/dist/domain/nativeApiBoundary.js +138 -0
- package/dist/domain/nodeRuntimeCharacterization.js +14 -13
- package/dist/domain/objcSwiftMetadata.js +150 -0
- package/dist/domain/packageAnalysis.js +123 -0
- package/dist/domain/peInspection.js +196 -0
- package/dist/domain/processCaptureReactiveValidation.js +8 -3
- package/dist/domain/processCaptureValidation.js +7 -3
- package/dist/domain/processComparison.js +12 -7
- package/dist/domain/processObservation.js +5 -6
- package/dist/domain/processReactiveMatching.js +14 -7
- package/dist/domain/processReactiveTransition.js +9 -3
- package/dist/domain/processScenario.js +6 -3
- package/dist/domain/processTraceComparison.js +3 -2
- package/dist/domain/protocolCapture.js +245 -0
- package/dist/domain/reconstructionReadinessSchemas.js +30 -2
- package/dist/domain/referenceSourceImportParsing.js +2 -2
- package/dist/domain/replayMachineRuntime.js +5 -3
- package/dist/domain/sourceToBundleComparison.js +2 -2
- package/dist/domain/sourceToBundleComparisonSchemas.js +8 -8
- package/dist/domain/sourceToBundleSignals.js +7 -1
- package/dist/domain/staticRuntimeCorrelation.js +7 -5
- package/dist/domain/webBundleAnalysis.js +14 -14
- package/dist/domain/webCaptureDiff.js +15 -12
- package/dist/dotnet/ManagedNativeBoundaryInspector.js +2 -3
- package/dist/dotnet/ManagedStaticProvider.js +34 -5
- package/dist/generatedMcpToolCatalog.js +37 -0
- package/dist/generatedPackageMetadata.js +4 -4
- package/dist/ghidra/GhidraClient.js +1 -1
- package/dist/ghidra/GhidraClientStartup.js +1 -1
- package/dist/ghidra/GhidraDefaults.js +1 -1
- package/dist/ghidra/GhidraFunctionValues.js +44 -16
- package/dist/ghidra/GhidraInventoryValues.js +57 -47
- package/dist/ghidra/GhidraProvider.js +18 -10
- package/dist/ghidra/GhidraProviderCapabilities.js +45 -39
- package/dist/ghidra/GhidraSocketConnection.js +1 -1
- package/dist/ghidra/protocol.js +19 -42
- package/dist/hopper/BridgeLauncher.js +3 -1
- package/dist/hopper/HopperAnalysisProfile.js +2 -4
- package/dist/hopper/HopperCleanup.js +5 -6
- package/dist/hopper/HopperClient.js +27 -3
- package/dist/hopper/HopperProvider.js +42 -44
- package/dist/hopper/HopperRequestQueue.js +32 -4
- package/dist/hopper/HopperResponseStream.js +2 -2
- package/dist/hopper/LinuxPrivateDisplayProbe.js +16 -10
- package/dist/hopper/protocol.js +63 -21
- package/dist/main/reload.js +1 -6
- package/dist/main/state.js +0 -14
- package/dist/main/transport.js +31 -41
- package/dist/main.js +17 -13
- package/dist/mcpDoctor.js +4 -26
- package/dist/mcpStartupPolicy.js +14 -0
- package/dist/process/PrivateRuntimeRoot.js +17 -0
- package/dist/process/ProcessOwnership.js +64 -128
- package/dist/process/ProcessOwnershipIdentity.js +13 -0
- package/dist/process/ProcessOwnershipObservation.js +88 -0
- package/dist/process/ProcessOwnershipProcessTree.js +22 -0
- package/dist/process/ProviderDeadline.js +8 -12
- package/dist/process/WindowsAuthority.js +32 -0
- package/dist/reference/ReferenceSourceReader.js +3 -3
- package/dist/reference/ReferenceSourceReaderEntries.js +2 -2
- package/dist/replay/JavaScriptReplayWorker.js +95 -11
- package/dist/replay/JavaScriptReplayWorkerTypes.js +1 -0
- package/dist/replay/LinuxJavaScriptReplayRunner.js +10 -15
- package/dist/replay/ReplayOutcome.js +26 -15
- package/dist/replay/ReplayWorkerProtocol.js +34 -29
- package/dist/server/createServer.js +101 -144
- package/dist/server/mcpClientMetadata.js +32 -0
- package/dist/server/registerApplicationTools/characterization.js +6 -13
- package/dist/server/registerApplicationTools/compareExportShapes.js +2 -7
- package/dist/server/registerApplicationTools/compareSourceToBundle.js +2 -7
- package/dist/server/registerApplicationTools/compareVersions.js +3 -8
- package/dist/server/registerApplicationTools/controlledReplay.js +6 -11
- package/dist/server/registerApplicationTools/coverage.js +13 -19
- package/dist/server/registerApplicationTools/obligationLedger.js +1 -6
- package/dist/server/registerApplicationTools/readiness.js +1 -6
- package/dist/server/registerApplicationTools/traceFeature.js +3 -8
- package/dist/server/registerApplicationTools/traceSemantics.js +1 -6
- package/dist/server/registerArtifactComparisonTool.js +12 -16
- package/dist/server/registerBrowserScenarioTool.js +1 -6
- package/dist/server/registerBrowserTools.js +37 -79
- package/dist/server/registerBundleComparisonTool.js +10 -14
- package/dist/server/registerCloseLifecycleTool.js +6 -14
- package/dist/server/registerElectronTools.js +30 -47
- package/dist/server/registerEnhancedTools.js +124 -122
- package/dist/server/registerEvidenceResources.js +50 -101
- package/dist/server/registerEvidenceTools.js +5 -9
- package/dist/server/registerFunctionComparisonTool.js +11 -15
- package/dist/server/registerInvestigationTools.js +42 -59
- package/dist/server/registerJavaScriptApplicationGraphResource.js +0 -4
- package/dist/server/registerJavaScriptRuntimeObservationTools.js +13 -27
- package/dist/server/registerManagedWorkflowTools/compareManagedMembers.js +4 -9
- package/dist/server/registerManagedWorkflowTools/contract.js +2 -3
- package/dist/server/registerManagedWorkflowTools/importManagedReconstruction.js +3 -8
- package/dist/server/registerManagedWorkflowTools/planManagedRuntimeCorrelation.js +3 -8
- package/dist/server/registerManagedWorkflowTools/projectManagedApplicationGraph.js +8 -13
- package/dist/server/registerManagedWorkflowTools/verifyManagedNativeBoundaries.js +4 -9
- package/dist/server/registerOfficialTools.js +8 -9
- package/dist/server/registerProcessComparisonTool.js +19 -24
- package/dist/server/registerReconstructionObligationLedgerResource.js +0 -7
- package/dist/server/registerReconstructionReadinessResource.js +0 -7
- package/dist/server/registerReplayMachineTool.js +4 -10
- package/dist/server/registerSessionRecordTools.js +146 -47
- package/dist/server/registerSessionStatusTool.js +14 -29
- package/dist/server/registerSessionTools.js +45 -41
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/server/sessionToolPolicies.js +1 -5
- package/dist/server/toolRegistrationOptions.js +4 -177
- package/dist/server/toolResult.js +14 -18
- package/package.json +35 -16
- package/scripts/electron-active-hook-boundaries.cjs +394 -0
- package/scripts/electron-active-hook.cjs +501 -0
- package/skills/reverse-engineer-anything/SKILL.md +10 -3
- package/dist/server/DynamicToolAvailability.js +0 -70
- package/dist/server/toolInputValidation.js +0 -77
|
@@ -1,9 +1,9 @@
|
|
|
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: "
|
|
5
|
-
serverSdkVersion: "2.0.0
|
|
6
|
-
clientSdkVersion: "2.0.0
|
|
7
|
-
coreSdkVersion: "2.0.0
|
|
4
|
+
version: "3.1.0", // x-release-please-version
|
|
5
|
+
serverSdkVersion: "2.0.0",
|
|
6
|
+
clientSdkVersion: "2.0.0",
|
|
7
|
+
coreSdkVersion: "2.0.0",
|
|
8
8
|
skillVersion: "23",
|
|
9
9
|
};
|
|
@@ -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,
|
|
@@ -17,4 +17,4 @@ export const GHIDRA_MAX_QUEUED_REQUESTS = 32;
|
|
|
17
17
|
/** Maximum encoded response line accepted from the Java bridge. */
|
|
18
18
|
export const GHIDRA_MAX_LINE_BYTES = 1024 * 1024;
|
|
19
19
|
/** Version of REA's Java bridge handshake and request protocol. */
|
|
20
|
-
export const GHIDRA_BRIDGE_VERSION =
|
|
20
|
+
export const GHIDRA_BRIDGE_VERSION = 6;
|
|
@@ -1,7 +1,7 @@
|
|
|
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 {
|
|
4
|
+
import { nativeApiBoundarySchema } from "../domain/nativeApiBoundary.js";
|
|
5
5
|
import { err, ok } from "../domain/result.js";
|
|
6
6
|
import { ghidraBoundedIdentifierSchema, ghidraCanonicalAddressSchema, } from "./GhidraInventoryValues.js";
|
|
7
7
|
/** Read-only function operations admitted by the Ghidra adapter. */
|
|
@@ -89,7 +89,7 @@ const inputSchemas = {
|
|
|
89
89
|
export const parseGhidraFunctionInput = (operation, value) => {
|
|
90
90
|
const parsed = inputSchemas[operation].safeParse(value);
|
|
91
91
|
return parsed.success
|
|
92
|
-
? ok(
|
|
92
|
+
? ok(parsed.data)
|
|
93
93
|
: err(new AnalysisInputError(operation, { cause: parsed.error }));
|
|
94
94
|
};
|
|
95
95
|
const classification = z
|
|
@@ -142,15 +142,24 @@ const referenceEdge = z
|
|
|
142
142
|
kind: referenceKind,
|
|
143
143
|
})
|
|
144
144
|
.strict();
|
|
145
|
-
const
|
|
146
|
-
.object({
|
|
145
|
+
const boundedReferenceFacts = {
|
|
147
146
|
items: z.array(referenceEdge),
|
|
148
147
|
total: z.number().int().min(0).nullable(),
|
|
149
148
|
returned: z.number().int().min(0),
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
.
|
|
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
|
+
])
|
|
154
163
|
.superRefine((value, context) => {
|
|
155
164
|
if (value.returned !== value.items.length)
|
|
156
165
|
context.addIssue({
|
|
@@ -164,12 +173,6 @@ const boundedReferences = z
|
|
|
164
173
|
path: ["total"],
|
|
165
174
|
message: "total cannot be smaller than returned",
|
|
166
175
|
});
|
|
167
|
-
if (value.next_offset !== null && !value.truncated)
|
|
168
|
-
context.addIssue({
|
|
169
|
-
code: "custom",
|
|
170
|
-
path: ["next_offset"],
|
|
171
|
-
message: "a continuation requires truncated output",
|
|
172
|
-
});
|
|
173
176
|
});
|
|
174
177
|
const procedureReferences = z
|
|
175
178
|
.object({
|
|
@@ -191,7 +194,32 @@ const procedureInfo = z
|
|
|
191
194
|
classification,
|
|
192
195
|
})
|
|
193
196
|
.strict();
|
|
194
|
-
const
|
|
197
|
+
const ghidraNativeApiBoundary = nativeApiBoundarySchema.superRefine((value, context) => {
|
|
198
|
+
if (!value.available)
|
|
199
|
+
return;
|
|
200
|
+
if (value.provenance !== "ghidra-high-function")
|
|
201
|
+
context.addIssue({
|
|
202
|
+
code: "custom",
|
|
203
|
+
message: "Ghidra native API observations require HighFunction provenance",
|
|
204
|
+
});
|
|
205
|
+
const addresses = value.jump_tables.flatMap((table) => [
|
|
206
|
+
table.dispatch_address,
|
|
207
|
+
...table.data_sources.map(({ address }) => address),
|
|
208
|
+
...table.mappings.flatMap(({ target_address, data_addresses }) => [
|
|
209
|
+
target_address,
|
|
210
|
+
...data_addresses,
|
|
211
|
+
]),
|
|
212
|
+
]);
|
|
213
|
+
if (addresses.some((address) => !ghidraCanonicalAddressSchema.safeParse(address).success))
|
|
214
|
+
context.addIssue({
|
|
215
|
+
code: "custom",
|
|
216
|
+
message: "Ghidra native API observation contains a non-canonical address",
|
|
217
|
+
});
|
|
218
|
+
});
|
|
219
|
+
const ghidraFunctionDossier = functionDossierSchema
|
|
220
|
+
.extend({ native_api: ghidraNativeApiBoundary })
|
|
221
|
+
.strict()
|
|
222
|
+
.superRefine((value, context) => {
|
|
195
223
|
const addresses = [
|
|
196
224
|
value.procedure.address,
|
|
197
225
|
...value.comments.items.map(({ address }) => address),
|
|
@@ -261,7 +289,7 @@ const resultSchemas = {
|
|
|
261
289
|
export const parseGhidraFunctionResult = (operation, value) => {
|
|
262
290
|
const parsed = resultSchemas[operation].safeParse(value);
|
|
263
291
|
return parsed.success
|
|
264
|
-
? ok(
|
|
292
|
+
? ok(parsed.data)
|
|
265
293
|
: err(new AnalysisOutputError(operation, "Ghidra bridge output did not match the function-analysis contract", { cause: parsed.error }));
|
|
266
294
|
};
|
|
267
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(
|
|
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) =>
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
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(
|
|
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 (!
|
|
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,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON } from "../process/WindowsAuthority.js";
|
|
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";
|
|
4
5
|
import { GHIDRA_INVENTORY_OPERATIONS } from "./GhidraInventoryValues.js";
|
|
@@ -8,10 +9,7 @@ export const GHIDRA_PROVIDER_IDENTITY = Object.freeze({
|
|
|
8
9
|
name: "Ghidra",
|
|
9
10
|
version: null,
|
|
10
11
|
});
|
|
11
|
-
const providerContractByName = new Map(
|
|
12
|
-
contract.name,
|
|
13
|
-
contract,
|
|
14
|
-
]));
|
|
12
|
+
const providerContractByName = new Map(GENERATED_MCP_TOOL_CATALOG.filter(({ kind }) => kind === "official-proxy" || kind === "enhanced").map((contract) => [contract.name, contract]));
|
|
15
13
|
/** Provider-neutral read-only contracts implemented by the Ghidra adapter. */
|
|
16
14
|
export const GHIDRA_PROVIDER_TOOL_CONTRACTS = Object.freeze([...GHIDRA_INVENTORY_OPERATIONS, ...GHIDRA_FUNCTION_OPERATIONS].map((operation) => {
|
|
17
15
|
const contract = providerContractByName.get(operation);
|
|
@@ -46,7 +44,7 @@ export const healthLimitations = Object.freeze([
|
|
|
46
44
|
export const windowsP0Limitations = Object.freeze([
|
|
47
45
|
"Windows Ghidra P0 accepts approved native x86-64 PE applications only; DLL, managed, hostile, sensitive, and mutable-path targets are unsupported.",
|
|
48
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.",
|
|
49
|
-
"Windows P0
|
|
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.",
|
|
50
48
|
]);
|
|
51
49
|
/** Limitation text for one admitted operation, including the common base. */
|
|
52
50
|
export const limitationsFor = (operation) => {
|
|
@@ -137,42 +135,50 @@ export const limitationsFor = (operation) => {
|
|
|
137
135
|
}
|
|
138
136
|
};
|
|
139
137
|
/** Provider-neutral capabilities advertised by every non-Windows Ghidra session. */
|
|
140
|
-
export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) =>
|
|
141
|
-
|
|
142
|
-
operation
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
:
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
:
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
138
|
+
export const CAPABILITIES = Object.freeze(GHIDRA_PROVIDER_TOOL_CONTRACTS.map((contract) => {
|
|
139
|
+
const operation = contract.analysisOperation;
|
|
140
|
+
if (operation === null)
|
|
141
|
+
throw new TypeError(`Missing analysis operation for ${contract.name}`);
|
|
142
|
+
return Object.freeze({
|
|
143
|
+
provider: GHIDRA_PROVIDER_IDENTITY,
|
|
144
|
+
operation,
|
|
145
|
+
inputContractVersion: 1,
|
|
146
|
+
outputContractVersion: 1,
|
|
147
|
+
available: true,
|
|
148
|
+
reason: null,
|
|
149
|
+
pagination: PAGINATED_OPERATIONS.has(contract.name)
|
|
150
|
+
? "offset"
|
|
151
|
+
: "none",
|
|
152
|
+
exhaustive: !PAGINATED_OPERATIONS.has(contract.name),
|
|
153
|
+
effects: Object.freeze({
|
|
154
|
+
mutatesArtifact: false,
|
|
155
|
+
launchesProcess: true,
|
|
156
|
+
mayShowUi: false,
|
|
157
|
+
mayAccessNetwork: false,
|
|
158
|
+
mayWriteFilesystem: true,
|
|
159
|
+
changesPermissions: false,
|
|
160
|
+
requiresRoot: false,
|
|
161
|
+
}),
|
|
162
|
+
limits: Object.freeze({
|
|
163
|
+
maxResults: PAGINATED_OPERATIONS.has(contract.name)
|
|
164
|
+
? SEARCH_OPERATIONS.has(contract.name)
|
|
165
|
+
? 100
|
|
166
|
+
: 500
|
|
167
|
+
: null,
|
|
168
|
+
maxPayloadBytes: GHIDRA_MAX_LINE_BYTES,
|
|
169
|
+
timeoutMs: DECOMPILE_OPERATIONS.has(contract.name)
|
|
170
|
+
? GHIDRA_DECOMPILE_REQUEST_TIMEOUT_MS
|
|
171
|
+
: GHIDRA_REQUEST_TIMEOUT_MS,
|
|
172
|
+
}),
|
|
173
|
+
limitations: Object.freeze(limitationsFor(contract.name)),
|
|
174
|
+
});
|
|
175
|
+
}));
|
|
173
176
|
/** Capabilities advertised for the experimental Windows x64 P0 boundary. */
|
|
174
177
|
export const WINDOWS_P0_CAPABILITIES = Object.freeze(CAPABILITIES.map((capability) => Object.freeze({
|
|
175
178
|
...capability,
|
|
179
|
+
available: false,
|
|
180
|
+
reason: WINDOWS_NATIVE_AUTHORITY_UNAVAILABLE_REASON,
|
|
181
|
+
availabilityCode: "unsupported_host",
|
|
176
182
|
limitations: Object.freeze([
|
|
177
183
|
...capability.limitations,
|
|
178
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,
|
package/dist/ghidra/protocol.js
CHANGED
|
@@ -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
|
-
.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
|
69
|
-
: err(new GhidraRemoteError(response.error
|
|
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
|
-
|
|
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
|
-
|
|
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?.
|
|
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
|
-
|
|
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({
|