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
@@ -2,7 +2,15 @@ import { mkdir, readFile, rm } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import writeFileAtomic from "write-file-atomic";
4
4
  import { PRODUCT_IDENTITY } from "../identity.js";
5
- const skillDestination = (home, name) => join(home, ".agents/skills", name, "SKILL.md");
5
+ const SKILL_FILES = [
6
+ "SKILL.md",
7
+ "references/native-and-artifacts.md",
8
+ "references/javascript-applications.md",
9
+ "references/runtime-observation.md",
10
+ "references/evidence-workflows.md",
11
+ "references/controlled-replay.md",
12
+ ];
13
+ const skillRoot = (home) => join(home, ".agents/skills", PRODUCT_IDENTITY.skillName);
6
14
  const readOptionalText = async (path) => {
7
15
  try {
8
16
  return await readFile(path, "utf8");
@@ -13,62 +21,58 @@ const readOptionalText = async (path) => {
13
21
  throw cause;
14
22
  }
15
23
  };
16
- const canonicalSkillFiles = async (home) => ({
17
- destination: skillDestination(home, PRODUCT_IDENTITY.skillName),
18
- content: await readFile(new URL(`../../skills/${PRODUCT_IDENTITY.skillName}/SKILL.md`, import.meta.url), "utf8"),
19
- });
20
- /** Report whether setup would change the managed REA skill. */
24
+ const canonicalSkillFiles = async (home) => Promise.all(SKILL_FILES.map(async (relativePath) => {
25
+ const destination = join(skillRoot(home), relativePath);
26
+ return {
27
+ destination,
28
+ content: await readFile(new URL(`../../skills/${PRODUCT_IDENTITY.skillName}/${relativePath}`, import.meta.url), "utf8"),
29
+ original: await readOptionalText(destination),
30
+ };
31
+ }));
32
+ /** Report whether setup would change any file in the managed REA skill bundle. */
21
33
  export const canonicalSkillNeedsInstall = async (home) => {
22
34
  try {
23
- const { content, destination } = await canonicalSkillFiles(home);
24
- return (await readOptionalText(destination)) !== content;
35
+ return (await canonicalSkillFiles(home)).some(({ content, original }) => original !== content);
25
36
  }
26
37
  catch {
27
38
  return true;
28
39
  }
29
40
  };
30
- /** Transactionally install or upgrade the versioned canonical REA skill. */
41
+ const writeText = (path, content) => writeFileAtomic(path, content, { encoding: "utf8", mode: 0o600 });
42
+ const restoreSkillFiles = async (changed) => {
43
+ for (const { destination, original } of [...changed].reverse()) {
44
+ if (original === undefined)
45
+ await rm(destination, { force: true });
46
+ else
47
+ await writeText(destination, original);
48
+ }
49
+ };
50
+ /** Transactionally install or upgrade the canonical REA skill and references. */
31
51
  export const installCanonicalSkill = async (home) => {
32
- let destination = skillDestination(home, PRODUCT_IDENTITY.skillName);
33
- let backup = `${destination}.rea.backup`;
34
- let original;
35
- let canonicalChanged = false;
52
+ let changed = [];
36
53
  try {
37
54
  const canonical = await canonicalSkillFiles(home);
38
- destination = canonical.destination;
39
- backup = `${destination}.rea.backup`;
40
- const { content } = canonical;
41
- original = await readOptionalText(destination);
42
- if (original === content)
55
+ changed = canonical.filter(({ content, original }) => original !== content);
56
+ if (changed.length === 0)
43
57
  return "unchanged";
44
- await mkdir(dirname(destination), { recursive: true });
45
- if (original !== undefined && original !== content)
46
- await writeFileAtomic(backup, original, {
47
- encoding: "utf8",
48
- mode: 0o600,
49
- });
50
- canonicalChanged = original !== content;
51
- if (canonicalChanged)
52
- await writeFileAtomic(destination, content, {
53
- encoding: "utf8",
54
- mode: 0o600,
55
- });
56
- if ((await readFile(destination, "utf8")) !== content)
57
- throw new Error("skill readback mismatch");
58
+ for (const { destination, original } of changed) {
59
+ await mkdir(dirname(destination), { recursive: true });
60
+ if (original !== undefined)
61
+ await writeText(`${destination}.rea.backup`, original);
62
+ }
63
+ for (const { destination, content } of changed)
64
+ await writeText(destination, content);
65
+ for (const { destination, content } of changed)
66
+ if ((await readFile(destination, "utf8")) !== content)
67
+ throw new Error(`skill readback mismatch: ${destination}`);
58
68
  return "installed";
59
69
  }
60
70
  catch {
61
71
  try {
62
- if (canonicalChanged && original === undefined)
63
- await rm(destination, { force: true });
64
- else if (canonicalChanged && original !== undefined)
65
- await writeFileAtomic(destination, original, {
66
- encoding: "utf8",
67
- mode: 0o600,
68
- });
72
+ await restoreSkillFiles(changed);
69
73
  }
70
74
  catch {
71
- // The canonical backup remains beside the skill for operator recovery.
75
+ // Per-file backups remain beside changed files for operator recovery.
72
76
  }
73
77
  return "failed";
74
78
  }
@@ -77,8 +77,9 @@ export class TerminalRenderer {
77
77
  return;
78
78
  }
79
79
  this.#capturedBytes += bytes;
80
+ const sequence = this.#frames.length;
80
81
  this.#frames.push({
81
- sequence: this.#frames.length,
82
+ sequence,
82
83
  at_ms: atMs,
83
84
  columns: this.#terminal.cols,
84
85
  rows: this.#terminal.rows,
@@ -88,5 +89,6 @@ export class TerminalRenderer {
88
89
  lines,
89
90
  serialized_state: serializedState,
90
91
  });
92
+ this.options.recordEvent?.("rendered_frames", sequence);
91
93
  }
