rea-agents 2.1.0 → 2.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. package/README.md +84 -18
  2. package/dist/application/AndroidApplicationService.js +17 -0
  3. package/dist/application/AppleApplicationService.js +17 -0
  4. package/dist/application/ApplicationWorkflowEvidenceResolver.js +162 -0
  5. package/dist/application/BinarySession.js +9 -2
  6. package/dist/application/BinarySessionStatus.js +39 -1
  7. package/dist/application/CapabilityInventory.js +15 -0
  8. package/dist/application/ClientRegistrationStatus.js +11 -4
  9. package/dist/application/CommandShimReplay.js +6 -3
  10. package/dist/application/CompositeProvider.js +5 -2
  11. package/dist/application/DirectAnalysis.js +1 -20
  12. package/dist/application/DirectAnalysisStatus.js +83 -0
  13. package/dist/application/Doctor.js +34 -25
  14. package/dist/application/DoctorDiagnostics.js +1 -4
  15. package/dist/application/DoctorProjection.js +43 -0
  16. package/dist/application/DoctorScope.js +102 -0
  17. package/dist/application/EvidenceReferenceResolver.js +26 -0
  18. package/dist/application/InventoryProjectionEvidence.js +41 -0
  19. package/dist/application/InvestigationProviders.js +12 -0
  20. package/dist/application/JavaScriptApplicationEvidence.js +1 -1
  21. package/dist/application/JavaScriptApplicationEvidenceGraph.js +10 -1
  22. package/dist/application/JavaScriptApplicationService.js +3 -2
  23. package/dist/application/JavaScriptApplicationWorkflowEvidence.js +26 -0
  24. package/dist/application/JavaScriptApplicationWorkflowService.js +49 -1
  25. package/dist/application/JavaScriptArtifactReconstruction.js +7 -0
  26. package/dist/application/JavaScriptModuleRelationships.js +25 -1
  27. package/dist/application/JavaScriptReturnShapeProjection.js +111 -0
  28. package/dist/application/JavaScriptSemanticGraphBuilder.js +294 -0
  29. package/dist/application/JavaScriptSemanticGraphConstruction.js +144 -0
  30. package/dist/application/JavaScriptSemanticGraphEvidence.js +86 -0
  31. package/dist/application/JavaScriptSemanticGraphFlowProjection.js +72 -0
  32. package/dist/application/JavaScriptSemanticGraphProjection.js +33 -0
  33. package/dist/application/JavaScriptSemanticTraceService.js +45 -0
  34. package/dist/application/LoopbackReplay.js +277 -133
  35. package/dist/application/LoopbackReplayRecorder.js +101 -0
  36. package/dist/application/PermissionAuthority.js +7 -3
  37. package/dist/application/ProcessCaptureJournal.js +95 -0
  38. package/dist/application/ProcessCaptureLifecycle.js +24 -13
  39. package/dist/application/ProcessCheckpoints.js +30 -4
  40. package/dist/application/ProcessCli.js +26 -4
  41. package/dist/application/ProcessHarness.js +20 -50
  42. package/dist/application/ProcessNormalization.js +3 -2
  43. package/dist/application/ProcessPairedExperiment.js +72 -0
  44. package/dist/application/ProcessReactiveCoordinator.js +218 -0
  45. package/dist/application/ProcessReactiveEffects.js +133 -0
  46. package/dist/application/ProcessReactiveObservations.js +20 -0
  47. package/dist/application/ProcessSampling.js +2 -0
  48. package/dist/application/SessionProviderRouter.js +7 -6
  49. package/dist/application/Setup.js +14 -13
  50. package/dist/application/SetupClientConfiguration.js +10 -6
  51. package/dist/application/SetupPlan.js +4 -3
  52. package/dist/application/SetupRegistrationEnvironment.js +12 -0
  53. package/dist/application/SetupSkill.js +44 -40
  54. package/dist/application/TerminalRenderer.js +3 -1
  55. package/dist/application/Uninstall.js +7 -1
  56. package/dist/application/Upgrade.js +16 -1
  57. package/dist/browser/CdpEndpoint.js +37 -4
  58. package/dist/catalogIdentity.js +16 -7
  59. package/dist/cli/coreAnalysisCommands.js +34 -2
  60. package/dist/cli/javascriptApplicationAnalysis.js +19 -0
  61. package/dist/cli/setupCommands.js +84 -30
  62. package/dist/cli/utilityCommands.js +10 -2
  63. package/dist/cliApplicationCommands.js +79 -16
  64. package/dist/cliCommandNames.js +3 -0
  65. package/dist/cliElectronCommands.js +23 -33
  66. package/dist/cliObservationOptions.js +1 -1
  67. package/dist/cliOutput.js +56 -0
  68. package/dist/cliProcessCommands.js +32 -1
  69. package/dist/cliSetup.js +55 -29
  70. package/dist/contracts/applicationToolContracts.js +54 -7
  71. package/dist/contracts/applicationWorkflowInputContracts.js +119 -0
  72. package/dist/contracts/electronToolContracts.js +73 -4
  73. package/dist/contracts/javascriptApplicationWorkflowExamples.js +32 -9
  74. package/dist/contracts/managedToolContracts.js +7 -2
  75. package/dist/contracts/processCaptureExample.js +1 -0
  76. package/dist/contracts/replayMachineExample.js +37 -0
  77. package/dist/contracts/sessionStatusContract.js +26 -0
  78. package/dist/contracts/toolContractExamples.js +2 -0
  79. package/dist/contracts/toolContractTypes.js +12 -1
  80. package/dist/contracts/toolContracts.js +8 -11
  81. package/dist/contracts/toolEffects.js +3 -0
  82. package/dist/contracts/toolOutputSchemaGroups.js +53 -9
  83. package/dist/contracts/toolOutputSchemaPrimitives.js +73 -32
  84. package/dist/doctorRuntime.js +41 -0
  85. package/dist/domain/analysisErrorPresentation.js +5 -3
  86. package/dist/domain/analysisErrorProjection.js +7 -1
  87. package/dist/domain/androidApplication.js +206 -0
  88. package/dist/domain/appleApplication.js +221 -0
  89. package/dist/domain/boundedCartesianProjection.js +15 -0
  90. package/dist/domain/changedBehavior.js +5 -4
  91. package/dist/domain/completionLedgerGeneration.js +190 -0
  92. package/dist/domain/errors.js +4 -2
  93. package/dist/domain/evidenceCompletionLedger.js +113 -0
  94. package/dist/domain/hopperStartupFailure.js +9 -0
  95. package/dist/domain/javascriptApplicationAnalysis.js +44 -2
  96. package/dist/domain/javascriptExportShapeComparison.js +145 -0
  97. package/dist/domain/javascriptExportShapeComparisonIdentity.js +11 -0
  98. package/dist/domain/javascriptExportShapeComparisonSchemas.js +277 -0
  99. package/dist/domain/javascriptExportShapeSelection.js +132 -0
  100. package/dist/domain/javascriptExportShapeVariants.js +272 -0
  101. package/dist/domain/javascriptRuntimeReconciliationParsing.js +2 -2
  102. package/dist/domain/javascriptSemanticAnalysis.js +17 -36
  103. package/dist/domain/javascriptSemanticCallResolution.js +129 -0
  104. package/dist/domain/javascriptSemanticCalls.js +269 -0
  105. package/dist/domain/javascriptSemanticGraph.js +356 -0
  106. package/dist/domain/javascriptSemanticGraphSchemas.js +329 -0
  107. package/dist/domain/javascriptSemanticGraphSerialization.js +23 -0
  108. package/dist/domain/javascriptSemanticIr.js +14 -1
  109. package/dist/domain/javascriptSemanticPrimitives.js +36 -0
  110. package/dist/domain/javascriptSemanticProjection.js +36 -4
  111. package/dist/domain/javascriptSemanticProvenance.js +29 -0
  112. package/dist/domain/javascriptSemanticQuery.js +294 -0
  113. package/dist/domain/javascriptSemanticQueryAssessment.js +74 -0
  114. package/dist/domain/javascriptSemanticQueryIdentity.js +86 -0
  115. package/dist/domain/javascriptSemanticQueryRelations.js +15 -0
  116. package/dist/domain/javascriptSemanticQuerySchemas.js +188 -0
  117. package/dist/domain/javascriptSemanticReturns.js +187 -0
  118. package/dist/domain/javascriptSemanticState.js +32 -0
  119. package/dist/domain/javascriptSemanticTraceSchemas.js +14 -0
  120. package/dist/domain/javascriptSemanticValues.js +54 -70
  121. package/dist/domain/processCapture.js +36 -0
  122. package/dist/domain/processCaptureValidation.js +101 -12
  123. package/dist/domain/processComparison.js +96 -24
  124. package/dist/domain/processObservation.js +153 -0
  125. package/dist/domain/processPairedExperiment.js +128 -0
  126. package/dist/domain/processReactiveCheckpointDataflow.js +32 -0
  127. package/dist/domain/processReactiveMatching.js +210 -0
  128. package/dist/domain/processReactiveRuntime.js +109 -0
  129. package/dist/domain/processReactiveScenario.js +361 -0
  130. package/dist/domain/processReactiveScenarioPreflight.js +120 -0
  131. package/dist/domain/processReactiveTransition.js +159 -0
  132. package/dist/domain/processScenario.js +12 -0
  133. package/dist/domain/processTraceComparison.js +43 -0
  134. package/dist/domain/processTraceDimensionProjection.js +50 -0
  135. package/dist/domain/processTraceEvaluation.js +312 -0
  136. package/dist/domain/processTraceSpecification.js +373 -0
  137. package/dist/domain/reconstructionVerification.js +5 -4
  138. package/dist/domain/replayMachine.js +332 -0
  139. package/dist/domain/replayMachineRun.js +216 -0
  140. package/dist/domain/replayMachineRuntime.js +294 -0
  141. package/dist/domain/runtimeIdentification.js +210 -0
  142. package/dist/domain/staticRuntimeCorrelation.js +4 -2
  143. package/dist/evaluation/CodexAgentEval.js +156 -0
  144. package/dist/generatedPackageMetadata.js +2 -2
  145. package/dist/ghidra/GhidraClient.js +13 -2
  146. package/dist/ghidra/GhidraDiagnostics.js +1 -0
  147. package/dist/ghidra/GhidraLauncher.js +7 -3
  148. package/dist/ghidra/GhidraProvider.js +8 -1
  149. package/dist/hopper/BridgeLauncher.js +56 -14
  150. package/dist/hopper/HopperClient.js +23 -10
  151. package/dist/hopper/HopperDiagnostics.js +14 -0
  152. package/dist/hopper/HopperProcessDiagnostic.js +14 -0
  153. package/dist/hopper/HopperProvider.js +8 -1
  154. package/dist/hopper/LinuxPrivateDisplayDiagnostic.js +72 -0
  155. package/dist/hopper/LinuxPrivateDisplayProbe.js +217 -0
  156. package/dist/identity.js +2 -1
  157. package/dist/main/transport.js +2 -0
  158. package/dist/mcpDoctor.js +310 -0
  159. package/dist/process/ProcessOwnership.js +200 -53
  160. package/dist/process/ProviderRunLineage.js +21 -0
  161. package/dist/server/createServer.js +8 -2
  162. package/dist/server/javascriptApplicationResult.js +106 -0
  163. package/dist/server/registerApplicationTools/characterization.js +3 -3
  164. package/dist/server/registerApplicationTools/compareExportShapes.js +37 -0
  165. package/dist/server/registerApplicationTools/compareVersions.js +12 -6
  166. package/dist/server/registerApplicationTools/controlledReplay.js +2 -2
  167. package/dist/server/registerApplicationTools/coverage.js +3 -3
  168. package/dist/server/registerApplicationTools/helpers.js +37 -25
  169. package/dist/server/registerApplicationTools/traceFeature.js +9 -5
  170. package/dist/server/registerApplicationTools/traceSemantics.js +30 -0
  171. package/dist/server/registerApplicationTools.js +4 -0
  172. package/dist/server/registerElectronTools.js +19 -5
  173. package/dist/server/registerEvidenceResources.js +7 -1
  174. package/dist/server/registerJavaScriptApplicationGraphResource.js +69 -0
  175. package/dist/server/registerManagedTools.js +18 -1
  176. package/dist/server/registerProcessComparisonTool.js +17 -7
  177. package/dist/server/registerReplayMachineTool.js +20 -0
  178. package/dist/server/registerSessionStatusTool.js +95 -25
  179. package/dist/server/registerSessionTools.js +12 -7
  180. package/dist/server/sessionAvailabilityPolicy.js +2 -1
  181. package/dist/server/toolResult.js +10 -4
  182. package/dist/serverIdentity.js +19 -0
  183. package/package.json +62 -29
  184. package/scripts/hopper-demo-x11.py +459 -61
  185. package/scripts/prepack.mjs +55 -0
  186. package/scripts/prepare.mjs +28 -0
  187. package/scripts/rea.mjs +26 -5
  188. package/skills/reverse-engineer-anything/SKILL.md +69 -228
  189. package/skills/reverse-engineer-anything/references/controlled-replay.md +12 -0
  190. package/skills/reverse-engineer-anything/references/evidence-workflows.md +33 -0
  191. package/skills/reverse-engineer-anything/references/javascript-applications.md +35 -0
  192. package/skills/reverse-engineer-anything/references/native-and-artifacts.md +36 -0
  193. package/skills/reverse-engineer-anything/references/runtime-observation.md +24 -0
