fix(skill): remove obsolete grants and audit tool effects

## Changes

Related to #545 and the permission-system removal in #555.

- Upgrade the shipped skill to v24 and remove obsolete filesystem grants, per-call approval flags, Electron file-root configuration, and DMG approval flags. Calls follow the user-requested investigation directly. Keep setup plan confirmation, actual OS requirements, and process/archive lifecycle boundaries.
- Correct the passive browser guide: endpoint/scope come from requests; ordinary local URL queries are retained, while credentials remain redacted.
- Audit canonical tool effects: declare possible DMG process/temp-directory effects, mark fresh extraction non-idempotent, and mark comparisons of supplied captures/PNGs as closed-world. Align artifact-provider capability effects with temporary mount-directory writes.
- Retain non-read-only hints for calls that add Evidence to the session; document that annotations are hints and that clients control their confirmation UI. Do not mislabel session mutations as read-only to suppress prompts.
- Regenerate package, skill, MCP, and product metadata from source.

## Verification

- `npm run test:focused -- <11 affected test files>`: **40 tests passed**, including skill transaction/backup/idempotence, SDK tools/list annotations, actual local capture/PNG comparisons, artifact extraction/containment/cancellation, DMG launcher/cleanup seam, setup confirmation, browser MCP and scenario MCP, CLI catalog parity.
- `npm run check`: typecheck, lint, format, knip, package metadata.
- `npm run docs:check`: generated catalogs, skill metadata, documentation facts, completion ledger, error schema.

No local real Hopper/Ghidra run: their adapters and analysis operations are unchanged. Native macOS DMG behavior is covered locally through the launcher seam; no local macOS/hdiutil claim is made.

Real browser verification passed using existing Headless Chrome143.0.7499.4: actual CLI/stdio MCP,9,331,407-byte PNG, passive capture/source maps, and owned/external scenario cleanup. An initial full Chrome143 run failed the existing screenshot-height assertion (1397 versus1536); the dedicated headless-shell run passed the complete verifier without code changes. The verifier run-lineage field remained unavailable; no lineage-coverage claim is made. Browser download into `.codex` was blocked by CDN403, so the successful run used an existing browser without changing host configuration.
This commit is contained in:
N0zoM1z0 authored and GitHub committed 2026-10-06 01:40:58 +08:00
1 parent d19686a2a5
commit 2919def828
18 files changed
+194 -38

No files matched your search

