rea-agents 2.2.0 → 2.4.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 +57 -10
- package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
- package/dist/application/ArtifactExtraction.js +5 -1
- package/dist/application/ArtifactGraphConstruction.js +3 -15
- package/dist/application/ArtifactInventory/classify.js +5 -1
- package/dist/application/ArtifactInventory/reader.js +2 -0
- package/dist/application/BinarySession.js +9 -2
- package/dist/application/BinarySessionStatus.js +40 -1
- package/dist/application/CapabilityInventory.js +26 -3
- package/dist/application/CommandShimReplay.js +6 -3
- package/dist/application/CompositeProvider.js +5 -2
- package/dist/application/DirectAnalysis.js +1 -20
- package/dist/application/DirectAnalysisStatus.js +83 -0
- package/dist/application/Doctor.js +34 -25
- package/dist/application/DoctorDiagnostics.js +1 -4
- package/dist/application/DoctorProjection.js +43 -0
- package/dist/application/DoctorScope.js +102 -0
- package/dist/application/EvidenceReferenceResolver.js +26 -0
- package/dist/application/JavaScriptApplicationEvidence.js +1 -1
- package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
- package/dist/application/JavaScriptApplicationService.js +3 -2
- package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
- package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
- package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
- package/dist/application/JavaScriptModuleRelationships.js +25 -1
- package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
- package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
- package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
- package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
- package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
- package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
- package/dist/application/JavaScriptSemanticTraceService.js +45 -0
- package/dist/application/LoopbackReplay.js +277 -133
- package/dist/application/LoopbackReplayRecorder.js +101 -0
- package/dist/application/PermissionAuthority.js +7 -3
- package/dist/application/ProcessCaptureEnvironment.js +26 -0
- package/dist/application/ProcessCaptureJournal.js +95 -0
- package/dist/application/ProcessCaptureLifecycle.js +25 -13
- package/dist/application/ProcessCheckpoints.js +35 -4
- package/dist/application/ProcessCli.js +26 -4
- package/dist/application/ProcessHarness.js +64 -83
- package/dist/application/ProcessNormalization.js +9 -2
- package/dist/application/ProcessReactiveCoordinator.js +225 -0
- package/dist/application/ProcessReactiveEffects.js +141 -0
- package/dist/application/ProcessReactiveHarness.js +85 -0
- package/dist/application/ProcessReactiveObservations.js +105 -0
- package/dist/application/ProcessSampling.js +2 -0
- package/dist/application/SessionProviderRouter.js +7 -6
- package/dist/application/Setup.js +11 -10
- package/dist/application/SetupPlan.js +1 -1
- package/dist/application/SetupRegistrationEnvironment.js +12 -0
- package/dist/application/TerminalRenderer.js +3 -1
- package/dist/browser/CdpEndpoint.js +37 -4
- package/dist/catalogIdentity.js +16 -7
- package/dist/cli/coreAnalysisCommands.js +34 -2
- package/dist/cli/javascriptApplicationAnalysis.js +19 -0
- package/dist/cli/setupCommands.js +81 -32
- package/dist/cli/utilityCommands.js +10 -2
- package/dist/cliApplicationCommands.js +79 -16
- package/dist/cliCommandNames.js +3 -0
- package/dist/cliElectronCommands.js +23 -33
- package/dist/cliObservationOptions.js +1 -1
- package/dist/cliOutput.js +56 -0
- package/dist/cliProcessCommands.js +32 -1
- package/dist/cliSetup.js +30 -21
- package/dist/contracts/applicationToolContracts.js +54 -7
- package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
- package/dist/contracts/electronToolContracts.js +53 -32
- package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
- package/dist/contracts/processCaptureExample.js +1 -0
- package/dist/contracts/replayMachineExample.js +37 -0
- package/dist/contracts/toolContractExamples.js +2 -0
- package/dist/contracts/toolContracts.js +5 -1
- package/dist/contracts/toolEffects.js +3 -0
- package/dist/contracts/toolOutputSchemaGroups.js +2 -0
- package/dist/contracts/toolOutputSchemaPrimitives.js +43 -0
- package/dist/doctorRuntime.js +41 -0
- package/dist/domain/analysisErrorPresentation.js +5 -3
- package/dist/domain/analysisErrorProjection.js +7 -1
- package/dist/domain/analysisSnapshot.js +2 -0
- package/dist/domain/artifactGraph.js +2 -0
- package/dist/domain/binaryTarget.js +3 -6
- package/dist/domain/changedBehavior.js +5 -4
- package/dist/domain/completionLedgerGeneration.js +190 -0
- package/dist/domain/errors.js +4 -2
- package/dist/domain/evidence.js +2 -0
- package/dist/domain/evidenceCompletionLedger.js +113 -0
- package/dist/domain/hopperStartupFailure.js +9 -0
- package/dist/domain/javascriptApplicationAnalysis.js +44 -2
- package/dist/domain/javascriptExportShapeComparison.js +145 -0
- package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
- package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
- package/dist/domain/javascriptExportShapeSelection.js +132 -0
- package/dist/domain/javascriptExportShapeVariants.js +272 -0
- package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
- package/dist/domain/javascriptSemanticAnalysis.js +17 -36
- package/dist/domain/javascriptSemanticCallResolution.js +129 -0
- package/dist/domain/javascriptSemanticCalls.js +269 -0
- package/dist/domain/javascriptSemanticGraph.js +356 -0
- package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
- package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
- package/dist/domain/javascriptSemanticIr.js +14 -1
- package/dist/domain/javascriptSemanticPrimitives.js +36 -0
- package/dist/domain/javascriptSemanticProjection.js +36 -4
- package/dist/domain/javascriptSemanticProvenance.js +29 -0
- package/dist/domain/javascriptSemanticQuery.js +294 -0
- package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
- package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
- package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
- package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
- package/dist/domain/javascriptSemanticReturns.js +187 -0
- package/dist/domain/javascriptSemanticState.js +32 -0
- package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
- package/dist/domain/javascriptSemanticValues.js +54 -70
- package/dist/domain/processCapture.js +100 -0
- package/dist/domain/processCaptureReactiveValidation.js +175 -0
- package/dist/domain/processCaptureValidation.js +103 -12
- package/dist/domain/processComparison.js +78 -25
- package/dist/domain/processObservation.js +162 -0
- package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
- package/dist/domain/processReactiveMatching.js +210 -0
- package/dist/domain/processReactiveRuntime.js +120 -0
- package/dist/domain/processReactiveScenario.js +361 -0
- package/dist/domain/processReactiveScenarioPreflight.js +120 -0
- package/dist/domain/processReactiveTransition.js +161 -0
- package/dist/domain/processScenario.js +33 -0
- package/dist/domain/processTraceComparison.js +43 -0
- package/dist/domain/processTraceDimensionProjection.js +50 -0
- package/dist/domain/processTraceEvaluation.js +312 -0
- package/dist/domain/processTraceSpecification.js +373 -0
- package/dist/domain/reconstructionVerification.js +5 -4
- package/dist/domain/replayMachine.js +18 -2
- package/dist/domain/replayMachineRun.js +216 -0
- package/dist/domain/replayMachineRuntime.js +88 -9
- package/dist/domain/staticRuntimeCorrelation.js +4 -2
- package/dist/domain/zipPackageFormat.js +20 -0
- package/dist/evaluation/CodexAgentEval.js +24 -0
- package/dist/generatedPackageMetadata.js +1 -1
- package/dist/ghidra/GhidraClient.js +13 -2
- package/dist/ghidra/GhidraDiagnostics.js +1 -0
- package/dist/ghidra/GhidraLauncher.js +7 -3
- package/dist/ghidra/GhidraProvider.js +8 -1
- package/dist/hopper/BridgeLauncher.js +56 -14
- package/dist/hopper/HopperClient.js +23 -10
- package/dist/hopper/HopperDiagnostics.js +14 -0
- package/dist/hopper/HopperProcessDiagnostic.js +14 -0
- package/dist/hopper/HopperProvider.js +8 -1
- package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
- package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
- package/dist/main/transport.js +2 -0
- package/dist/mcpDoctor.js +310 -0
- package/dist/native/NativeMacOSProvider.js +1 -0
- package/dist/process/ProcessOwnership.js +200 -53
- package/dist/process/ProviderRunLineage.js +21 -0
- package/dist/server/createServer.js +4 -1
- package/dist/server/javascriptApplicationResult.js +22 -1
- package/dist/server/registerApplicationTools/characterization.js +3 -3
- package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
- package/dist/server/registerApplicationTools/compareVersions.js +12 -6
- package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
- package/dist/server/registerApplicationTools/coverage.js +3 -3
- package/dist/server/registerApplicationTools/helpers.js +37 -25
- package/dist/server/registerApplicationTools/traceFeature.js +9 -5
- package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
- package/dist/server/registerApplicationTools.js +4 -0
- package/dist/server/registerEvidenceResources.js +5 -1
- package/dist/server/registerProcessComparisonTool.js +17 -7
- package/dist/server/registerReplayMachineTool.js +20 -0
- package/dist/server/registerSessionTools.js +12 -7
- package/dist/server/sessionAvailabilityPolicy.js +2 -1
- package/dist/serverIdentity.js +19 -0
- package/package.json +62 -30
- package/scripts/hopper-demo-x11.py +459 -61
- package/scripts/prepack.mjs +55 -0
- package/scripts/prepare.mjs +28 -0
- package/scripts/rea.mjs +26 -5
- package/skills/reverse-engineer-anything/SKILL.md +4 -3
- package/skills/reverse-engineer-anything/references/javascript-applications.md +10 -0
- package/skills/reverse-engineer-anything/references/native-and-artifacts.md +2 -2
package/README.md
CHANGED
|
@@ -262,7 +262,7 @@ Uninstall preserves Hopper, Node.js, evidence, captures, external evidence roots
|
|
|
262
262
|
| Inspect or decompile one part of an app from the Terminal | `rea analyze` or `rea decompile` |
|
|
263
263
|
| Validate, canonicalize, or compare Evidence v2 bundles | `rea evidence-import`, `rea evidence-export`, or `rea compare` |
|
|
264
264
|
| Run or resume a persistent two-version artifact analysis | `rea investigate-versions` |
|
|
265
|
-
| Map a local JavaScript/Electron application without executing it | `rea analyze-javascript-application`
|
|
265
|
+
| Map a local JavaScript/Electron application without executing it | `rea analyze PATH --approved` or `rea analyze-javascript-application` |
|
|
266
266
|
| Reuse immutable analysis results without relaunching a provider | Pass `--snapshot /approved/path/analysis.json` to a deep-analysis command |
|
|
267
267
|
| Import source as historical reference | `rea import-reference-source` |
|
|
268
268
|
| Capture or compare controlled process behavior | `rea capture-process` or `rea compare-process-captures` |
|
|
@@ -276,9 +276,21 @@ rea evidence-import /absolute/path/to/evidence/bundle.json
|
|
|
276
276
|
rea evidence-export /absolute/path/to/evidence/bundle.json /absolute/path/to/evidence/canonical.json
|
|
277
277
|
rea compare /absolute/path/to/evidence/left.json /absolute/path/to/evidence/right.json
|
|
278
278
|
rea investigate-versions /absolute/path/to/releases/v1 /absolute/path/to/releases/v2 /absolute/path/to/evidence/releases.json --yes --workspace-name releases
|
|
279
|
+
rea analyze /absolute/path/to/releases/app.asar --approved --json
|
|
279
280
|
rea analyze-javascript-application /absolute/path/to/releases/app.asar --approved --json
|
|
280
281
|
```
|
|
281
282
|
|
|
283
|
+
For a directory or `.asar`, generic `rea analyze` automatically selects the
|
|
284
|
+
static JavaScript application provider when neither `--provider` nor
|
|
285
|
+
`--snapshot` is supplied. The dedicated command remains available for explicit
|
|
286
|
+
format and resource-limit controls. Both routes require `--approved` and an
|
|
287
|
+
administrator-approved investigation input root.
|
|
288
|
+
|
|
289
|
+
If REA is registered with an MCP client, run approved `rea setup` while the
|
|
290
|
+
explicit investigation-root variable is set, then restart that client. Setup
|
|
291
|
+
copies this non-secret policy into the managed registration; changing the shell
|
|
292
|
+
environment alone cannot update an already-running MCP process.
|
|
293
|
+
|
|
282
294
|
`investigate-versions` inventories both versions, checkpoints their observed
|
|
283
295
|
Evidence, derives an artifact comparison, and records a changed-behavior report.
|
|
284
296
|
Both input paths must resolve beneath `REA_INVESTIGATION_INPUT_ROOTS_JSON`;
|
|
@@ -364,12 +376,12 @@ REA handles the app analysis in steps 1–5. The agent performs step 6 with its
|
|
|
364
376
|
| Native inspection | 33 | procedures, pseudocode, assembly, strings, names, segments, callers, callees, xrefs, annotations |
|
|
365
377
|
| Investigation workflows | 10 | `binary_overview`, `analyze_function`, `batch_decompile`, `trace_feature`, call graphs, Swift and Objective-C discovery |
|
|
366
378
|
| Native macOS utilities | 5 | Mach-O metadata, code signatures, plists, architectures, Swift demangling; Hopper-free and provenance-bearing |
|
|
367
|
-
| Artifact graph | 2 | deterministic directory, ZIP/APK/IPA, and ASAR inventory; explicitly selected extraction into an absent owned tree
|
|
379
|
+
| Artifact graph | 2 | deterministic directory, ZIP/APK/IPA/MSIX/AppX, and ASAR inventory; explicitly selected extraction into an absent owned tree |
|
|
368
380
|
| Managed PE/CLI | 8 | PE/CLI identity, metadata members, CIL hashes, P/Invoke/native-boundary declarations and verification, application-graph projection, decompiler reconstruction import, token remapping, runtime-correlation plans, and version comparison |
|
|
369
381
|
| Browser observation | 8 | exact-origin CDP capture, bundle and source-map analysis, WebMCP discovery, session timelines, capture diff, and visual evidence |
|
|
370
382
|
| Electron analysis | 4 | passive root-confined observation, bounded static application mapping, and evidence-backed static/runtime reconciliation |
|
|
371
|
-
| Application workflows |
|
|
372
|
-
| Workspace and observation |
|
|
383
|
+
| Application workflows | 9 | bounded cross-layer traces, unique-only version matching, static export return-shape comparison, approved Linux-isolated extracted-module replay, managed-runtime characterization, and reconstruction coverage closure |
|
|
384
|
+
| Workspace and observation | 19 | target lifecycle, Evidence v2 bundles, direct finite replay-machine evaluation, process/artifact/function comparison, evidence-linked residual-unknown lifecycle |
|
|
373
385
|
|
|
374
386
|
The public interface describes what the agent is trying to learn. Providers decide how to answer. macOS utilities handle common semantic inspection without launching Hopper; Hopper handles deeper native analysis; the process harness implements controlled behavioral capture.
|
|
375
387
|
|
|
@@ -384,7 +396,7 @@ REA is already useful for native application, browser, and Electron investigatio
|
|
|
384
396
|
- Validate and canonically serialize a provider-neutral [JavaScript Application Graph v1](docs/javascript-application-graph.md) spanning packages, ASAR entries, Electron roles, JavaScript/source-map entities, browser/runtime instances, IPC, endpoints, storage, and native add-ons. This shipped domain contract performs no extraction or I/O by itself.
|
|
385
397
|
- Reconstruct bounded static package, entrypoint, Webpack/Rspack module, import, worker, endpoint, storage, source-map, BrowserWindow, preload, contextBridge, IPC, utility-process, and native-add-on structure from an approved local directory or ASAR through `analyze_javascript_application` or `rea analyze-javascript-application`. The AST-only [application service](docs/javascript-artifact-reconstruction.md) never executes bootstrap code, pairs only unique exact literal IPC channels, and reports dynamic or ambiguous channels as unresolved.
|
|
386
398
|
- Reconcile that static graph with existing passive web or Electron Evidence through `reconcile_javascript_runtime` or `rea reconcile-javascript-runtime`. Exact captured bytes outrank caller-declared file/URL mappings; target, frame, script, worker, cache, and asset ambiguity stays explicit, source-map authority stays separate, and a module resident in an observed bundle is never reported as executed. See [JavaScript static/runtime reconciliation](docs/javascript-runtime-reconciliation.md).
|
|
387
|
-
- Trace a literal route, string, API, IPC channel, module, or native export through authenticated application Evidence with explicit traversal bounds, then hand exact native artifact digests and requested exports to retained Ghidra or Hopper Evidence without automatic provider switching. Compare application versions using unique-only digest, source-map, structural, and semantic tiers;
|
|
399
|
+
- Trace a literal route, string, API, IPC channel, module, or native export through authenticated application Evidence with explicit traversal bounds, then hand exact native artifact digests and requested exports to retained Ghidra or Hopper Evidence without automatic provider switching. Compare application versions using unique-only digest, source-map, structural, and semantic tiers; compare one exact JavaScript export's static return shapes through unique literal discriminants and bounded JSON Pointer changes. Duplicate, dynamic, incomplete, and truncated facts stay unknown. See [cross-layer JavaScript application workflows](docs/javascript-application-workflows.md).
|
|
388
400
|
- Classify PE/CLI managed artifacts with `inspect_managed_artifact` / `rea inspect-managed-artifact`, inspect bounded metadata members, signatures, raw CIL hashes, limited decoded-instruction-tuple v1 hashes, separately reported exception regions, call edges, and field-access anchors with `inspect_managed_members` / `rea inspect-managed-members`, inventory declared ModuleRef/ImplMap/PInvoke and non-IL method boundary indicators with `inspect_managed_native_boundaries` / `rea inspect-managed-native-boundaries`, then compare two authenticated member observations with `compare_managed_members` / `rea compare-managed-members`. `verify_managed_native_boundaries` / `rea verify-managed-native-boundaries` checks managed P/Invoke declarations against authenticated native export or function Evidence while keeping verified, inferred, contradicted, and unresolved states distinct. The comparison treats build-local tokens as build-local and uses unique decoded-CIL/signature and structural method-shape tiers, never names alone; the v1 tuple hash does not itself resolve tokens or fully commit control flow. `project_managed_application_graph` / `rea project-managed-application-graph` projects authenticated managed artifact/member/native-boundary Evidence into the existing application graph for cross-layer feature tracing. `import_managed_reconstruction` / `rea import-managed-reconstruction` admits user-supplied decompiler C#/IL/pseudocode as analyst inference only after exact artifact SHA-256, MVID, signature, and the shipped v1 decoded-IL commitment match. Separately, `plan_managed_runtime_correlation` / `rea plan-managed-runtime-correlation` can admit a default-disabled, permission-gated runtime-correlation plan locked to the same build evidence. These paths never load the assembly, resolve CLR dependencies, execute target code, run a decompiler, or translate managed tokens into native addresses; full normalized-CIL v2 semantics, native-body bridge mapping, and an actual runtime executor remain future managed-code contracts.
|
|
389
401
|
- Configure `REA_ILSPY_CMD_PATH=/absolute/path/to/ilspycmd` only when you want
|
|
390
402
|
doctor and `verify:managed` to inspect a bring-your-own ILSpy command as a
|
|
@@ -397,6 +409,7 @@ REA is already useful for native application, browser, and Electron investigatio
|
|
|
397
409
|
- Export and import evidence bundles across sessions.
|
|
398
410
|
- Persist automatic cross-version artifact runs as canonical, lock-protected workspaces with tamper-evident revision commitments.
|
|
399
411
|
- Capture approved PTY scenarios as Process Capture v4 Evidence, including committed run manifests, raw and rendered terminal frames, scripted interactions, descendant settlement, named filesystem checkpoints, deterministic command shims, and loopback HTTP/WebSocket exchanges.
|
|
412
|
+
- Validate finite replay machines without launching a target through `run_replay_machine` or `rea run-replay-machine`; ordered events return typed decisions, actions, captured aliases, transition journals, final state, and exact limit use without echoing request or captured values.
|
|
400
413
|
- Compare complete artifact inventories by stable path, content, metadata, and relations; incomplete evidence never implies equivalence.
|
|
401
414
|
- Compare explicit function dossiers across text, calls, references, strings, and address-normalized CFG topology with per-facet unknowns.
|
|
402
415
|
- Compare canonical Evidence bundles by exact membership, explicit observation pairs, and residual-unknown histories without turning omissions into behavioral absence.
|
|
@@ -425,7 +438,7 @@ rea inspect-web-page http://127.0.0.1:9222 TARGET_ID --approved --json
|
|
|
425
438
|
|
|
426
439
|
All eight browser tools expose the same Evidence v2 contracts over CLI and MCP. Inspection is passive: REA does not evaluate page JavaScript, navigate, click, close the page, or close the browser. Query values, credentials, cookies, authorization headers, storage values, and raw JSON or WebSocket values are never retained. Separately approved captures can retain bounded redacted console primitives, value-free JSON/WebSocket shapes, script sources, accessibility text, or screenshot pixels. Existing activity before attach is explicitly unavailable. See [Website observation with CDP](docs/browser-observation.md) for browser startup, schemas, limits, and the threat model.
|
|
427
440
|
|
|
428
|
-
Exact package, tool-family, provider, setup-client, public schema-version, and CLI facts are generated from source in [`docs/product-catalog.json`](docs/product-catalog.json).
|
|
441
|
+
Exact package, tool-family, provider, setup-client, public schema-version, and CLI facts are generated from source in [`docs/product-catalog.json`](docs/product-catalog.json). PR CI verifies this catalog, narrative documentation, generated schemas, and a clean TypeDoc render.
|
|
429
442
|
|
|
430
443
|
## Roadmap
|
|
431
444
|
|
|
@@ -466,7 +479,7 @@ Setup detects Claude Code, Claude Desktop, Codex, Cursor, Gemini CLI, Windsurf,
|
|
|
466
479
|
"mcpServers": {
|
|
467
480
|
"rea": {
|
|
468
481
|
"command": "npx",
|
|
469
|
-
"args": ["-y", "rea-agents@2.
|
|
482
|
+
"args": ["-y", "rea-agents@2.4.0", "mcp"]
|
|
470
483
|
}
|
|
471
484
|
}
|
|
472
485
|
}
|
|
@@ -572,8 +585,15 @@ operations still work. An explicit unknown, unavailable, or unsupported
|
|
|
572
585
|
provider fails with candidate IDs, stable rejection codes, and actionable local
|
|
573
586
|
diagnostics. `binary_session`, `rea providers`, and `rea capabilities` expose
|
|
574
587
|
the authoritative `analysis_provider_candidates` and
|
|
575
|
-
`analysis_provider_binding` fields.
|
|
576
|
-
|
|
588
|
+
`analysis_provider_binding` fields. Each open target also has an
|
|
589
|
+
`analysis_run.run_id` allocated before provider startup. When dynamic providers
|
|
590
|
+
start, `analysis_run.process_lineage` changes from `not_observed` to `snapshots`
|
|
591
|
+
and retains one provider-attributed, token-verified observation per started
|
|
592
|
+
provider. Each observation carries `observed_at` and remains `unavailable` or
|
|
593
|
+
`verified`; a verified empty descendant list is distinct from both. Snapshots
|
|
594
|
+
describe bounded observations, not current live state or historical absence.
|
|
595
|
+
Reopening same target without a selector keeps its binding; runtime failure
|
|
596
|
+
never selects another provider silently.
|
|
577
597
|
Ghidra can appear as an available, target-compatible candidate after doctor
|
|
578
598
|
validates its exact installation. Its capability list contains the 18 admitted
|
|
579
599
|
read-only inventory and function-analysis operations; selecting it still does
|
|
@@ -705,13 +725,40 @@ Any agent that can run a local MCP server can use the manual configuration. Setu
|
|
|
705
725
|
|
|
706
726
|
## Development
|
|
707
727
|
|
|
708
|
-
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, architecture, tests, and release instructions.
|
|
728
|
+
See [CONTRIBUTING.md](CONTRIBUTING.md) for setup, architecture, tests, and release instructions. PR CI publishes generated API documentation as the `api-docs` workflow artifact.
|
|
709
729
|
|
|
710
730
|
`npm run verify:agent` runs brandless native, JavaScript-application, managed,
|
|
711
731
|
and browser prompts through a real local Codex CLI. Its JSON report measures
|
|
712
732
|
natural MCP use, first-tool routing, repeated calls, actual Codex token usage,
|
|
713
733
|
completion quality, and explicit treatment of authority and unknowns.
|
|
714
734
|
|
|
735
|
+
`npm run evidence:generate` regenerates the managed conformance manifest and
|
|
736
|
+
Evidence v2 completion ledger from live verifier output. `npm run
|
|
737
|
+
evidence:check` reruns the verifier and fails when artifacts, scenarios,
|
|
738
|
+
providers, schemas, claim counts, Evidence IDs, or the bundled skill have
|
|
739
|
+
drifted. Unsupported claims remain explicit and never count as passes.
|
|
740
|
+
Verifier JSON reports include an ephemeral `verifier_run` UUID allocated before
|
|
741
|
+
the verifier performs work and inherited by its child processes through
|
|
742
|
+
`REA_PROCESS_RUN_ID`. The final report includes the verifier and parent PIDs
|
|
743
|
+
plus `process_lineage` and its ISO `observed_at` timestamp: POSIX verifiers
|
|
744
|
+
report a token-verified, point-in-time launcher process group and live
|
|
745
|
+
descendants, while platforms without an owned
|
|
746
|
+
lineage primitive report `status: "unavailable"` and a reason. An empty verified
|
|
747
|
+
descendant list means no child was live during the final observation; it does
|
|
748
|
+
not claim the verifier launched no children earlier. Nested verifier entrypoints
|
|
749
|
+
in the same process reuse its UUID; each new verifier process replaces any
|
|
750
|
+
inherited parent token with a fresh run identity.
|
|
751
|
+
Generated completion commitments deliberately exclude this per-execution
|
|
752
|
+
identity, so check mode remains deterministic while live reports remain
|
|
753
|
+
attributable.
|
|
754
|
+
|
|
755
|
+
Owned Hopper shutdown logs retain the launcher PID, process-group ID, cleanup
|
|
756
|
+
status, and whether a verified group signal was required. They omit the run
|
|
757
|
+
token and unexpected exception text. The real-Hopper verifier also starts an
|
|
758
|
+
unrelated `Hopper`-named sentinel in a distinct process group and fails unless
|
|
759
|
+
that process survives every session close; the sentinel is removed only by the
|
|
760
|
+
verifier after the survival check.
|
|
761
|
+
|
|
715
762
|
## Project links
|
|
716
763
|
|
|
717
764
|
[npm](https://www.npmjs.com/package/rea-agents) · [Issues](https://github.com/morluto/rea/issues) · [Security](SECURITY.md) · [Contributing](CONTRIBUTING.md) · [Hopper](https://www.hopperapp.com/) · [Ghidra](https://github.com/NationalSecurityAgency/ghidra)
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
import { compareApplicationVersionsRequestSchema, compareJavaScriptExportShapesRequestSchema, traceApplicationFeatureRequestSchema, traceJavaScriptSemanticsRequestSchema, } from "../contracts/applicationWorkflowInputContracts.js";
|
|
3
|
+
import { AnalysisInputError } from "../domain/errors.js";
|
|
4
|
+
import { projectInputIssues } from "../domain/inputIssueProjection.js";
|
|
5
|
+
import { compareApplicationVersionsInputSchema } from "../domain/javascriptApplicationVersionComparisonSchemas.js";
|
|
6
|
+
import { compareJavaScriptExportShapesInputSchema } from "../domain/javascriptExportShapeComparisonSchemas.js";
|
|
7
|
+
import { traceApplicationFeatureInputSchema } from "../domain/javascriptFeatureTraceSchemas.js";
|
|
8
|
+
import { traceJavaScriptSemanticsInputSchema } from "../domain/javascriptSemanticTraceSchemas.js";
|
|
9
|
+
import { err, ok } from "../domain/result.js";
|
|
10
|
+
import { resolveEvidenceReferences, } from "./EvidenceReferenceResolver.js";
|
|
11
|
+
const APPLICATION_GRAPH_IDENTITIES = [
|
|
12
|
+
{
|
|
13
|
+
operation: "analyze_javascript_application",
|
|
14
|
+
predicate: "rea.javascript-application-analysis/v1",
|
|
15
|
+
},
|
|
16
|
+
{
|
|
17
|
+
operation: "analyze_javascript_application",
|
|
18
|
+
predicate: "rea.javascript-application-analysis/v2",
|
|
19
|
+
},
|
|
20
|
+
{
|
|
21
|
+
operation: "reconcile_javascript_runtime",
|
|
22
|
+
predicate: "rea.javascript-runtime-reconciliation/v1",
|
|
23
|
+
},
|
|
24
|
+
{
|
|
25
|
+
operation: "project_managed_application_graph",
|
|
26
|
+
predicate: "rea.managed-application-graph/v1",
|
|
27
|
+
},
|
|
28
|
+
];
|
|
29
|
+
/** Parse and resolve one trace adapter request into its canonical domain input. */
|
|
30
|
+
export const resolveTraceApplicationFeatureRequest = (input, lookup) => {
|
|
31
|
+
const parsed = traceApplicationFeatureRequestSchema.safeParse(input);
|
|
32
|
+
return parsed.success
|
|
33
|
+
? resolveTraceApplicationFeatureRequestValidated(parsed.data, lookup)
|
|
34
|
+
: invalid("trace_application_feature", parsed.error, input);
|
|
35
|
+
};
|
|
36
|
+
/** Resolve a trace request already parsed by the caller-facing contract. */
|
|
37
|
+
export const resolveTraceApplicationFeatureRequestValidated = (input, lookup) => {
|
|
38
|
+
const application = input.application === undefined
|
|
39
|
+
? resolveEvidenceReferences(lookup, input.application_evidence_id === undefined
|
|
40
|
+
? []
|
|
41
|
+
: [input.application_evidence_id], APPLICATION_GRAPH_IDENTITIES)
|
|
42
|
+
: ok([input.application]);
|
|
43
|
+
if (!application.ok)
|
|
44
|
+
return application;
|
|
45
|
+
const native = resolveEvidenceReferences(lookup, input.native_observation_evidence_ids);
|
|
46
|
+
if (!native.ok)
|
|
47
|
+
return native;
|
|
48
|
+
const raw = {
|
|
49
|
+
application: application.value[0],
|
|
50
|
+
native_observations: [...input.native_observations, ...native.value],
|
|
51
|
+
seed: input.seed,
|
|
52
|
+
direction: input.direction,
|
|
53
|
+
limits: input.limits,
|
|
54
|
+
};
|
|
55
|
+
const parsed = traceApplicationFeatureInputSchema.safeParse(raw);
|
|
56
|
+
return parsed.success
|
|
57
|
+
? ok(parsed.data)
|
|
58
|
+
: invalid("trace_application_feature", parsed.error, raw);
|
|
59
|
+
};
|
|
60
|
+
/** Parse and resolve one semantic trace adapter request. */
|
|
61
|
+
export const resolveTraceJavaScriptSemanticsRequest = (input, lookup) => {
|
|
62
|
+
const parsed = traceJavaScriptSemanticsRequestSchema.safeParse(input);
|
|
63
|
+
return parsed.success
|
|
64
|
+
? resolveTraceJavaScriptSemanticsRequestValidated(parsed.data, lookup)
|
|
65
|
+
: invalid("trace_javascript_semantics", parsed.error, input);
|
|
66
|
+
};
|
|
67
|
+
/** Resolve a semantic trace request already parsed by its public contract. */
|
|
68
|
+
export const resolveTraceJavaScriptSemanticsRequestValidated = (input, lookup) => {
|
|
69
|
+
const application = input.application === undefined
|
|
70
|
+
? resolveEvidenceReferences(lookup, input.application_evidence_id === undefined
|
|
71
|
+
? []
|
|
72
|
+
: [input.application_evidence_id], APPLICATION_GRAPH_IDENTITIES)
|
|
73
|
+
: ok([input.application]);
|
|
74
|
+
if (!application.ok)
|
|
75
|
+
return application;
|
|
76
|
+
const raw = { application: application.value[0], query: input.query };
|
|
77
|
+
const parsed = traceJavaScriptSemanticsInputSchema.safeParse(raw);
|
|
78
|
+
return parsed.success
|
|
79
|
+
? ok(parsed.data)
|
|
80
|
+
: invalid("trace_javascript_semantics", parsed.error, raw);
|
|
81
|
+
};
|
|
82
|
+
/** Parse and resolve one comparison adapter request into canonical input. */
|
|
83
|
+
export const resolveCompareApplicationVersionsRequest = (input, lookup) => {
|
|
84
|
+
const parsed = compareApplicationVersionsRequestSchema.safeParse(input);
|
|
85
|
+
return parsed.success
|
|
86
|
+
? resolveCompareApplicationVersionsRequestValidated(parsed.data, lookup)
|
|
87
|
+
: invalid("compare_application_versions", parsed.error, input);
|
|
88
|
+
};
|
|
89
|
+
/** Resolve a comparison request parsed by the caller-facing contract. */
|
|
90
|
+
export const resolveCompareApplicationVersionsRequestValidated = (input, lookup) => {
|
|
91
|
+
const left = graphEvidence(input.left, input.left_evidence_id, lookup);
|
|
92
|
+
if (!left.ok)
|
|
93
|
+
return left;
|
|
94
|
+
const right = graphEvidence(input.right, input.right_evidence_id, lookup);
|
|
95
|
+
if (!right.ok)
|
|
96
|
+
return right;
|
|
97
|
+
const leftNative = resolveEvidenceReferences(lookup, input.left_native_observation_evidence_ids);
|
|
98
|
+
if (!leftNative.ok)
|
|
99
|
+
return leftNative;
|
|
100
|
+
const rightNative = resolveEvidenceReferences(lookup, input.right_native_observation_evidence_ids);
|
|
101
|
+
if (!rightNative.ok)
|
|
102
|
+
return rightNative;
|
|
103
|
+
const raw = {
|
|
104
|
+
left: left.value,
|
|
105
|
+
right: right.value,
|
|
106
|
+
left_native_observations: [
|
|
107
|
+
...input.left_native_observations,
|
|
108
|
+
...leftNative.value,
|
|
109
|
+
],
|
|
110
|
+
right_native_observations: [
|
|
111
|
+
...input.right_native_observations,
|
|
112
|
+
...rightNative.value,
|
|
113
|
+
],
|
|
114
|
+
limits: input.limits,
|
|
115
|
+
...(input.unknown_registry_approved === undefined
|
|
116
|
+
? {}
|
|
117
|
+
: { unknown_registry_approved: input.unknown_registry_approved }),
|
|
118
|
+
};
|
|
119
|
+
const parsed = compareApplicationVersionsInputSchema.safeParse(raw);
|
|
120
|
+
return parsed.success
|
|
121
|
+
? ok(parsed.data)
|
|
122
|
+
: invalid("compare_application_versions", parsed.error, raw);
|
|
123
|
+
};
|
|
124
|
+
/** Parse and resolve an export-shape adapter request into canonical input. */
|
|
125
|
+
export const resolveCompareJavaScriptExportShapesRequest = (input, lookup) => {
|
|
126
|
+
const parsed = compareJavaScriptExportShapesRequestSchema.safeParse(input);
|
|
127
|
+
return parsed.success
|
|
128
|
+
? resolveCompareJavaScriptExportShapesRequestValidated(parsed.data, lookup)
|
|
129
|
+
: invalid("compare_javascript_export_shapes", parsed.error, input);
|
|
130
|
+
};
|
|
131
|
+
/** Resolve an export-shape request already parsed by the adapter contract. */
|
|
132
|
+
export const resolveCompareJavaScriptExportShapesRequestValidated = (input, lookup) => {
|
|
133
|
+
const left = graphEvidence(input.left, input.left_evidence_id, lookup);
|
|
134
|
+
if (!left.ok)
|
|
135
|
+
return left;
|
|
136
|
+
const right = graphEvidence(input.right, input.right_evidence_id, lookup);
|
|
137
|
+
if (!right.ok)
|
|
138
|
+
return right;
|
|
139
|
+
const raw = {
|
|
140
|
+
left: left.value,
|
|
141
|
+
right: right.value,
|
|
142
|
+
left_module_path: input.left_module_path,
|
|
143
|
+
left_export_name: input.left_export_name,
|
|
144
|
+
right_module_path: input.right_module_path,
|
|
145
|
+
right_export_name: input.right_export_name,
|
|
146
|
+
limits: input.limits,
|
|
147
|
+
...(input.unknown_registry_approved === undefined
|
|
148
|
+
? {}
|
|
149
|
+
: { unknown_registry_approved: input.unknown_registry_approved }),
|
|
150
|
+
};
|
|
151
|
+
const parsed = compareJavaScriptExportShapesInputSchema.safeParse(raw);
|
|
152
|
+
return parsed.success
|
|
153
|
+
? ok(parsed.data)
|
|
154
|
+
: invalid("compare_javascript_export_shapes", parsed.error, raw);
|
|
155
|
+
};
|
|
156
|
+
const graphEvidence = (evidence, evidenceId, lookup) => {
|
|
157
|
+
if (evidence !== undefined)
|
|
158
|
+
return ok(evidence);
|
|
159
|
+
const resolved = resolveEvidenceReferences(lookup, evidenceId === undefined ? [] : [evidenceId], APPLICATION_GRAPH_IDENTITIES);
|
|
160
|
+
return resolved.ok ? ok(resolved.value[0]) : resolved;
|
|
161
|
+
};
|
|
162
|
+
const invalid = (operation, cause, input) => err(new AnalysisInputError(operation, undefined, projectInputIssues(cause.issues, input)));
|
|
@@ -140,7 +140,11 @@ const createReader = async (path, format) => {
|
|
|
140
140
|
return new DirectoryArtifactReader(path);
|
|
141
141
|
if (format === "asar")
|
|
142
142
|
return new AsarArtifactReader(path);
|
|
143
|
-
if (format === "ipa" ||
|
|
143
|
+
if (format === "ipa" ||
|
|
144
|
+
format === "apk" ||
|
|
145
|
+
format === "msix" ||
|
|
146
|
+
format === "appx" ||
|
|
147
|
+
format === "zip")
|
|
144
148
|
return new ZipArtifactReader(path, format);
|
|
145
149
|
if (format === "mach-o")
|
|
146
150
|
return new MachOSliceArtifactReader(path);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
|
-
import { extname } from "node:path";
|
|
3
2
|
import canonicalize from "canonicalize";
|
|
3
|
+
import { zipPackageFormatForPath } from "../domain/zipPackageFormat.js";
|
|
4
4
|
/** Index the first occurrence for each canonical logical path. */
|
|
5
5
|
export const indexOccurrencesByPath = (occurrences) => {
|
|
6
6
|
const byPath = new Map();
|
|
@@ -74,7 +74,7 @@ export const createRootNode = (input) => createArtifactNode({
|
|
|
74
74
|
}),
|
|
75
75
|
size: input.digest?.bytes ?? 0,
|
|
76
76
|
kind: input.directory ||
|
|
77
|
-
["zip", "ipa", "apk", "asar", "dmg", "pkg"].includes(input.format)
|
|
77
|
+
["zip", "ipa", "apk", "msix", "appx", "asar", "dmg", "pkg"].includes(input.format)
|
|
78
78
|
? "container"
|
|
79
79
|
: classifyArtifactPath(input.path).kind,
|
|
80
80
|
format: input.format,
|
|
@@ -174,7 +174,7 @@ export const classifyArtifactPath = (path) => {
|
|
|
174
174
|
return { kind: "javascript", format: "javascript-bundle" };
|
|
175
175
|
if (lower.endsWith(".asar"))
|
|
176
176
|
return { kind: "container", format: "asar" };
|
|
177
|
-
const archiveFormat =
|
|
177
|
+
const archiveFormat = zipPackageFormatForPath(lower);
|
|
178
178
|
if (archiveFormat !== undefined)
|
|
179
179
|
return { kind: "container", format: archiveFormat };
|
|
180
180
|
if (/\.framework(?:\/|$)/u.test(lower))
|
|
@@ -251,16 +251,4 @@ const relationFor = (path) => {
|
|
|
251
251
|
return "embeds";
|
|
252
252
|
return "contains";
|
|
253
253
|
};
|
|
254
|
-
const archiveFormatForExtension = (extension) => {
|
|
255
|
-
switch (extension) {
|
|
256
|
-
case ".zip":
|
|
257
|
-
return "zip";
|
|
258
|
-
case ".ipa":
|
|
259
|
-
return "ipa";
|
|
260
|
-
case ".apk":
|
|
261
|
-
return "apk";
|
|
262
|
-
default:
|
|
263
|
-
return undefined;
|
|
264
|
-
}
|
|
265
|
-
};
|
|
266
254
|
const depth = (path) => path.split("/").length;
|
|
@@ -1,8 +1,12 @@
|
|
|
1
1
|
import { open } from "node:fs/promises";
|
|
2
2
|
import { classifyArtifactPath } from "../ArtifactGraphConstruction.js";
|
|
3
|
+
import { zipPackageFormatForPath } from "../../domain/zipPackageFormat.js";
|
|
3
4
|
const classifyContainerExtension = (path) => {
|
|
4
5
|
const lower = path.toLowerCase();
|
|
5
|
-
|
|
6
|
+
const zipPackage = zipPackageFormatForPath(lower);
|
|
7
|
+
if (zipPackage !== undefined)
|
|
8
|
+
return zipPackage;
|
|
9
|
+
for (const format of ["asar", "dmg", "pkg"])
|
|
6
10
|
if (lower.endsWith(`.${format}`))
|
|
7
11
|
return format;
|
|
8
12
|
return undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto";
|
|
1
2
|
import { analysisProfilesEqual, } from "../domain/analysisProfile.js";
|
|
2
3
|
import { AnalysisCancelledError, ProviderAdapterError, } from "../domain/errors.js";
|
|
3
4
|
import { err, ok } from "../domain/result.js";
|
|
@@ -116,7 +117,8 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
116
117
|
const previous = this.#active;
|
|
117
118
|
this.#active = undefined;
|
|
118
119
|
await previous?.client.close();
|
|
119
|
-
const
|
|
120
|
+
const runId = randomUUID();
|
|
121
|
+
const client = route.createClient(target, { runId });
|
|
120
122
|
const started = await client.execute("health", {}, options);
|
|
121
123
|
if (!started.ok) {
|
|
122
124
|
await client.close();
|
|
@@ -134,6 +136,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
134
136
|
profile,
|
|
135
137
|
compatibility: structuredClone(compatibility),
|
|
136
138
|
route,
|
|
139
|
+
runId,
|
|
137
140
|
};
|
|
138
141
|
this.#clearRuntimeAvailability();
|
|
139
142
|
if (profile === null)
|
|
@@ -172,6 +175,8 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
172
175
|
route: this.#currentRoute(),
|
|
173
176
|
router: this.#providerRouter,
|
|
174
177
|
runtimeAvailability: this.#runtimeAvailability,
|
|
178
|
+
runId: this.#active?.runId,
|
|
179
|
+
runtimeLineageSnapshots: this.#active?.client.runtimeLineageSnapshots?.() ?? [],
|
|
175
180
|
});
|
|
176
181
|
}
|
|
177
182
|
/** Return the immutable artifact identity captured before its provider started. */
|
|
@@ -300,7 +305,8 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
300
305
|
async #restore(previous) {
|
|
301
306
|
if (previous === undefined)
|
|
302
307
|
return;
|
|
303
|
-
const
|
|
308
|
+
const runId = randomUUID();
|
|
309
|
+
const client = previous.route.createClient(previous.target, { runId });
|
|
304
310
|
const started = await client.execute("health", {});
|
|
305
311
|
if (started.ok)
|
|
306
312
|
this.#active = {
|
|
@@ -309,6 +315,7 @@ export class BinarySession extends BinarySessionRecords {
|
|
|
309
315
|
profile: previous.profile,
|
|
310
316
|
compatibility: previous.compatibility,
|
|
311
317
|
route: previous.route,
|
|
318
|
+
runId,
|
|
312
319
|
};
|
|
313
320
|
else
|
|
314
321
|
await client.close();
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/** Project internal provider routing state into the caller-visible session status. */
|
|
2
|
-
export const binarySessionStatus = ({ target, route, router, runtimeAvailability, }) => {
|
|
2
|
+
export const binarySessionStatus = ({ target, route, router, runtimeAvailability, runId, runtimeLineageSnapshots, }) => {
|
|
3
3
|
const configuredProvider = router.configuredIdentity();
|
|
4
4
|
const provider = providerSummary(configuredProvider);
|
|
5
5
|
const providers = router.providerIdentities(route).map(providerSummary);
|
|
@@ -35,6 +35,12 @@ export const binarySessionStatus = ({ target, route, router, runtimeAvailability
|
|
|
35
35
|
capabilities,
|
|
36
36
|
analysis_provider_binding: analysisProviderBinding,
|
|
37
37
|
analysis_provider_candidates: analysisProviderCandidates,
|
|
38
|
+
analysis_run: runId === undefined
|
|
39
|
+
? null
|
|
40
|
+
: {
|
|
41
|
+
run_id: runId,
|
|
42
|
+
process_lineage: processLineageStatus(runtimeLineageSnapshots),
|
|
43
|
+
},
|
|
38
44
|
};
|
|
39
45
|
return target === undefined
|
|
40
46
|
? { open: false, ...common }
|
|
@@ -49,10 +55,43 @@ export const binarySessionStatus = ({ target, route, router, runtimeAvailability
|
|
|
49
55
|
};
|
|
50
56
|
};
|
|
51
57
|
const providerSummary = ({ id, name, version, }) => ({ id, name, version });
|
|
58
|
+
const processLineageStatus = (snapshots) => snapshots.length === 0
|
|
59
|
+
? { status: "not_observed" }
|
|
60
|
+
: {
|
|
61
|
+
status: "snapshots",
|
|
62
|
+
snapshots: snapshots
|
|
63
|
+
.slice()
|
|
64
|
+
.sort((left, right) => left.provider.id.localeCompare(right.provider.id))
|
|
65
|
+
.map(({ provider, observation }) => ({
|
|
66
|
+
provider: providerSummary(provider),
|
|
67
|
+
observation: observation.status === "unavailable"
|
|
68
|
+
? {
|
|
69
|
+
status: observation.status,
|
|
70
|
+
observed_at: observation.observedAt,
|
|
71
|
+
launcher_pid: observation.launcherPid,
|
|
72
|
+
process_group_id: observation.processGroupId,
|
|
73
|
+
reason: observation.reason,
|
|
74
|
+
}
|
|
75
|
+
: {
|
|
76
|
+
status: observation.status,
|
|
77
|
+
observed_at: observation.observedAt,
|
|
78
|
+
schema_version: observation.lineage.schemaVersion,
|
|
79
|
+
launcher_pid: observation.lineage.launcherPid,
|
|
80
|
+
launcher_parent_pid: observation.lineage.launcherParentPid,
|
|
81
|
+
process_group_id: observation.lineage.processGroupId,
|
|
82
|
+
descendants: observation.lineage.descendants.map(({ pid, parentPid, processGroupId }) => ({
|
|
83
|
+
pid,
|
|
84
|
+
parent_pid: parentPid,
|
|
85
|
+
process_group_id: processGroupId,
|
|
86
|
+
})),
|
|
87
|
+
},
|
|
88
|
+
})),
|
|
89
|
+
};
|
|
52
90
|
const capabilityStatus = (descriptor) => ({
|
|
53
91
|
operation: descriptor.operation,
|
|
54
92
|
available: descriptor.available,
|
|
55
93
|
reason: descriptor.reason,
|
|
94
|
+
availability_code: descriptor.availabilityCode ?? null,
|
|
56
95
|
input_contract_version: descriptor.inputContractVersion,
|
|
57
96
|
output_contract_version: descriptor.outputContractVersion,
|
|
58
97
|
pagination: descriptor.pagination,
|
|
@@ -8,6 +8,7 @@ const statusSchema = z.object({
|
|
|
8
8
|
operation: z.string(),
|
|
9
9
|
available: z.boolean(),
|
|
10
10
|
reason: z.string().nullable(),
|
|
11
|
+
availability_code: z.string().nullable().optional(),
|
|
11
12
|
})),
|
|
12
13
|
});
|
|
13
14
|
const ENHANCED_REQUIREMENTS = {
|
|
@@ -35,7 +36,14 @@ const ENHANCED_REQUIREMENTS = {
|
|
|
35
36
|
/** Build stable per-operation availability without hiding familiar tools. */
|
|
36
37
|
export const buildCapabilityInventory = (sessionStatus, policy) => {
|
|
37
38
|
const status = statusSchema.parse(sessionStatus);
|
|
38
|
-
const descriptors = new Map(status.capabilities.map((descriptor) => [
|
|
39
|
+
const descriptors = new Map(status.capabilities.map((descriptor) => [
|
|
40
|
+
descriptor.operation,
|
|
41
|
+
{
|
|
42
|
+
available: descriptor.available,
|
|
43
|
+
reason: descriptor.reason,
|
|
44
|
+
availability_code: descriptor.availability_code ?? null,
|
|
45
|
+
},
|
|
46
|
+
]));
|
|
39
47
|
return TOOL_CONTRACTS.map((contract) => {
|
|
40
48
|
const availability = availabilityFor({
|
|
41
49
|
name: contract.name,
|
|
@@ -62,6 +70,9 @@ export const buildCapabilityInventory = (sessionStatus, policy) => {
|
|
|
62
70
|
}).sort((left, right) => left.name.localeCompare(right.name));
|
|
63
71
|
};
|
|
64
72
|
const availabilityFor = (context) => {
|
|
73
|
+
const javascriptApplication = javascriptApplicationAvailability(context);
|
|
74
|
+
if (javascriptApplication !== null)
|
|
75
|
+
return javascriptApplication;
|
|
65
76
|
const policyDecision = policyAvailability(context);
|
|
66
77
|
if (policyDecision !== null)
|
|
67
78
|
return policyDecision;
|
|
@@ -70,6 +81,18 @@ const availabilityFor = (context) => {
|
|
|
70
81
|
return targetDecision;
|
|
71
82
|
return providerAvailability(context);
|
|
72
83
|
};
|
|
84
|
+
const javascriptApplicationAvailability = ({ name, policy, }) => {
|
|
85
|
+
if (name === "analyze_javascript_application")
|
|
86
|
+
return policy.investigationInputRoots === 0
|
|
87
|
+
? {
|
|
88
|
+
reason: "policy_disabled",
|
|
89
|
+
remediation: "Configure an exact REA_INVESTIGATION_INPUT_ROOTS_JSON root in the MCP registration, then restart the registered MCP server or client.",
|
|
90
|
+
}
|
|
91
|
+
: { reason: "available", remediation: null };
|
|
92
|
+
return name === "reconcile_javascript_runtime"
|
|
93
|
+
? { reason: "available", remediation: null }
|
|
94
|
+
: null;
|
|
95
|
+
};
|
|
73
96
|
const policyAvailability = ({ name, kind, policy, }) => {
|
|
74
97
|
if (name === "capture_process_scenario" && !policy.processCaptureEnabled)
|
|
75
98
|
return {
|
|
@@ -142,7 +165,7 @@ const providerAvailability = ({ descriptors, kind, name, }) => {
|
|
|
142
165
|
remediation: "Install or configure a provider that declares this operation.",
|
|
143
166
|
};
|
|
144
167
|
if (!descriptor.available &&
|
|
145
|
-
descriptor.
|
|
168
|
+
descriptor.availability_code === "unsupported_host")
|
|
146
169
|
return {
|
|
147
170
|
reason: "unsupported_host",
|
|
148
171
|
remediation: descriptor.reason,
|
|
@@ -172,7 +195,7 @@ const composedAvailability = (name, descriptors) => {
|
|
|
172
195
|
.find((descriptor) => descriptor?.available === false);
|
|
173
196
|
if (unavailable !== undefined)
|
|
174
197
|
return {
|
|
175
|
-
reason: unavailable.
|
|
198
|
+
reason: unavailable.availability_code === "unsupported_host"
|
|
176
199
|
? "unsupported_host"
|
|
177
200
|
: "provider_unavailable",
|
|
178
201
|
remediation: unavailable.reason ?? "Choose another target or configured provider.",
|
|
@@ -27,7 +27,7 @@ const shellQuote = (value) => `'${value.replaceAll("'", `'\\''`)}'`;
|
|
|
27
27
|
* would make an unmatched dependency call look authoritative. Unmatched and
|
|
28
28
|
* exhausted routes therefore fail visibly and remain part of the capture.
|
|
29
29
|
*/
|
|
30
|
-
export const startCommandShimReplay = async (scenario, temporaryRoot, started) => {
|
|
30
|
+
export const startCommandShimReplay = async (scenario, temporaryRoot, started, recordEvent = () => undefined) => {
|
|
31
31
|
const binPath = join(temporaryRoot, "shims");
|
|
32
32
|
await mkdir(binPath);
|
|
33
33
|
const runnerPath = join(temporaryRoot, "shim-runner.mjs");
|
|
@@ -62,9 +62,10 @@ export const startCommandShimReplay = async (scenario, temporaryRoot, started) =
|
|
|
62
62
|
: "matched";
|
|
63
63
|
if (events.length >= scenario.limits.protocol_events)
|
|
64
64
|
truncated = true;
|
|
65
|
-
else
|
|
65
|
+
else {
|
|
66
|
+
const index = events.length;
|
|
66
67
|
events.push({
|
|
67
|
-
sequence:
|
|
68
|
+
sequence: index,
|
|
68
69
|
at_ms: Math.max(0, Date.now() - started),
|
|
69
70
|
command: invocation.command,
|
|
70
71
|
route_index: routeIndex !== undefined && routeIndex >= 0 ? routeIndex : null,
|
|
@@ -72,6 +73,8 @@ export const startCommandShimReplay = async (scenario, temporaryRoot, started) =
|
|
|
72
73
|
working_directory: invocation.working_directory,
|
|
73
74
|
outcome,
|
|
74
75
|
});
|
|
76
|
+
recordEvent("shim_events", index);
|
|
77
|
+
}
|
|
75
78
|
if (outcome !== "matched" || route === undefined) {
|
|
76
79
|
response.writeHead(409).end();
|
|
77
80
|
return;
|
|
@@ -51,13 +51,13 @@ export class CompositeProvider {
|
|
|
51
51
|
? Promise.resolve(ok({ profile: null, compatibility: {} }))
|
|
52
52
|
: resolve.call(this.#profileProvider, target, options);
|
|
53
53
|
}
|
|
54
|
-
createClient(target, profile) {
|
|
54
|
+
createClient(target, profile, context) {
|
|
55
55
|
const clients = new Map();
|
|
56
56
|
const clientFor = (provider) => {
|
|
57
57
|
const existing = clients.get(provider);
|
|
58
58
|
if (existing !== undefined)
|
|
59
59
|
return existing;
|
|
60
|
-
const created = provider.createClient(target, profile?.provider.id === provider.identity().id ? profile : undefined);
|
|
60
|
+
const created = provider.createClient(target, profile?.provider.id === provider.identity().id ? profile : undefined, context);
|
|
61
61
|
clients.set(provider, created);
|
|
62
62
|
return created;
|
|
63
63
|
};
|
|
@@ -77,6 +77,9 @@ export class CompositeProvider {
|
|
|
77
77
|
? Promise.resolve(err(new AnalysisCapabilityUnavailableError(this.#identity.id, operation, "operation is not declared by this provider set")))
|
|
78
78
|
: clientFor(provider).execute(operation, parameters, options);
|
|
79
79
|
},
|
|
80
|
+
runtimeLineageSnapshots: () => [...clients.values()]
|
|
81
|
+
.flatMap((client) => client.runtimeLineageSnapshots?.() ?? [])
|
|
82
|
+
.sort((left, right) => left.provider.id.localeCompare(right.provider.id)),
|
|
80
83
|
close: async () => {
|
|
81
84
|
await Promise.allSettled([...clients.values()].map(async (client) => client.close()));
|
|
82
85
|
},
|