@@ -1,5 +1,8 @@
1
1
  import { Cli, z } from "incur";
2
- import { compareApplicationVersionsEvidence, traceApplicationFeatureEvidence, } from "./application/JavaScriptApplicationWorkflowService.js";
2
+ import { compareApplicationVersionsEvidenceValidated, compareJavaScriptExportShapesEvidenceValidated, traceApplicationFeatureEvidenceValidated, } from "./application/JavaScriptApplicationWorkflowService.js";
3
+ import { traceJavaScriptSemanticsEvidenceValidated } from "./application/JavaScriptSemanticTraceService.js";
4
+ import { resolveCompareApplicationVersionsRequest, resolveCompareJavaScriptExportShapesRequest, resolveTraceApplicationFeatureRequest, resolveTraceJavaScriptSemanticsRequest, } from "./application/ApplicationWorkflowEvidenceResolver.js";
5
+ import { readEvidenceBundle } from "./application/EvidenceBundleFiles.js";
3
6
  import { runControlledReplay } from "./application/JavaScriptReplayService.js";
4
7
  import { executeNodeCharacterization, prepareNodeCharacterization, } from "./application/NodeRuntimeCharacterizationService.js";
5
8
  import { commitReconstructionCoverage, queryReconstructionCoverage, reconstructionCoverageCommitInputSchema, reconstructionCoverageQueryInputSchema, } from "./application/ReconstructionCoverageService.js";