92
94
  }
@@ -128,7 +128,13 @@ const isOwnedRegistration = (value) => {
128
128
  args[0] === "mcp") ||
129
129
  (command === "npx" &&
130
130
  (JSON.stringify(args) ===
131
- JSON.stringify(["-y", PRODUCT_IDENTITY.packageSpecifier, "mcp"]) ||
131
+ JSON.stringify([
132
+ "-y",
133
+ PRODUCT_IDENTITY.registrationPackageSpecifier,
134
+ "mcp",
135
+ ]) ||
136
+ JSON.stringify(args) ===
137
+ JSON.stringify(["-y", PRODUCT_IDENTITY.packageSpecifier, "mcp"]) ||
132
138
  JSON.stringify(args) ===
133
139
  JSON.stringify(["-y", PRODUCT_IDENTITY.packageName, "mcp"]))));
134
140
  };
@@ -9,6 +9,7 @@ import { PRODUCT_IDENTITY } from "../identity.js";
9
9
  const execFileAsync = promisify(execFile);
10
10
  const registryResponseSchema = z.object({ version: z.string().min(1) });
11
11
  const UPGRADE_COMMAND = "npm install --global rea-agents@latest";
12
+ const CLI_SCRIPT_PATH = fileURLToPath(new URL("../../scripts/rea.mjs", import.meta.url));
12
13
  /** Check the npm registry and update the same global REA installation. */
13
14
  export const runUpgrade = async (currentVersion, host = systemUpgradeHost(), output = "human") => {
14
15
  const latestVersion = await host.latestVersion();
@@ -46,6 +47,12 @@ export const runUpgrade = async (currentVersion, host = systemUpgradeHost(), out
46
47
  reason: "install",
47
48
  remediation: `REA could not update through npm. Check npm registry access and global install permissions, then run: ${UPGRADE_COMMAND}`,
48
49
  };
50
+ const integrationSyncResult = await host.syncAgentIntegration(output);
51
+ const integrationSync = integrationSyncResult === undefined
52
+ ? "deferred"
53
+ : integrationSyncResult
54
+ ? "setup_invoked"
55
+ : "failed";
49
56
  return {
50
57
  status: "upgraded",
51
58
  previousVersion: currentVersion,
@@ -53,8 +60,11 @@ export const runUpgrade = async (currentVersion, host = systemUpgradeHost(), out
53
60
  versionCheck: "available",
54
61
  installMethod: "npm",
55
62
  command: UPGRADE_COMMAND,
63
+ integrationSync,
56
64
  clientRestartRequired: true,
57
- remediation: "Rerun rea setup to refresh registrations and the skill, then restart clients that may retain an older MCP server.",
65
+ remediation: integrationSync === "setup_invoked"
66
+ ? "The updated setup journey was opened to align registrations and the skill. Restart clients whose approved registration changed."
67
+ : "Run rea setup --all-detected to align registrations and the skill, then restart clients that may retain an older MCP server.",
58
68
  };
59
69
  };
60
70
  /** Create the npm registry and subprocess effects for a production upgrade. */
@@ -79,6 +89,11 @@ export const systemUpgradeHost = () => ({
79
89
  prefix,
80
90
  `${PRODUCT_IDENTITY.packageName}@latest`,
81
91
  ], output),
92
+ syncAgentIntegration: (output) => output === "structured" ||
93
+ process.stdin.isTTY !== true ||
94
+ process.stderr.isTTY !== true
95
+ ? Promise.resolve(undefined)
96
+ : runCommand(process.execPath, [CLI_SCRIPT_PATH, "setup", "--all-detected"], "human"),
82
97
  });