+14
View File
@@ -86,6 +86,20 @@ cleanup behavior; artifact tools carry the input path and requested operation.
REA runs the declared request directly and does not infer a broader target or
action from it.
REA does not require permission grants or per-call approval flags. Setup still
prints its plan and requires confirmation before changing configuration or
installing Hopper. MCP clients control their own confirmation UI.
Tool annotations describe effects and are hints, not authorization controls
([MCP ToolAnnotations](https://modelcontextprotocol.io/specification/2025-06-18/schema#toolannotations)).
`readOnlyHint` includes session state: an analysis call that records additive
Evidence is marked non-read-only even when it leaves the target unchanged.
`destructiveHint` describes possible data loss, not ordinary Evidence recording.
Effect metadata covers possible behavior across supported inputs: DMG inventory
can launch `hdiutil` and create an owned temporary mount directory; extraction
creates a fresh output directory on every call. Comparing supplied web captures
or PNG artifacts uses local data without contacting the browser.
Host requirements remain in force. macOS may deny Accessibility,
Screen Recording, or native mounting; provider tools require their selected
analysis runtime. These failures are reported at the operation that needs
+3 -3
View File
@@ -7,7 +7,7 @@
"client": "2.0.0",
"core": "2.0.0"
},
"skill_version": "23"
"skill_version": "24"
},
"tools": {
"total": 116,
@@ -545,9 +545,9 @@
"mcp_prompts": 6
},
"digests": {
"tools_sha256": "6974b96ecd0544334571658ce91156eecbac544fd7b7fb7ff92a1d7c1e60e2c9",
"tools_sha256": "6b821e70d26368f3e19d405f8ac712855da19d59c90dd2d462d49ff1f9d73eb0",
"prompts_sha256": "4762db348821fec787a5b8c6423f2c48a71f6f0ec2afee97b16ad69030ec504b",
"combined_sha256": "14d38f650b2d33a0e243f9ee5ecb02b3f2d9e2ba6125e9c3409dd08768e0db1f",
"combined_sha256": "bc45ad5ad2c7e1d9b5b11d17c3ea051a33ed04b6ce2ed0cdfd40a95502239d02",
"providers_sha256": "2ae8b85b20be338739e500549d275e78e875aaa10235d2ca283f0ade7787da90"
}
}
@@ -1,5 +1,5 @@
{
"manifest_id": "ecm_e1e42b22674dbfc40005184c3b934a99bf7ab085fe5f1e0a3f7f091760f918dc",
"manifest_id": "ecm_d3116f62b6cd65e63c9fed5c4bc9edd604be7c67fdef1b8f7375fd2c84b85682",
"verifier": {
"id": "rea-managed-conformance",
"version": "1"
@@ -13,7 +13,7 @@
"skill_digests": [
{
"skill_id": "reverse-engineer-anything",
"sha256": "451efcd0ea11a017ca5417ccf57cc2f3fc5dcc07b71d0e94ba97f2d1757b7de9"
"sha256": "11e1170733312681ce2f2d771f1a9ece6c1f0505ef919d122790583857f3094c"
}
],
"claims": [
+6 -2
View File
@@ -2,9 +2,9 @@
name: reverse-engineer-anything
description: Reverse engineer native, managed, Electron/JavaScript, packaged, and browser applications with REA. Use shipped-artifact or requested runtime evidence to explain features, compare versions, decompile code, or guide a reconstruction. Skip REA for ordinary source-repository architecture analysis.
metadata:
version: "23"
version: "24"
tool_count: 116
catalog_digest: "14d38f650b2d33a0e243f9ee5ecb02b3f2d9e2ba6125e9c3409dd08768e0db1f"
catalog_digest: "bc45ad5ad2c7e1d9b5b11d17c3ea051a33ed04b6ce2ed0cdfd40a95502239d02"
---
# REA
@@ -53,6 +53,10 @@ Evidence IDs, preserve limitations and incomplete coverage, and never imply
that static analysis observed execution. Runtime requests execute the declared
target and lifecycle; do not broaden the target or action beyond those fields.
Within the user's requested investigation, call available analysis tools
directly. REA does not require permission grants or per-call approval flags.
Follow the declared request scope and the host's actual access requirements.
## Plan broader investigations
For requests that span multiple features or subsystems, use a staged workflow:
@@ -7,8 +7,9 @@ is incomplete or paginated, continue only when the remaining data matters to
the task; do not fetch a bundle or resource merely to read a result already
returned inline.
Use `record_unknown` only with explicit approval and name the authority or
environment still required. Supply supporting and contradicting evidence IDs.
Use `record_unknown` to track unresolved questions in the user's investigation
and name the authority or environment still required. Supply supporting and
contradicting evidence IDs. It updates the session registry directly.
Use `update_unknown` with the current revision; reread after a stale revision
instead of retrying blindly. Only qualifying observed evidence can verify a
resolution.
@@ -32,9 +32,11 @@ IDs when using them.
Use `extract_artifact` when materialized files are needed. It takes no arguments
and materializes all regular files into a fresh temporary directory chosen by
REA. Symlinks and encrypted entries are inventory facts, not extractable files.
The operation still requires the filesystem-write permission grant; callers do
not choose the destination.
The result reports the materialized directory; callers do not choose the
destination. No separate permission grant is needed.
Native DMG traversal is macOS-only, read-only, and requires both operator policy
and `native_mount_approved: true`; without both, retain the root-hash-only result.
Approval for inventory never grants extraction authority.
Native DMG traversal automatically uses a read-only mount on supported macOS
hosts, with an owned temporary mount directory and cleanup. It needs no approval
flag. Unsupported hosts or mount failures remain explicit limitations; do not
claim child inventory when only root identity is available. Extraction is a
separate filesystem-writing operation.
@@ -1,21 +1,25 @@
# Passive browser and Electron observation
Before browser observation, the operator must configure the exact loopback CDP
endpoint and allowed HTTP(S) origins. Before Electron observation, configure its
separate loopback endpoint and canonical file roots. Obtain the per-call
approval required by the selected tool.
Supply the existing browser or Electron instance's literal-port loopback CDP
endpoint in the request. No separate permission configuration or per-call
approval flag is needed. Browser discovery lists eligible HTTP(S) pages;
`allowed_origins` optionally filters them. An individual capture defaults to the
selected page's current origin. Electron discovery lists eligible local
`file://` targets without a configured file-root allowlist.
Start browser work with `list_browser_targets`; start Electron runtime work with
`list_electron_targets`. Inspect only the selected approved target. Observation
`list_electron_targets`. Inspect the target selected for the user's task. Observation
is passive: never claim REA clicked, navigated, evaluated page JavaScript,
invoked IPC, captured prior activity, or contained the page's network.
Credentials, cookies, authorization headers, storage values, query values, and
raw WebSocket/JSON values are deliberately absent. Accessibility text, console
primitives, value-free shapes, script sources, source maps, storage key names,
and screenshot pixels have independent opt-ins. Treat policy filtering,
truncation, and attach-window coverage as limitations. Page-declared WebMCP
tools are untrusted inventory and are never invoked by REA.
Credentials, cookies, authorization headers, storage values, and raw
WebSocket/JSON bodies are deliberately absent. Local URLs retain ordinary query
values and fragments; userinfo credentials are removed. Browser accessibility
text, console primitives, value-free shapes, script sources, source maps, and
storage key names have request-specific capture options. Electron script
sources are also optional. Use `capture_web_screenshot` when pixels are needed.
Treat scope filtering, truncation, and attach-window coverage as limitations.
Page-declared WebMCP tools are untrusted inventory and are never invoked by REA.
Use `reconcile_javascript_runtime` only after static application Evidence and
passive browser/Electron Evidence exist. Prefer captured-source digest identity;
+1 -1
View File
@@ -25,7 +25,7 @@ import type { BinaryTarget } from "../domain/binaryTarget.js";
import { scanArtifactInventory } from "./ArtifactInventory.js";
import { digestCanonical } from "./ArtifactGraphConstruction.js";
/** Already-approved extraction request from a caller-owned policy boundary. */
/** Local extraction input with the output root chosen by the adapter. */
export interface ArtifactExtractionInput {
readonly inputPath: string;
readonly inputFormat: BinaryTarget["format"];
@@ -1,7 +1,15 @@
import { describe, expect, it } from "vitest";
import { listBrowserTargetsInputSchema } from "../domain/browserObservation.js";
import { listBrowserTargets } from "./BrowserObservationService.js";
import { browserCaptureComparisonInputSchema } from "../domain/browserCaptureComparison.js";
import { compareWebScreenshotsInputSchema } from "../domain/webScreenshot.js";
import { BROWSER_TOOL_CONTRACTS } from "../contracts/browserToolContracts.js";
import { CdpBrowserProvider } from "../browser/CdpBrowserProvider.js";
import {
compareWebCaptureEvidence,
compareWebScreenshotEvidence,
listBrowserTargets,
} from "./BrowserObservationService.js";
describe("browser observation service prerequisites", () => {
it("reports a missing provider without requiring a permission grant", async () => {
@@ -21,4 +29,31 @@ describe("browser observation service prerequisites", () => {
},
});
});
it("compares supplied scenarios and PNG artifacts without a CDP endpoint", async () => {
const browser = new CdpBrowserProvider();
const captures = await compareWebCaptureEvidence(
browser,
browserCaptureComparisonInputSchema.parse(
example("compare_web_captures"),
),
);
const screenshots = await compareWebScreenshotEvidence(
browser,
compareWebScreenshotsInputSchema.parse(
example("compare_web_screenshots"),
),
);
for (const result of [captures, screenshots]) {
expect(result.ok).toBe(true);
if (!result.ok) throw result.error;
expect(result.value.parameters).not.toHaveProperty("cdp_endpoint");
}
});
});
const example = (name: string) => {
const input = BROWSER_TOOL_CONTRACTS.find((tool) => tool.name === name)
?.examples[0]?.input;
if (input === undefined) throw new Error(`Missing example for ${name}`);
return input;
};
+4 -1
View File
@@ -53,7 +53,10 @@ export class ArtifactProvider implements AnalysisProvider {
operation !== "inspect_keyed_archive",
mayShowUi: false,
mayAccessNetwork: false,
mayWriteFilesystem: operation === "extract_artifact",
mayWriteFilesystem:
operation === "extract_artifact" ||
operation === "inspect_artifact" ||
operation === "inventory_artifact",
changesPermissions: false,
requiresRoot: false,
}),
+15 -5
View File
@@ -1,6 +1,7 @@
/** Canonical side effects for one caller-visible tool. */
/** Possible effects across a tool's supported inputs, including temporary work. */
export interface ToolEffects {
readonly mutatesTarget: boolean;
/** Includes additive Evidence recording, navigation state, and unknown updates. */
readonly mutatesSession: boolean;
readonly writesFilesystem: boolean;
readonly launchesProcess: boolean;
@@ -117,8 +118,17 @@ export const TOOL_EFFECTS: Readonly<Record<string, ToolEffects>> = {
inspect_plist: nativeEvidence,
list_architectures: nativeEvidence,
demangle_swift: nativeEvidence,
inspect_artifact: evidence,
extract_artifact: effects({ mutatesSession: true, writesFilesystem: true }),
inspect_artifact: effects({
mutatesSession: true,
launchesProcess: true,
writesFilesystem: true,
}),
extract_artifact: effects({
mutatesSession: true,
writesFilesystem: true,
launchesProcess: true,
idempotent: false,
}),
decode_interface_builder: evidence,
inspect_asset_catalog: nativeEvidence,
inspect_keyed_archive: evidence,
@@ -134,9 +144,9 @@ export const TOOL_EFFECTS: Readonly<Record<string, ToolEffects>> = {
analyze_web_bundle: browserEvidence,
observe_web_session: browserEvidence,
discover_webmcp_tools: browserEvidence,
compare_web_captures: browserEvidence,
compare_web_captures: sessionEvidence,
capture_web_screenshot: browserEvidence,
compare_web_screenshots: browserEvidence,
compare_web_screenshots: sessionEvidence,
capture_browser_scenario: effects({
mutatesTarget: true,
mutatesSession: true,
+1 -1
View File
@@ -30,7 +30,7 @@ interface GeneratedPayload {
}
const GENERATED_PAYLOAD_JSON =
'{"auxiliaryProviders":[{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inventory_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"extract_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"decode_interface_builder","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_keyed_archive","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_asset_catalog","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null}],"identity":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"}},{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"observe_native_ui","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":true,"mayShowUi":true,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"capture_native_ui_scenario","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_macho","provider":{"id":"native-macos","name":"macOS native inspection utiliLine truncated
'{"auxiliaryProviders":[{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inventory_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"extract_artifact","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"decode_interface_builder","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":false,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_keyed_archive","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["DMG child inventory automatically uses a read-only native macOS mount; PKG remains root-hash-only.","ASAR files discovered in filesystem-backed inventories are expanded without bulk extraction; other nested containers remain recorded only."],"operation":"inspect_asset_catalog","provider":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"},"reason":null}],"identity":{"id":"rea-artifact-graph","name":"REA safe artifact graph provider","version":"1"}},{"capabilities":[{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"observe_native_ui","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":true,"mayShowUi":true,"mayWriteFilesystem":true,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"capture_native_ui_scenario","provider":{"id":"native-macos","name":"macOS native inspection utilities","version":null},"reason":null},{"available":true,"effects":{"changesPermissions":false,"launchesProcess":true,"mayAccessNetwork":false,"mayShowUi":false,"mayWriteFilesystem":false,"mutatesArtifact":false,"requiresRoot":false},"limitations":["Availability and textual formats depend on the installed macOS/Xcode toolchain."],"operation":"inspect_macho","provider":{"id":"native-macos","name":"macOS native inspection utilitiLine truncated
const generatedPayload: unknown = JSON.parse(GENERATED_PAYLOAD_JSON);
if (!isGeneratedPayload(generatedPayload))
throw new TypeError("Generated MCP catalog payload is invalid");
+1 -1
View File
@@ -5,5 +5,5 @@ export const PACKAGE_METADATA = {
serverSdkVersion: "2.0.0",
clientSdkVersion: "2.0.0",
coreSdkVersion: "2.0.0",
skillVersion: "23",
skillVersion: "24",
} as const;
+1 -1
View File
@@ -16,7 +16,7 @@ interface BrowserScenarioToolRegistration {
readonly recordEvidence: BinarySessionPort["recordEvidence"] | undefined;
}
/** Register the controlled browser scenario tool even when policy disables it. */
/** Register the browser scenario tool with execution-time provider diagnostics. */
export const registerBrowserScenarioTool = (
server: McpServer,
options: BrowserScenarioToolRegistration,
+1 -1
View File
@@ -37,7 +37,7 @@ interface BrowserToolContext {
readonly progress: ProgressReporter;
}
/** Register browser tools even when policy/provider availability denies execution. */
/** Register browser tools with execution-time provider diagnostics. */
// oxlint-disable-next-line max-lines-per-function -- direct SDK calls retain each schema-handler type correlation.
export const registerBrowserTools = (
server: McpServer,
+34 -1
View File
@@ -17,9 +17,15 @@ describe("canonical skill transaction", () => {
".agents/skills/reverse-engineer-anything/SKILL.md",
);
const sibling = join(home, ".agents/skills/unrelated/SKILL.md");
const nativeGuide = join(
dirname(destination),
"references/native-and-artifacts.md",
);
await mkdir(dirname(destination), { recursive: true });
await mkdir(dirname(nativeGuide), { recursive: true });
await mkdir(dirname(sibling), { recursive: true });
await writeFile(destination, "stale managed skill\n");
await writeFile(nativeGuide, "stale filesystem-write permission grant\n");
await writeFile(sibling, "unrelated skill\n");
expect(await canonicalSkillNeedsInstall(home)).toBe(true);
@@ -28,7 +34,34 @@ describe("canonical skill transaction", () => {
"stale managed skill\n",
);
const installedSkill = await readFile(destination, "utf8");
expect(installedSkill).toContain('version: "23"');
expect(installedSkill).toContain('version: "24"');
expect(installedSkill).toContain("call available analysis tools");
expect(installedSkill).toContain("obtain approval before setup writes");
expect(await readFile(`${nativeGuide}.rea.backup`, "utf8")).toBe(
"stale filesystem-write permission grant\n",
);
for (const reference of [
"native-and-artifacts.md",
"runtime-observation.md",
"evidence-workflows.md",
]) {
const installed = await readFile(
join(dirname(destination), "references", reference),
"utf8",
);
expect(installed).toBe(
await readFile(
new URL(
`../../../skills/reverse-engineer-anything/references/${reference}`,
import.meta.url,
),
"utf8",
),
);
expect(installed).not.toMatch(
/filesystem-write permission grant|native_mount_approved|only with explicit approval|Obtain the per-call/u,
);
}
expect(installedSkill).toContain(
"use normal repository tools and do not run REA",
);
@@ -75,6 +75,28 @@ describe("tool registration options", () => {
annotations: tool.annotations,
})),
);
for (const [name, expected] of [
["binary_session", { readOnlyHint: true, openWorldHint: false }],
["read_bytes", { readOnlyHint: false, destructiveHint: false }],
["set_comment", { readOnlyHint: false }],
["unset_bookmark", { destructiveHint: true }],
[
"capture_process_scenario",
{ readOnlyHint: false, openWorldHint: true },
],
["inspect_artifact", { readOnlyHint: false, openWorldHint: true }],
["extract_artifact", { readOnlyHint: false, idempotentHint: false }],
["compare_web_captures", { readOnlyHint: false, openWorldHint: false }],
[
"compare_web_screenshots",
{ readOnlyHint: false, openWorldHint: false },
],
] as const) {
expect(
advertised.find((tool) => tool.name === name)?.annotations,
name,
).toMatchObject(expected);
}
} finally {
await Promise.allSettled([client.close(), server.close()]);
}
@@ -7,6 +7,7 @@ import { createTestTempDirectory } from "../../../fixtures/temporaryDirectory.js
import { ArtifactProvider } from "../../../../src/artifacts/ArtifactProvider.js";
import { artifactExtractionExecutionSchema } from "../../../../src/contracts/artifactToolContracts.js";
import { TOOL_EFFECTS } from "../../../../src/contracts/toolEffects.js";
import {
artifactExtractionResultSchema,
artifactInventoryResultSchema,
@@ -14,6 +15,33 @@ import {
import type { BinaryTarget } from "../../../../src/domain/binaryTarget.js";
describe("artifact extraction", () => {
it("declares possible native mounts and fresh extraction directories", () => {
for (const platform of ["linux", "darwin"] as const) {
const provider = new ArtifactProvider(platform);
for (const operation of [
"inventory_artifact",
"inspect_artifact",
"extract_artifact",
] as const) {
expect(
provider
.capabilities()
.find((capability) => capability.operation === operation)?.effects,
).toMatchObject({ launchesProcess: true, mayWriteFilesystem: true });
}
}
expect(TOOL_EFFECTS.inspect_artifact).toMatchObject({
launchesProcess: true,
writesFilesystem: true,
mutatesTarget: false,
});
expect(TOOL_EFFECTS.extract_artifact).toMatchObject({
launchesProcess: true,
writesFilesystem: true,
idempotent: false,
mutatesTarget: false,
});
});
it("extracts all regular occurrences through an exclusively owned output tree", async () => {
const root = await createTestTempDirectory("rea-extract-");
const source = join(root, "source");