@@ -19,14 +22,32 @@ export const registerApplicationCommands = (cli, logger) => {
19
22
  logger,
20
23
  name: CLI_COMMANDS.traceApplicationFeature,
21
24
  description: "Trace a typed seed through authenticated application Evidence JSON",
22
- workflow: traceApplicationFeatureEvidence,
25
+ resolveInput: resolveTraceApplicationFeatureRequest,
26
+ workflow: traceApplicationFeatureEvidenceValidated,
27
+ });
28
+ registerJsonCommand({
29
+ cli,
30
+ logger,
31
+ name: CLI_COMMANDS.traceJavaScriptSemantics,
32
+ description: "Trace bounded static semantic relations through authenticated application Evidence",
33
+ resolveInput: resolveTraceJavaScriptSemanticsRequest,
34
+ workflow: traceJavaScriptSemanticsEvidenceValidated,
23
35
  });
24
36
  registerJsonCommand({
25
37
  cli,
26
38
  logger,
27
39
  name: CLI_COMMANDS.compareApplicationVersions,
28
40
  description: "Compare two authenticated JavaScript Application Graph versions",
29
- workflow: compareApplicationVersionsEvidence,
41
+ resolveInput: resolveCompareApplicationVersionsRequest,
42
+ workflow: compareApplicationVersionsEvidenceValidated,
43
+ });
44
+ registerJsonCommand({
45
+ cli,
46
+ logger,
47
+ name: CLI_COMMANDS.compareJavaScriptExportShapes,
48
+ description: "Compare exact static JavaScript export return shapes without execution",
49
+ resolveInput: resolveCompareJavaScriptExportShapesRequest,
50
+ workflow: compareJavaScriptExportShapesEvidenceValidated,
30
51
  });
31
52
  cli.command(CLI_COMMANDS.runControlledReplay, {
32
53
  description: "Plan or execute an approved extracted-module replay in the Linux sandbox",
@@ -138,13 +159,10 @@ const registerCoverageCommands = (cli, logger) => {
138
159
  });
139
160
  };
140
161
  const configuredAuthority = async () => {
141
- const config = parseConfig(process.env);
142
- if (!config.ok)
143
- return { ok: false, error: projectAnalysisError(config.error) };
144
- const authority = await loadConfiguredPermissionAuthority(config.value);
145
- return authority.ok
146
- ? { ok: true, config: config.value, authority: authority.value }
147
- : { ok: false, error: projectAnalysisError(authority.error) };
162
+ const configured = await loadConfiguredAuthority();
163
+ return configured.ok
164
+ ? configured
165
+ : { ok: false, error: projectAnalysisError(configured.error) };
148
166
  };