83
98
  const systemNpmInstallationHost = {
84
99
  canonicalPath: realpath,
@@ -40,25 +40,58 @@ export const discoverCdpEndpoint = async (endpoint, operation, signal) => {
40
40
  targets: targets.map((target) => ({
41
41
  id: target.id,
42
42
  type: target.type,
43
- title: sanitizeTargetTitle(target.title),
43
+ title: sanitizeTargetTitle(target.title, target.url),
44
44
  url: target.url,
45
45
  attached: target.attached,
46
46
  ...targetWebSocket(endpoint, target, operation),
47
47
  })),
48
48
  };
49
49
  };
50
- const sanitizeTargetTitle = (value) => {
50
+ const sanitizeTargetTitle = (value, targetUrl) => {
51
51
  let url;
52
52
  try {
53
53
  url = new URL(value);
54
54
  }
55
55
  catch {
56
- return value;
56
+ return sanitizeTargetUrlAlias(value, targetUrl);
57
57
  }
58
58
  return url.protocol === "http:" || url.protocol === "https:"
59
59
  ? sanitizeBrowserUrl(value).url.slice(0, 16_384)
60
- : value;
60
+ : sanitizeTargetUrlAlias(value, targetUrl);
61
+ };
62
+ const sanitizeTargetUrlAlias = (value, targetUrl) => {
63
+ let parsed;
64
+ try {
65
+ parsed = new URL(targetUrl);
66
+ }
67
+ catch {
68
+ return value;
69
+ }
70
+ const markers = [parsed.origin, `//${parsed.host}`, parsed.host];
71
+ if (parsed.pathname !== "/")
72
+ markers.push(parsed.pathname);
73
+ const candidatePattern = new RegExp(`(?:${markers.map(escapeRegExp).join("|")})[^\\s<>"']*`, "gu");
74
+ return value
75
+ .replace(candidatePattern, (candidate) => sanitizeSameOriginTitleUrl(candidate, parsed))
76
+ .slice(0, 16_384);
77
+ };
78
+ const sanitizeSameOriginTitleUrl = (candidate, target) => {
79
+ let parsed;
80
+ try {
81
+ parsed = candidate.startsWith("//")
82
+ ? new URL(`${target.protocol}${candidate}`)
83
+ : candidate.startsWith(target.host)
84
+ ? new URL(`${target.protocol}//${candidate}`)
85
+ : new URL(candidate, target.origin);
86
+ }
87
+ catch {
88
+ return candidate;
89
+ }
90
+ return parsed.origin === target.origin && parsed.search !== ""
91
+ ? sanitizeBrowserUrl(parsed.href).url
92
+ : candidate;
61
93
  };
94
+ const escapeRegExp = (value) => value.replaceAll(/[.*+?^${}()|[\]\\]/gu, "\\$&");
62
95
  /** Select a browser attachment socket or a direct socket for one page target. */
63
96
  export const cdpTargetWebSocket = (discovery, target, operation) => {
64
97
  const webSocket = availableCdpTargetWebSocket(discovery, target);
@@ -26,11 +26,13 @@ const promptCatalog = PROMPT_CONTRACTS.map((contract) => ({
26
26
  arguments: contract.arguments,
27
27
  steps: contract.steps,
28
28
  })).sort((left, right) => left.name.localeCompare(right.name));
29
- const resourceCatalog = [
29
+ /** Canonical fixed resources exposed by every target-free MCP session. */
30
+ export const MCP_RESOURCE_CATALOG = [
30
31
  { name: "server-identity", uri: "rea://server/identity" },
31
32
  { name: "active-residual-unknowns", uri: "rea://unknowns/active" },
32
33
  ];
33
- const resourceTemplateCatalog = [
34
+ /** Canonical resource templates exposed by every target-free MCP session. */
35
+ export const MCP_RESOURCE_TEMPLATE_CATALOG = [
34
36
  { name: "session-evidence", uri_template: "rea://evidence/{evidenceId}" },
35
37
  {
36
38
  name: "evidence-section",
@@ -57,6 +59,10 @@ const resourceTemplateCatalog = [
57
59
  name: "reconstruction-coverage-revision",
58
60
  uri_template: "rea://reconstruction-coverage/{workspaceId}/revision/{revision}",
59
61
  },
62
+ {
63
+ name: "javascript-application-graph-page",
64
+ uri_template: "rea://evidence/{evidenceId}/application-graph/{collection}/offset/{offset}/limit/{limit}",
65
+ },
60
66
  ];
61
67
  const digest = (value) => {
62
68
  const encoded = canonicalize(value);
@@ -70,19 +76,22 @@ export const CATALOG_IDENTITY = {
70
76
  cli_commands: CLI_COMMAND_NAMES.length,
71
77
  mcp_tools: toolCatalog.length,
72
78
  mcp_prompts: promptCatalog.length,
73
- mcp_resources: resourceCatalog.length,
74
- mcp_resource_templates: resourceTemplateCatalog.length,
79
+ mcp_resources: MCP_RESOURCE_CATALOG.length,
80
+ mcp_resource_templates: MCP_RESOURCE_TEMPLATE_CATALOG.length,
75
81
  },
76
82
  digests: {
77
83
  tools_sha256: digest(toolCatalog),
78
84
  prompts_sha256: digest(promptCatalog),
79
- resources_sha256: digest({ resourceCatalog, resourceTemplateCatalog }),
85
+ resources_sha256: digest({
86
+ resourceCatalog: MCP_RESOURCE_CATALOG,
87
+ resourceTemplateCatalog: MCP_RESOURCE_TEMPLATE_CATALOG,
88
+ }),
80
89
  combined_sha256: digest({
81
90
  cli: CLI_COMMAND_NAMES,
82
91
  tools: toolCatalog,
83
92
  prompts: promptCatalog,
84
- resources: resourceCatalog,
85
- resource_templates: resourceTemplateCatalog,
93
+ resources: MCP_RESOURCE_CATALOG,
94
+ resource_templates: MCP_RESOURCE_TEMPLATE_CATALOG,
86
95
  }),
87
96
  },
88
97
  tools: toolCatalog.map(({ name, surface, effects, annotations }) => ({
@@ -1,8 +1,11 @@
1
1
  import { z } from "incur";
2
+ import { stat } from "node:fs/promises";
3
+ import { resolve } from "node:path";
2
4
  import { runDirectAnalysis } from "../application/DirectAnalysis.js";
3
5
  import { CLI_COMMANDS } from "../cliCommandNames.js";
4
6
  import { logCliCommand } from "../cliLogging.js";
5
7
  import { directAnalysisOptions, providerSelectionOption } from "./options.js";
8
+ import { runCliJavaScriptApplicationAnalysis } from "./javascriptApplicationAnalysis.js";
6
9
  export const registerCoreAnalysisCommands = (cli, logger) => {
7
10
  registerCoreCommands(cli, logger);
8
11
  registerFunctionCommand(cli, logger);
@@ -30,13 +33,19 @@ const registerCoreCommands = (cli, logger) => {
30
33
  .describe("Load and update a local analysis snapshot"),
31
34
  provider: providerSelectionOption,
32
35
  });
36
+ const analyzeOptions = overviewOptions.extend({
37
+ approved: z
38
+ .boolean()
39
+ .default(false)
40
+ .describe("Approve static analysis when the path is a JavaScript directory or ASAR"),
41
+ });
33
42
  cli.command(CLI_COMMANDS.analyze, {
34
43
  description: "Get an overview of an app",
35
44
  args: z.object({
36
45
  path: z.string().describe("App, program, or analysis database path"),
37
46
  }),
38
- options: overviewOptions,
39
- run: ({ args, options }) => logCliCommand(logger, "analyze", () => runDirectAnalysis(args.path, "binary_overview", { detail: options.detail, limit: options.limit }, directAnalysisOptions(logger, options.snapshot, options.provider))),
47
+ options: analyzeOptions,
48
+ run: ({ args, options }) => logCliCommand(logger, "analyze", () => runRoutedOverview(args.path, options, logger)),
40
49
  });
41
50
  cli.command(CLI_COMMANDS.inspect, {
42
51
  description: "Inspect an app overview with evidence",
@@ -63,6 +72,29 @@ const registerCoreCommands = (cli, logger) => {
63
72
  run: ({ args, options }) => logCliCommand(logger, "decompile", () => runDirectAnalysis(args.path, "procedure_pseudo_code", { procedure: args.address }, directAnalysisOptions(logger, options.snapshot, options.provider))),
64
73
  });
65
74
  };
75
+ const runRoutedOverview = async (path, options, logger) => {
76
+ if (options.provider === undefined &&
77
+ options.snapshot === undefined &&
78
+ (await isJavaScriptApplicationPath(path)))
79
+ return runCliJavaScriptApplicationAnalysis({
80
+ input_path: resolve(path),
81
+ approved: options.approved,
82
+ });
83
+ return runDirectAnalysis(path, "binary_overview", { detail: options.detail, limit: options.limit }, directAnalysisOptions(logger, options.snapshot, options.provider));
84
+ };
85
+ const isJavaScriptApplicationPath = async (path) => {
86
+ const lower = path.toLowerCase();
87
+ if (lower.endsWith(".asar"))
88
+ return true;
89
+ if (lower.endsWith(".app"))
90
+ return false;
91
+ try {
92
+ return (await stat(path)).isDirectory();
93
+ }
94
+ catch {
95
+ return false;
96
+ }
97
+ };
66
98
  const registerXrefsCommand = (cli, logger) => {
67
99
  cli.command(CLI_COMMANDS.xrefs, {
68
100
  description: "List bounded references to an analyzed address",
@@ -0,0 +1,19 @@
1
+ import { analyzeJavaScriptApplication } from "../application/JavaScriptApplicationService.js";
2
+ import { loadConfiguredPermissionAuthority } from "../application/PermissionConfiguration.js";
3
+ import { parseConfig } from "../config.js";
4
+ import { projectAnalysisError } from "../domain/errors.js";
5
+ /** Execute the shared one-shot CLI boundary for static JavaScript analysis. */
6
+ export const runCliJavaScriptApplicationAnalysis = async (input) => {
7
+ const config = parseConfig(process.env);
8
+ if (!config.ok)
9
+ return cliError(config.error);
10
+ const authority = await loadConfiguredPermissionAuthority(config.value);
11
+ if (!authority.ok)
12
+ return cliError(authority.error);
13
+ const result = await analyzeJavaScriptApplication(authority.value, input);
14
+ return result.ok ? result.value : cliError(result.error);
15
+ };
16
+ const cliError = (error) => ({
17
+ error: "JavaScript application analysis failed",
18
+ ...projectAnalysisError(error),
19
+ });
@@ -1,6 +1,6 @@
1
1
  import { z } from "incur";
2
- import { runDoctor } from "../application/Doctor.js";
3
- import { runSetup, systemSetupHost } from "../application/Setup.js";
2
+ import { DOCTOR_PROVIDER_IDS, runDoctor, } from "../application/Doctor.js";
3
+ import { runSetup, systemSetupHost, } from "../application/Setup.js";
4
4
  import { runUninstall } from "../application/Uninstall.js";
5
5
  import { runUpgrade, systemUpgradeHost } from "../application/Upgrade.js";
6
6
  import { conciseSetupResult, confirmInteractiveSetup, renderInteractiveSetupResult, renderSetupProgress, } from "../cliSetup.js";
@@ -8,7 +8,19 @@ import { PRODUCT_IDENTITY } from "../identity.js";
8
8
  import { logCliCommand } from "../cliLogging.js";
9
9
  import { createSystemDoctorHost } from "../doctorRuntime.js";
10
10
  import { CLI_COMMANDS } from "../cliCommandNames.js";
11
+ import { SUPPORTED_CLIENT_DEFINITIONS } from "../application/SupportedClients.js";
12
+ import { projectDoctorReport } from "../application/DoctorProjection.js";
13
+ const supportedClientIds = SUPPORTED_CLIENT_DEFINITIONS.map(({ name }) => name);
14
+ const supportedClientSchema = z
15
+ .string()
16
+ .refine((candidate) => supportedClientIds.some((name) => name === candidate), "Unsupported agent integration");
17
+ /** Register setup, doctor, uninstall, and upgrade CLI commands. */
11
18
  export const registerSetupCommands = (cli, logger) => {
19
+ registerSetupCommand(cli, logger);
20
+ registerDoctorCommand(cli, logger);
21
+ registerMaintenanceCommands(cli, logger);
22
+ };
23
+ const registerSetupCommand = (cli, logger) => {
12
24
  cli.command(CLI_COMMANDS.setup, {
13
25
  description: "Install requirements and configure agents",
14
26
  outputPolicy: "agent-only",
@@ -22,14 +34,7 @@ export const registerSetupCommands = (cli, logger) => {
22
34
  .default(false)
23
35
  .describe("Also approve Hopper installation with --yes"),
24
36
  client: z
25
- .array(z.enum([
26
- "claude_code",
27
- "claude_desktop",
28
- "codex",
29
- "cursor",
30
- "gemini_cli",
31
- "windsurf",
32
- ]))
37
+ .array(supportedClientSchema)
33
38
  .default([])
34
39
  .describe("Agent integration to configure; repeat for multiple agents"),
35
40
  allDetected: z
@@ -39,7 +44,7 @@ export const registerSetupCommands = (cli, logger) => {
39
44
  skill: z
40
45
  .boolean()
41
46
  .optional()
42
- .describe("Install or skip the bundled REA skill"),
47
+ .describe("Override the bundled skill included with agent integrations"),
43
48
  dryRun: z
44
49
  .boolean()
45
50
  .default(false)
@@ -48,17 +53,41 @@ export const registerSetupCommands = (cli, logger) => {
48
53
  .boolean()
49
54
  .default(false)
50
55
  .describe("Use sequential accessible setup prompts"),
56
+ detail: z
57
+ .enum(["summary", "full"])
58
+ .default("summary")
59
+ .describe("Summary or complete setup and doctor diagnostics"),
51
60
  }),
52
61
  alias: { yes: "y" },
53
- run: ({ options, formatExplicit, agent }) => logCliCommand(logger, "setup", () => runSetupCommand({ options, formatExplicit, agent })),
62
+ run: ({ options, formatExplicit }) => logCliCommand(logger, "setup", () => runSetupCommand({ options, formatExplicit })),
54
63
  });
64
+ };
65
+ const registerDoctorCommand = (cli, logger) => {
55
66
  cli.command(CLI_COMMANDS.doctor, {
56
67
  description: "Check whether REA is ready",
57
68
  options: z.object({
58
69
  target: z.string().optional().describe("Optional app path to check"),
70
+ client: z
71
+ .array(supportedClientSchema)
72
+ .default([])
73
+ .describe("Agent registration whose readiness is required; repeatable"),
74
+ provider: z
75
+ .array(z.enum(DOCTOR_PROVIDER_IDS))
76
+ .default([])
77
+ .describe("Deep-analysis provider whose readiness is required"),
78
+ skill: z
79
+ .boolean()
80
+ .optional()
81
+ .describe("Require the installed REA skill identity to be aligned"),
82
+ detail: z
83
+ .enum(["summary", "full"])
84
+ .default("summary")
85
+ .describe("Summary or complete doctor diagnostics"),
59
86
  }),
60
- run: ({ options }) => logCliCommand(logger, "doctor", () => runDoctor(options.target, createSystemDoctorHost())),
87
+ run: ({ options }) => logCliCommand(logger, "doctor", () => runDoctor(options.target, createSystemDoctorHost(), doctorScope(options)).then((report) => projectDoctorReport(report, options.detail))),
61
88
  });
89
+ };
90
+ const registerMaintenanceCommands = (cli, logger) => {
62
91
  cli.command(CLI_COMMANDS.uninstall, {
63
92
  description: "Remove REA-owned agent configuration and skill files",
64
93
  options: z.object({
@@ -77,32 +106,57 @@ export const registerSetupCommands = (cli, logger) => {
77
106
  };
78
107
  const runSetupCommand = async (input) => {
79
108
  const { options } = input;
80
- const interactive = !options.yes &&
81
- !options.dryRun &&
82
- !input.formatExplicit &&
83
- process.stdin.isTTY === true &&
84
- process.stderr.isTTY === true;
109
+ const interactive = setupIsInteractive(options, input.formatExplicit);
85
110
  const hasExplicitScope = setupHasExplicitScope(options);
86
111
  if (options.yes && !hasExplicitScope)
87
- process.stderr.write("! Implicit `rea setup --yes` scope is deprecated; use `--all-detected --skill` to retain it.\n");
88
- const result = await runSetup({
112
+ process.stderr.write("! Implicit `rea setup --yes` scope is deprecated; use `--all-detected` to retain it.\n");
113
+ const result = await runSetup(setupRunOptions(input, interactive, hasExplicitScope), systemSetupHost(createSystemDoctorHost()), interactive
114
+ ? (actions) => confirmInteractiveSetup(actions, options.accessible)
115
+ : undefined);
116
+ if (interactive)
117
+ renderInteractiveSetupResult(result);
118
+ return options.detail === "full" ? result : conciseSetupResult(result);
119
+ };
120
+ const setupRunOptions = (input, interactive, hasExplicitScope) => {
121
+ const { options } = input;
122
+ const agentIntegrationSelected = options.allDetected || options.client.length > 0;
123
+ const hasSelectedClients = hasExplicitScope && !options.allDetected;
124
+ return {
89
125
  approved: options.yes && !options.dryRun,
90
126
  installHopper: options.installHopper,
91
127
  structured: input.formatExplicit || options.dryRun,
92
128
  proposeHopper: !hasExplicitScope || options.installHopper,
93
- ...(!hasExplicitScope || options.allDetected
94
- ? {}
95
- : { clientIds: options.client }),
96
- ...(!hasExplicitScope ? {} : { installSkill: options.skill ?? false }),
129
+ ...(hasSelectedClients ? { clientIds: options.client } : {}),
130
+ ...(hasExplicitScope
131
+ ? { installSkill: options.skill ?? agentIntegrationSelected }
132
+ : {}),
97
133
  ...(interactive ? { onProgress: renderSetupProgress } : {}),
98
- }, systemSetupHost(createSystemDoctorHost()), interactive
99
- ? (actions) => confirmInteractiveSetup(actions, options.accessible)
100
- : undefined);
101
- if (interactive)
102
- renderInteractiveSetupResult(result);
103
- return input.formatExplicit ? result : conciseSetupResult(result);
134
+ ...(hasSelectedClients
135
+ ? {
136
+ readinessScope: {
137
+ clients: options.client,
138
+ providers: options.installHopper ? ["hopper"] : [],
139
+ skill: options.skill ?? agentIntegrationSelected,
140
+ },
141
+ }
142
+ : {}),
143
+ };
104
144
  };
145
+ const setupIsInteractive = (options, formatExplicit) => !options.yes &&
146
+ !options.dryRun &&
147
+ !formatExplicit &&
148
+ process.stdin.isTTY === true &&
149
+ process.stderr.isTTY === true;
105
150
  const setupHasExplicitScope = (options) => options.allDetected ||
106
151
  options.client.length > 0 ||
107
152
  options.skill !== undefined ||
108
153
  options.installHopper;
154
+ const doctorScope = (options) => options.client.length === 0 &&
155
+ options.provider.length === 0 &&
156
+ options.skill === undefined
157
+ ? undefined
158
+ : {
159
+ clients: options.client,
160
+ providers: options.provider,
161
+ skill: options.skill === true,
162
+ };
@@ -1,5 +1,5 @@
1
1
  import { z } from "incur";
2
- import { runProviderAnalysis, runSessionStatus, } from "../application/DirectAnalysis.js";
2
+ import { runCapabilityStatus, runProviderAnalysis, runProviderStatus, } from "../application/DirectAnalysis.js";
3
3
  import { importReferenceSource } from "../application/ReferenceSourceImport.js";
4
4
  import { projectReferenceSourceImportError } from "../application/ReferenceSourceImportTypes.js";
5
5
  import { loadConfiguredPermissionAuthority } from "../application/PermissionConfiguration.js";
@@ -22,7 +22,15 @@ const registerCapabilityCommands = (cli, logger) => {
22
22
  description: command === "capabilities"
23
23
  ? "List provider capabilities and side effects"
24
24
  : "List configured analysis providers",
25
- run: () => logCliCommand(logger, command, () => runSessionStatus(logger)),
25
+ options: z.object({
26
+ detail: z
27
+ .enum(["summary", "full"])
28
+ .default("summary")
29
+ .describe("Summary or complete provider descriptors"),
30
+ }),
31
+ run: ({ options }) => logCliCommand(logger, command, () => command === CLI_COMMANDS.providers
32
+ ? runProviderStatus(logger, options.detail)
33
+ : runCapabilityStatus(logger, options.detail)),
26
34
  });
27
35
  }
28
36
  };