149
167
  const replayDependencies = (config, authority) => ({
150
168
  policy: config.javascriptReplayPolicy,
@@ -152,25 +170,70 @@ const replayDependencies = (config, authority) => ({
152
170
  runner: new LinuxJavaScriptReplayRunner(),
153
171
  authority,
154
172
  });
155
- const registerJsonCommand = ({ cli, logger, name, description, workflow, }) => {
173
+ const registerJsonCommand = ({ cli, logger, name, description, resolveInput, workflow, }) => {
156
174
  cli.command(name, {
157
175
  description,
158
176
  args: z.object({
159
177
  inputJson: z.string().describe("Inline workflow JSON or JSON file path"),
160
178
  }),
161
- run: ({ args }) => logCliCommand(logger, name, async () => {
179
+ options: z.object({
180
+ evidenceBundle: z
181
+ .string()
182
+ .optional()
183
+ .describe("Authorized Evidence bundle used to resolve Evidence IDs"),
184
+ }),
185
+ run: ({ args, options }) => logCliCommand(logger, name, async () => {
162
186
  const input = await parseCliJsonInput(args.inputJson, name);
163
187
  if (!input.ok)
164
188
  return input.error;
165
- const result = workflow(input.value);
189
+ const lookup = await loadEvidenceLookup(options.evidenceBundle, name);
190
+ if (!lookup.ok)
191
+ return {
192
+ error: "Application workflow failed",
193
+ ...projectAnalysisError(lookup.error),
194
+ };
195
+ const resolved = resolveInput(input.value, lookup.value);
196
+ if (!resolved.ok)
197
+ return {
198
+ error: "Application workflow failed",
199
+ ...projectAnalysisError(resolved.error),
200
+ };
201
+ const result = workflow(resolved.value);
166
202
  return result.ok
167
203
  ? result.value
168
204
  : {
169
205
  error: "Application workflow failed",
170
- ...projectAnalysisError(result.error instanceof AnalysisInputError
171
- ? result.error
172
- : new AnalysisInputError(name)),
206
+ ...projectAnalysisError(result.error),
173
207
  };
174
208
  }),
175
209
  });
176
210
  };
211
+ const loadEvidenceLookup = async (bundlePath, operation) => {
212
+ if (bundlePath === undefined)
213
+ return { ok: true, value: undefined };
214
+ const configured = await loadConfiguredAuthority();
215
+ if (!configured.ok)
216
+ return configured;
217
+ const authorized = await authorizeRootPermission(configured.authority, {
218
+ capability: "evidence_read",
219
+ roots: [bundlePath],
220
+ access: "read",
221
+ operation,
222
+ });
223
+ if (!authorized.ok)
224
+ return authorized;
225
+ const loaded = await readEvidenceBundle(bundlePath, configured.config.evidenceFilePolicy);
226
+ if (!loaded.ok)
227
+ return loaded;
228
+ const records = new Map(loaded.value.records.map((record) => [record.evidence_id, record]));
229
+ return { ok: true, value: (evidenceId) => records.get(evidenceId) };
230
+ };
231
+ const loadConfiguredAuthority = async () => {
232
+ const config = parseConfig(process.env);
233
+ if (!config.ok)
234
+ return config;
235
+ const authority = await loadConfiguredPermissionAuthority(config.value);
236
+ return authority.ok
237
+ ? { ok: true, config: config.value, authority: authority.value }
238
+ : authority;
239
+ };
@@ -49,7 +49,10 @@ export const CLI_COMMANDS = Object.freeze({
49
49
  analyzeJavaScriptApplication: "analyze-javascript-application",
50
50
  reconcileJavaScriptRuntime: "reconcile-javascript-runtime",
51
51
  traceApplicationFeature: "trace-application-feature",
52
+ traceJavaScriptSemantics: "trace-javascript-semantics",
52
53
  compareApplicationVersions: "compare-application-versions",
54
+ compareJavaScriptExportShapes: "compare-javascript-export-shapes",
55
+ runReplayMachine: "run-replay-machine",
53
56
  runControlledReplay: "run-controlled-replay",
54
57
  prepareNodeCharacterization: "prepare-node-characterization",
55
58
  executeNodeCharacterization: "execute-node-characterization",
@@ -1,17 +1,16 @@
1
1
  import { Cli, z } from "incur";
2
2
  import { inspectElectronPage, listElectronTargets, } from "./application/ElectronObservationService.js";
3
- import { analyzeJavaScriptApplication } from "./application/JavaScriptApplicationService.js";
4
3
  import { reconcileJavaScriptRuntimeEvidence } from "./application/JavaScriptRuntimeReconciliationService.js";
5
4
  import { loadConfiguredPermissionAuthority } from "./application/PermissionConfiguration.js";
6
5
  import { CdpElectronProvider } from "./browser/CdpElectronProvider.js";
7
6
  import { logCliCommand } from "./cliLogging.js";
8
7
  import { parseConfig } from "./config.js";
9
8
  import { inspectElectronPageInputSchema, listElectronTargetsInputSchema, } from "./domain/electronObservation.js";
10
- import { analyzeJavaScriptApplicationInputSchema } from "./domain/javascriptApplicationAnalysis.js";
11
9
  import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
12
10
  import { CLI_COMMANDS } from "./cliCommandNames.js";
13
11
  import { parseCliJsonInput } from "./cliJsonInput.js";
14
12
  import { electronPageInspectionOptions, javascriptApplicationOptions, } from "./cliObservationOptions.js";
13
+ import { runCliJavaScriptApplicationAnalysis } from "./cli/javascriptApplicationAnalysis.js";
15
14
  const scopeOptions = {
16
15
  allowedFileRoots: z
17
16
  .array(z.string().min(1))
@@ -134,37 +133,28 @@ const registerJavaScriptApplicationCommand = (cli, logger) => {
134
133
  path: z.string().describe("Absolute ASAR or extracted application path"),
135
134
  }),
136
135
  options: javascriptApplicationOptions,
137
- run: ({ args, options }) => logCliCommand(logger, CLI_COMMANDS.analyzeJavaScriptApplication, async () => {
138
- const context = await electronContext();
139
- if (!context.ok)
140
- return context.error;
141
- const parsed = analyzeJavaScriptApplicationInputSchema.safeParse({
142
- input_path: args.path,
143
- approved: options.approved,
144
- format: options.format,
145
- source_map_read_approved: options.sourceMapReadApproved,
146
- limits: {
147
- max_entries: options.maxEntries,
148
- max_total_artifact_bytes: options.maxTotalArtifactBytes,
149
- max_artifact_entry_bytes: options.maxArtifactEntryBytes,
150
- max_compression_ratio: options.maxCompressionRatio,
151
- max_depth: options.maxDepth,
152
- max_path_bytes: options.maxPathBytes,
153
- max_text_files: options.maxTextFiles,
154
- max_total_text_bytes: options.maxTotalTextBytes,
155
- max_text_file_bytes: options.maxTextFileBytes,
156
- max_ast_nodes: options.maxAstNodes,
157
- max_findings: options.maxFindings,
158
- max_modules: options.maxModules,
159
- max_source_map_sources: options.maxSourceMapSources,
160
- max_parse_milliseconds: options.maxParseMilliseconds,
161
- },
162
- });
163
- if (!parsed.success)
164
- return inputError("analyze_javascript_application");
165
- const result = await analyzeJavaScriptApplication(context.authority, parsed.data);
166
- return result.ok ? result.value : cliError(result.error);
167
- }),
136
+ run: ({ args, options }) => logCliCommand(logger, CLI_COMMANDS.analyzeJavaScriptApplication, () => runCliJavaScriptApplicationAnalysis({
137
+ input_path: args.path,
138
+ approved: options.approved,
139
+ format: options.artifactFormat,
140
+ source_map_read_approved: options.sourceMapReadApproved,
141
+ limits: {
142
+ max_entries: options.maxEntries,
143
+ max_total_artifact_bytes: options.maxTotalArtifactBytes,
144
+ max_artifact_entry_bytes: options.maxArtifactEntryBytes,
145
+ max_compression_ratio: options.maxCompressionRatio,
146
+ max_depth: options.maxDepth,
147
+ max_path_bytes: options.maxPathBytes,
148
+ max_text_files: options.maxTextFiles,
149
+ max_total_text_bytes: options.maxTotalTextBytes,
150
+ max_text_file_bytes: options.maxTextFileBytes,
151
+ max_ast_nodes: options.maxAstNodes,
152
+ max_findings: options.maxFindings,
153
+ max_modules: options.maxModules,
154
+ max_source_map_sources: options.maxSourceMapSources,
155
+ max_parse_milliseconds: options.maxParseMilliseconds,
156
+ },
157
+ })),
168
158
  });
169
159
  };
170
160
  const electronContext = async () => {
@@ -108,7 +108,7 @@ export const javascriptApplicationOptions = z.object({
108
108
  .boolean()
109
109
  .default(false)
110
110
  .describe("Approve reading the application artifact"),
111
- format: z
111
+ artifactFormat: z
112
112
  .enum(["auto", "asar", "directory"])
113
113
  .default("auto")
114
114
  .describe("Application artifact format"),
package/dist/cliOutput.js CHANGED
@@ -1,4 +1,5 @@
1
1
  const SAFE_VALIDATION_MESSAGE = "REA could not read the command arguments. Run `rea --help`, correct the arguments, then try again.";
2
+ const UNSUPPORTED_OUTPUT_COMBINATION_MESSAGE = "Token windows cannot preserve structured output. Remove --token-limit/--token-offset and use --filter-output or command pagination.";
2
3
  const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
3
4
  const validationError = (value) => {
4
5
  if (!isRecord(value))
@@ -9,6 +10,61 @@ const validationError = (value) => {
9
10
  return value.error.code === "VALIDATION_ERROR" ? value.error : undefined;
10
11
  return undefined;
11
12
  };
13
+ /** Reject text-window controls that would corrupt a structured document. */
14
+ export const validateCliOutputArguments = (arguments_) => {
15
+ let format = "toon";
16
+ let tokenWindow = false;
17
+ for (let index = 0; index < arguments_.length; index += 1) {
18
+ const argument = arguments_[index];
19
+ if (argument === "--")
20
+ break;
21
+ if (argument === "--json") {
22
+ format = "json";
23
+ continue;
24
+ }
25
+ if (argument === "--format") {
26
+ const value = arguments_[index + 1];
27
+ if (value !== undefined) {
28
+ format = value;
29
+ index += 1;
30
+ }
31
+ continue;
32
+ }
33
+ if (argument?.startsWith("--format=")) {
34
+ format = argument.slice("--format=".length);
35
+ continue;
36
+ }
37
+ if (argument === "--token-limit" || argument === "--token-offset") {
38
+ if (arguments_[index + 1] !== undefined) {
39
+ tokenWindow = true;
40
+ index += 1;
41
+ }
42
+ continue;
43
+ }
44
+ if (argument?.startsWith("--token-limit=") ||
45
+ argument?.startsWith("--token-offset="))
46
+ tokenWindow = true;
47
+ }
48
+ if (tokenWindow &&
49
+ (format === "json" || format === "jsonl" || format === "yaml"))
50
+ return {
51
+ ok: false,
52
+ format,
53
+ code: "UNSUPPORTED_OUTPUT_COMBINATION",
54
+ message: UNSUPPORTED_OUTPUT_COMBINATION_MESSAGE,
55
+ };
56
+ return { ok: true };
57
+ };
58
+ /** Render one complete structured error before command execution. */
59
+ export const renderCliOutputArgumentError = (error) => {
60
+ const value = {
61
+ ok: false,
62
+ error: { code: error.code, message: error.message },
63
+ };
64
+ if (error.format === "yaml")
65
+ return `ok: false\nerror:\n code: ${error.code}\n message: ${JSON.stringify(error.message)}\n`;
66
+ return `${JSON.stringify(value)}\n`;
67
+ };
12
68
  /** Remove validator internals from Incur's caller-visible CLI output. */
13
69
  export const sanitizeCliOutput = (output) => {
14
70
  const trimmed = output.trimStart();
@@ -2,8 +2,13 @@ import { Cli, z } from "incur";
2
2
  import { captureProcessScenarioFile, compareProcessEvidenceFiles, } from "./application/ProcessCli.js";
3
3
  import { logCliCommand } from "./cliLogging.js";
4
4
  import { CLI_COMMANDS } from "./cliCommandNames.js";
5
+ import { parseCliJsonInput } from "./cliJsonInput.js";
6
+ import { replayMachineRunInputSchema, runReplayMachine, } from "./domain/replayMachineRun.js";
7
+ import { AnalysisInputError, projectAnalysisError } from "./domain/errors.js";
8
+ import { projectInputIssues } from "./domain/inputIssueProjection.js";
5
9
  /** Register Process Capture v4 one-shot commands through shared application services. */
6
10
  export const registerProcessCommands = (cli, logger) => {
11
+ registerReplayMachineCommand(cli, logger);
7
12
  cli.command(CLI_COMMANDS.captureProcess, {
8
13
  description: "Capture one approved Process Capture v4 JSON scenario",
9
14
  args: z.object({ scenario: z.string().describe("Scenario JSON path") }),
@@ -14,7 +19,33 @@ export const registerProcessCommands = (cli, logger) => {
14
19
  args: z.object({
15
20
  left: z.string().describe("Left capture Evidence JSON path"),
16
21
  right: z.string().describe("Right capture Evidence JSON path"),
22
+ traceSpec: z
23
+ .string()
24
+ .optional()
25
+ .describe("Optional partial-order or finite-trace specification path"),
26
+ }),
27
+ run: ({ args }) => logCliCommand(logger, "compare-process-captures", () => compareProcessEvidenceFiles(args.left, args.right, args.traceSpec)),
28
+ });
29
+ };
30
+ const registerReplayMachineCommand = (cli, logger) => {
31
+ cli.command(CLI_COMMANDS.runReplayMachine, {
32
+ description: "Run ordered protocol events directly through a finite replay machine",
33
+ args: z.object({
34
+ inputJson: z.string().describe("Inline replay JSON or JSON file path"),
35
+ }),
36
+ run: ({ args }) => logCliCommand(logger, CLI_COMMANDS.runReplayMachine, async () => {
37
+ const input = await parseCliJsonInput(args.inputJson, CLI_COMMANDS.runReplayMachine);
38
+ if (!input.ok)
39
+ return input.error;
40
+ const parsed = replayMachineRunInputSchema.safeParse(input.value);
41
+ return parsed.success
42
+ ? runReplayMachine(parsed.data)
43
+ : {
44
+ error: "Process command failed",
45
+ ...projectAnalysisError(new AnalysisInputError(CLI_COMMANDS.runReplayMachine, {
46
+ cause: parsed.error,
47
+ }, projectInputIssues(parsed.error.issues, input.value))),
48
+ };
17
49
  }),
18
- run: ({ args }) => logCliCommand(logger, "compare-process-captures", () => compareProcessEvidenceFiles(args.left, args.right)),
19
50
  });
20
51
  };
package/dist/cliSetup.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { cancel, confirm, intro, isCancel, multiselect, outro, } from "@clack/prompts";
2
+ import { projectDoctorReport } from "./application/DoctorProjection.js";
2
3
  import { SUPPORTED_CLIENT_DEFINITIONS } from "./application/SupportedClients.js";
3
4
  const clientDisplayNames = new Map(SUPPORTED_CLIENT_DEFINITIONS.map(({ name, displayName }) => [
4
5
  name,
@@ -9,8 +10,8 @@ const promptStreams = {
9
10
  output: process.stderr,
10
11
  withGuide: true,
11
12
  };
12
- const agentAccessCapabilityId = "agent_access";
13
- /** Run the inline setup picker, exact preflight, and default-No consent. */
13
+ const agentIntegrationCapabilityId = "agent_integration";
14
+ /** Run the inline setup picker, exact preflight, and explicit consent. */
14
15
  export const confirmInteractiveSetup = async (actions, accessible) => {
15
16
  intro("REA setup", promptStreams);
16
17
  renderValueIntroduction();
@@ -31,7 +32,7 @@ export const confirmInteractiveSetup = async (actions, accessible) => {
31
32
  message: selectedActions.length === 1
32
33
  ? "Apply this change?"
33
34
  : `Apply these ${String(selectedActions.length)} changes?`,
34
- initialValue: false,
35
+ initialValue: true,
35
36
  active: "Yes, apply",
36
37
  inactive: "No, cancel",
37
38
  });
@@ -77,10 +78,7 @@ export const conciseSetupResult = (result) => ({
77
78
  plannedActions: result.plannedActions,
78
79
  appliedActions: result.appliedActions,
79
80
  clients: result.clients,
80
- doctor: {
81
- healthy: result.doctor.healthy,
82
- checks: result.doctor.checks.filter(({ ok }) => !ok),
83
- },
81
+ doctor: projectDoctorReport(result.doctor, "summary"),
84
82
  ...(result.code === undefined ? {} : { code: result.code }),
85
83
  ...(result.remediation === undefined
86
84
  ? {}
@@ -90,41 +88,65 @@ const selectSetupActions = async (actions, accessible) => {
90
88
  const clientActions = actions.filter(({ kind }) => kind === "configure_client");
91
89
  const componentActions = actions.filter(({ kind }) => kind !== "configure_client");
92
90
  const capabilities = setupCapabilities(clientActions, componentActions);
91
+ const preselectedCapabilityIds = defaultCapabilityIds(capabilities);
93
92
  const selectedCapabilities = accessible
94
- ? await selectCapabilitiesAccessibly(capabilities)
95
- : await selectCapabilities(capabilities);
93
+ ? await selectCapabilitiesAccessibly(capabilities, preselectedCapabilityIds)
94
+ : await selectCapabilities(capabilities, preselectedCapabilityIds);
96
95
  if (selectedCapabilities === undefined)
97
96
  return undefined;
98
97
  const selectedCapabilityIds = new Set(selectedCapabilities);
98
+ const bundledSkillAction = componentActions.find(({ kind }) => kind === "install_skill");
99
99
  const selectedActionIds = componentActions
100
- .filter(({ id }) => selectedCapabilityIds.has(id))
100
+ .filter(({ id }) => id !== bundledSkillAction?.id && selectedCapabilityIds.has(id))
101
101
  .map(({ id }) => id);
102
- if (!selectedCapabilityIds.has(agentAccessCapabilityId))
102
+ if (!selectedCapabilityIds.has(agentIntegrationCapabilityId))
103
103
  return selectedActionIds;
104
+ const bundledSkillId = bundledSkillAction === undefined ? undefined : bundledSkillAction.id;
105
+ if (clientActions.length === 0)
106
+ return [
107
+ ...(bundledSkillId === undefined ? [] : [bundledSkillId]),
108
+ ...selectedActionIds,
109
+ ];
110
+ const preselectedClientIds = clientActions.map(({ id }) => id);
104
111
  const selectedClients = accessible
105
- ? await selectClientsAccessibly(clientActions)
106
- : await selectClients(clientActions);
107
- return selectedClients === undefined
108
- ? undefined
109
- : [...selectedClients, ...selectedActionIds];
112
+ ? await selectClientsAccessibly(clientActions, preselectedClientIds)
113
+ : await selectClients(clientActions, preselectedClientIds);
114
+ if (selectedClients === undefined)
115
+ return undefined;
116
+ return [
117
+ ...selectedClients,
118
+ ...(bundledSkillId === undefined ? [] : [bundledSkillId]),
119
+ ...selectedActionIds,
120
+ ];
121
+ };
122
+ const defaultCapabilityIds = (capabilities) => {
123
+ const hasAgentIntegration = capabilities.some(({ id }) => id === agentIntegrationCapabilityId);
124
+ if (!hasAgentIntegration)
125
+ return [];
126
+ return [agentIntegrationCapabilityId];
110
127
  };
111
128
  const setupCapabilities = (clientActions, componentActions) => [
112
- ...(clientActions.length === 0
129
+ ...(clientActions.length === 0 &&
130
+ !componentActions.some(({ kind }) => kind === "install_skill")
113
131
  ? []
114
132
  : [
115
133
  {
116
- id: agentAccessCapabilityId,
117
- label: "Coding-agent access (MCP)",
118
- hint: `${String(clientActions.length)} detected ${clientActions.length === 1 ? "agent" : "agents"}`,
134
+ id: agentIntegrationCapabilityId,
135
+ label: "Agent integration (MCP + guided workflow)",
136
+ hint: clientActions.length === 0
137
+ ? "MCP registrations are aligned; installs the matching bundled skill"
138
+ : `${String(clientActions.length)} detected ${clientActions.length === 1 ? "agent" : "agents"}; installs the bundled skill when needed`,
119
139
  },
120
140
  ]),
121
- ...componentActions.map((action) => ({
141
+ ...componentActions
142
+ .filter(({ kind }) => kind !== "install_skill")
143
+ .map((action) => ({
122
144
  id: action.id,
123
145
  label: `${action.label} (${actionModality(action)})`,
124
146
  hint: `${action.operation} · ${action.target}`,
125
147
  })),
126
148
  ];
127
- const selectCapabilities = async (capabilities) => {
149
+ const selectCapabilities = async (capabilities, initialValues) => {
128
150
  const selection = await multiselect({
129
151
  ...promptStreams,
130
152
  message: "What should REA set up?",
@@ -133,19 +155,21 @@ const selectCapabilities = async (capabilities) => {
133
155
  label: capability.label,
134
156
  hint: capability.hint,
135
157
  })),
158
+ initialValues: [...initialValues],
136
159
  required: false,
137
160
  maxItems: Math.max(3, Math.min(capabilities.length, (process.stderr.rows ?? 24) - 8)),
138
161
  showInstructions: true,
139
162
  });
140
163
  return isCancel(selection) ? undefined : selection;
141
164
  };
142
- const selectCapabilitiesAccessibly = async (capabilities) => {
165
+ const selectCapabilitiesAccessibly = async (capabilities, preselectedIds) => {
166
+ const preselected = new Set(preselectedIds);
143
167
  const selected = [];
144
168
  for (const capability of capabilities) {
145
169
  const included = await confirm({
146
170
  ...promptStreams,
147
171
  message: `Set up ${capability.label}? ${capability.hint}`,
148
- initialValue: false,
172
+ initialValue: preselected.has(capability.id),
149
173
  vertical: true,
150
174
  });
151
175
  if (isCancel(included))
@@ -155,28 +179,30 @@ const selectCapabilitiesAccessibly = async (capabilities) => {
155
179
  }
156
180
  return selected;
157
181
  };
158
- const selectClients = async (actions) => {
182
+ const selectClients = async (actions, initialValues) => {
159
183
  const selection = await multiselect({
160
184
  ...promptStreams,
161
185
  message: "Which agents should use REA?",
162
186
  options: actions.map((action) => ({
163
187
  value: action.id,
164
188
  label: `${action.label} (detected)`,
165
- hint: `${action.operation} · ${action.target}`,
189
+ hint: `Configure the REA MCP server for ${action.label}`,
166
190
  })),
191
+ initialValues: [...initialValues],
167
192
  required: false,
168
193
  maxItems: Math.max(3, Math.min(actions.length, (process.stderr.rows ?? 24) - 8)),
169
194
  showInstructions: true,
170
195
  });
171
196
  return isCancel(selection) ? undefined : selection;
172
197
  };
173
- const selectClientsAccessibly = async (actions) => {
198
+ const selectClientsAccessibly = async (actions, initialValues) => {
199
+ const preselected = new Set(initialValues);
174
200
  const selected = [];
175
201
  for (const action of actions) {
176
202
  const included = await confirm({
177
203
  ...promptStreams,
178
204
  message: `Configure ${action.label}? ${action.target}`,
179
- initialValue: false,
205
+ initialValue: preselected.has(action.id),
180
206
  vertical: true,
181
207
  });
182
208
  if (isCancel(included))
@@ -223,7 +249,7 @@ const renderReadyCapabilities = (result, readyClients) => {
223
249
  writeLine("│ CLI: rea analyze /path/to/app");
224
250
  const firstClient = readyClients[0];
225
251
  if (firstClient !== undefined)
226
- writeLine(`│ Try in ${firstClient}: "Use REA to explain how a feature works in /path/to/app."`);
252
+ writeLine(`│ Try in ${firstClient}: "Explain how a feature works in /path/to/app and show the evidence."`);
227
253
  };
228
254
  const readyAgentClients = (result, changedClients) => {
229
255
  const alignedClients = (result.doctor.identity?.registrations ?? [])
@@ -1,5 +1,8 @@
1
- import { applicationVersionComparisonResultSchema, compareApplicationVersionsInputSchema, } from "../domain/javascriptApplicationVersionComparisonSchemas.js";
2
- import { applicationFeatureTraceResultSchema, traceApplicationFeatureInputSchema, } from "../domain/javascriptFeatureTraceSchemas.js";
1
+ import { applicationVersionComparisonResultSchema } from "../domain/javascriptApplicationVersionComparisonSchemas.js";
2
+ import { applicationFeatureTraceResultSchema } from "../domain/javascriptFeatureTraceSchemas.js";
3
+ import { javaScriptSemanticTraceResultSchema } from "../domain/javascriptSemanticTraceSchemas.js";
4
+ import { javaScriptExportShapeComparisonResultSchema } from "../domain/javascriptExportShapeComparisonSchemas.js";
5
+ import { compareApplicationVersionsRequestSchema, compareJavaScriptExportShapesRequestSchema, traceApplicationFeatureRequestSchema, traceJavaScriptSemanticsRequestSchema, } from "./applicationWorkflowInputContracts.js";
3
6
  import { controlledReplayInputSchema, controlledReplayOutputSchema, } from "../domain/javascriptReplay.js";
4
7
  import { nodeCharacterizationExecutionInputSchema, nodeCharacterizationExecutionOutputSchema, nodeCharacterizationPreparationInputSchema, nodeCharacterizationPreparationOutputSchema, } from "../domain/nodeRuntimeCharacterization.js";
5
8
  import { reconstructionCoverageCommitInputSchema, reconstructionCoverageCommitOutputSchema, reconstructionCoverageQueryInputSchema, } from "../application/ReconstructionCoverageService.js";
@@ -7,9 +10,11 @@ import { reconstructionClosureResultSchema } from "../domain/reconstructionCover
7
10
  import { jsonObjectSchema } from "../domain/jsonValue.js";
8
11
  import { toolContractMetadata } from "./toolEffects.js";
9
12
  import { evidenceResultOf } from "./toolOutputSchemas.js";
10
- import { JAVASCRIPT_APPLICATION_VERSION_COMPARISON_EXAMPLE, JAVASCRIPT_FEATURE_TRACE_EXAMPLE, } from "./javascriptApplicationWorkflowExamples.js";
13
+ import { JAVASCRIPT_APPLICATION_VERSION_COMPARISON_EXAMPLE, JAVASCRIPT_EXPORT_SHAPE_COMPARISON_EXAMPLE, JAVASCRIPT_FEATURE_TRACE_EXAMPLE, } from "./javascriptApplicationWorkflowExamples.js";
11
14
  const traceOutputSchema = evidenceResultOf(applicationFeatureTraceResultSchema);
15
+ const semanticTraceOutputSchema = evidenceResultOf(javaScriptSemanticTraceResultSchema);
12
16
  const comparisonOutputSchema = evidenceResultOf(applicationVersionComparisonResultSchema);
17
+ const exportShapeComparisonOutputSchema = evidenceResultOf(javaScriptExportShapeComparisonResultSchema);
13
18
  const HASH = "0".repeat(64);
14
19
  const NODE_PREPARATION_EXAMPLE = jsonObjectSchema.parse({
15
20
  preparation_approved: true,
@@ -77,9 +82,9 @@ export const APPLICATION_TOOL_CONTRACTS = [
77
82
  {
78
83
  name: "trace_application_feature",
79
84
  ...toolContractMetadata("trace_application_feature"),
80
- description: "Trace a typed literal seed through an authenticated JavaScript Application Graph with explicit direction, depth, node, edge, and path bounds. Original static, native, passive-runtime, inferred, and unknown authorities remain distinct; native addon handoffs never open a provider or execute the application.",
85
+ description: "Trace a typed literal seed through an authenticated JavaScript Application Graph supplied as full Evidence or an Evidence ID returned earlier in this session. Explicit direction, depth, node, edge, and path bounds apply. Original static, native, passive-runtime, inferred, and unknown authorities remain distinct; native addon handoffs never open a provider or execute the application.",
81
86
  kind: "application",
82
- inputSchema: traceApplicationFeatureInputSchema,
87
+ inputSchema: traceApplicationFeatureRequestSchema,
83
88
  outputSchema: traceOutputSchema,
84
89
  examples: [
85
90
  {
@@ -88,12 +93,33 @@ export const APPLICATION_TOOL_CONTRACTS = [
88
93
  },
89
94
  ],
90
95
  },
96
+ {
97
+ name: "trace_javascript_semantics",
98
+ ...toolContractMetadata("trace_javascript_semantics"),
99
+ description: "Trace bounded static JavaScript data-flow, direct call/return, and closure relations from authenticated analyze_javascript_application v2 Evidence. Queries declare direction and exact node, relation, depth, function, module, and page limits. Dynamic or unsupported semantics remain explicit unknowns; static reachability never claims runtime execution.",
100
+ kind: "application",
101
+ inputSchema: traceJavaScriptSemanticsRequestSchema,
102
+ outputSchema: semanticTraceOutputSchema,
103
+ examples: [
104
+ {
105
+ title: "Trace backward provenance from one semantic node",
106
+ input: {
107
+ application_evidence_id: `ev_${HASH}`,
108
+ query: {
109
+ seed: { kind: "semantic-node", node_id: `jsrg_node_${HASH}` },
110
+ direction: "backward-provenance",
111
+ source_map_authority: { authority: "none" },
112
+ },
113
+ },
114
+ },
115
+ ],
116
+ },
91
117
  {
92
118
  name: "compare_application_versions",
93
119
  ...toolContractMetadata("compare_application_versions"),
94
- description: "Compare two authenticated JavaScript Application Graph versions using unique-only exact digest, module source digest, source-map identity, structural fingerprint, and non-module semantic-key tiers. Reports added, removed, changed, ambiguous, and unknown entities plus a bounded changed_from graph without fuzzy or module-ordinal pairing.",
120
+ description: "Compare two authenticated JavaScript Application Graph versions supplied as full Evidence or Evidence IDs returned earlier in this session. Uses unique-only exact digest, module source digest, source-map identity, structural fingerprint, and non-module semantic-key tiers. Reports added, removed, changed, ambiguous, and unknown entities plus a bounded changed_from graph without fuzzy or module-ordinal pairing.",
95
121
  kind: "application",
96
- inputSchema: compareApplicationVersionsInputSchema,
122
+ inputSchema: compareApplicationVersionsRequestSchema,
97
123
  outputSchema: comparisonOutputSchema,
98
124
  examples: [
99
125
  {
@@ -102,6 +128,20 @@ export const APPLICATION_TOOL_CONTRACTS = [
102
128
  },
103
129
  ],
104
130
  },
131
+ {
132
+ name: "compare_javascript_export_shapes",
133
+ ...toolContractMetadata("compare_javascript_export_shapes"),
134
+ description: "Compare bounded static return shapes for one exact module/export selector on each authenticated JavaScript Application Graph, supplied as full Evidence or session Evidence IDs. Variants pair only by reciprocal unique literal discriminants; dynamic values, incomplete properties, and ambiguous variants remain unknown. Reports JSON Pointer changes and recommends controlled replay separately without executing JavaScript.",
135
+ kind: "application",
136
+ inputSchema: compareJavaScriptExportShapesRequestSchema,
137
+ outputSchema: exportShapeComparisonOutputSchema,
138
+ examples: [
139
+ {
140
+ title: "Compare one exact parser export without execution",
141
+ input: JAVASCRIPT_EXPORT_SHAPE_COMPARISON_EXAMPLE,
142
+ },
143
+ ],
144
+ },
105
145
  {
106
146
  name: "run_controlled_replay",
107
147
  ...toolContractMetadata("run_controlled_replay"),
@@ -223,3 +263,10 @@ export const APPLICATION_TOOL_CONTRACTS = [
223
263
  ],
224
264
  },
225
265
  ];
266
+ /** Resolve one named application contract without relying on array position. */
267
+ export const applicationToolContract = (name) => {
268
+ const contract = APPLICATION_TOOL_CONTRACTS.find(({ name: candidate }) => candidate === name);
269
+ if (contract === undefined)
270
+ throw new Error(`Missing application tool contract: ${name}`);
271
+ return contract;
272
+ };