{"id":"a2672097-62de-4347-885e-5a2719828666","entityType":"agent","slug":"clawhub-imjszhang-js-eyes","name":"js-eyes","canonicalUrl":"https://www.xpersona.co/agent/clawhub-imjszhang-js-eyes","canonicalPath":"/agent/clawhub-imjszhang-js-eyes","generatedAt":"2026-10-09T20:33:01.804Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":null},"description":"Install, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 3.6K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s178deygezkand2ppdrw966d7s840msf:js-eyes","sourceUrl":"https://clawhub.ai/imjszhang/js-eyes","homepage":"https://clawhub.ai/imjszhang/skills/js-eyes","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/imjszhang/js-eyes","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/imjszhang/skills/js-eyes","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":55,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"js-eyes technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":null},"stars":null,"forks":null,"downloads":3625,"packageName":null,"latestVersion":"2.10.0","tractionLabel":"3.6K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T07:26:49.542Z","lastCrawledAt":"2026-10-09T07:26:49.542Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T07:26:49.542Z","lastVerifiedAt":null,"highlights":[{"version":"2.10.0","createdAt":"2026-07-25T07:32:57.703Z","changelog":"- **Package boundaries**: install/trust helpers live in `@js-eyes/skill-install`; policy primitives live in `@js-eyes/policy`. Compatibility re-exports under `@js-eyes/protocol/*` and `@js-eyes/client-sdk/policy` are removed. - **V1 skill activation removed**: `createOpenClawAdapter` / `skill.contract.js` loading and `externalSkills.policy=legacy` are gone. Migrate to V2 `skill.manifest.json` + `skill.entry.js`. - **First-class page interact**: `click` / `fill` / `scroll` / `wait_for` no longer require `allowRawEval`; MCP safe profile exposes matching tools. - **Skill scaffold**: official Skills use `@js-eyes/skill-scaffold` and `TOOL_DEFINITIONS` as the tool SSOT. - **Extension staging**: shared runtime is injected into `dist/extensions-stage/{chrome,firefox}` instead of committed browser copies. - **OpenClaw optional peer**: `@js-eyes/openclaw-plugin` no longer pulls OpenClaw into workspace production audits when the peer is absent.","fileCount":90,"zipByteSize":169720},{"version":"2.9.0","createdAt":"2026-07-24T11:22:02.080Z","changelog":"- **Host-neutral Skill Runtime V2**: the new public `@js-eyes/skill-contract`, `@js-eyes/skill-runtime`, and `@js-eyes/skill-worker` packages define static manifests, discovery, invocation, trust, and Worker execution independently of any host. - **CLI and MCP skill host**: invoke skills with `js-eyes skill call`; MCP clients can discover, describe, and call the same skills through `skill_list`, `skill_describe`, and `skill_call`. - **External-skill trust policy**: prompt and strict modes bind trust to a source digest and declared permissions, with explicit inspect, trust, and revoke flows. - **Optional OpenClaw adapter**: OpenClaw-specific configuration migration, routing, watchers, and registration now live in the plugin instead of the core runtime. - **Reliable hot reload**: linked skill directories and configuration changes rebuild the runtime; updated per-skill configuration reaches the replacement Worker. - **Static official manifests**: all eleven bundled skills expose V2 manifests and entries while retaining the V1 `createOpenClawAdapter` compatibility shim. - **Real-host validation**: the release was exercised through the CLI, MCP stdio, and OpenClaw 2026.6.10, including Worker isolation and plugin hot reload.","fileCount":90,"zipByteSize":176783},{"version":"2.8.5","createdAt":"2026-07-22T07:04:27.195Z","changelog":"- **Native MCP facade**: the new public `@js-eyes/mcp-server` package exposes the existing Client SDK and browser-extension runtime over standard MCP stdio JSON-RPC. - **Safe-by-default tools**: eight browser status, tab, navigation, HTML, metadata, and screenshot tools are available by default. JavaScript, CSS, cookies, and file upload require the explicit `full` profile. - **Structured MCP results**: normal operations return both readable content and `structuredContent`; screenshots use native MCP image blocks instead of embedding data URLs in text. - **Deterministic browser targeting**: exact extension client IDs take precedence, browser-name matches must be unique, and ambiguous calls fail instead of selecting an arbitrary browser. - **Security-preserving errors**: policy approval IDs and stable error codes are retained while tokens, scripts, file payloads, HTML, cookies, and image base64 are excluded from logs and unknown error responses. - **Protocol and end-to-end coverage**: tests use the official MCP client over both in-memory and real stdio transports and exercise the full MCP → Client SDK → Server Core → browser-extension route. - **Configurable Client SDK connection timeout**: MCP status checks and lazy connections can use a bounded connection timeout instead of the previous fixed ten-second value. - **Nine-package release pipeline**: release verification and OIDC publishing now include `@js-eyes/mcp-server` alongside the existing runtime packages and CLI.","fileCount":57,"zipByteSize":129691},{"version":"2.8.4","createdAt":"2026-07-19T10:16:41.698Z","changelog":"- **Chrome WebSocket compatibility**: browser extensions authenticate with the published `bearer.<token>` subprotocol, the server echoes the selected protocol, and credentials are no longer duplicated into WebSocket URLs. - **Chrome `execute_script` restored**: approved arbitrary JavaScript runs in Chrome's isolated `userScripts` world instead of MV3 CSP-blocked extension `eval`, including synchronous values, objects, and Promise results. - **Firefox startup restored**: classic background scripts now load without global-scope collisions after the extension hotspot split. - **Quieter extension reloads**: expected missing-receiver errors are consumed by the Chrome popup instead of surfacing as unchecked runtime errors. - **js-x-ops-skill 3.8.5**: media download/upload, Article and DraftJS support, improved official API routing, retries/timeouts, promoted-content detection, and expanded post/search coverage. - **Reproducible quality gates**: workspace tests, lint, type checking, coverage, dependency audit, package smoke tests, extension sync checks, and controlled release verification now run in CI. - **Hotspot refactor**: CLI commands, OpenClaw registration, build tooling, browser background orchestration, and X post/API code are separated into bounded modules without changing protocol version `1.0`. - **Platform bump**: CLI, extensions, OpenClaw plugin, and the eight published npm packages are synchronized to `2.8.4`.","fileCount":57,"zipByteSize":129689},{"version":"2.8.2","createdAt":"2026-05-22T08:27:57.030Z","changelog":"- **Firefox full-page screenshots**: `capture_screenshot` now supports","fileCount":39,"zipByteSize":103173},{"version":"2.8.1","createdAt":"2026-05-19T16:38:46.394Z","changelog":"- **Visual flags**: `--visual-hud` / `--no-visual-hud` / `--visual-flash` /","fileCount":38,"zipByteSize":101404},{"version":"2.8.0","createdAt":"2026-05-17T08:21:18.996Z","changelog":"- **Single OpenClaw tool**: the plugin registers only `js-eyes`; previous built-ins such as `js_eyes_get_tabs` and per-skill tools are internalized. - **Path-style actions**: call `browser/get-tabs`, `browser/open-url`, `skills/reload`, `security/reload`, or `skill/<skillId>/<action>` with `args: { ... }`. - **Router-mode skills**: `SkillRegistry` keeps hot-reloadable skill bindings without registering each skill action as an OpenClaw tool. - **Security preserved**: sensitive operations still pass through action-level policy wrapping and `security.toolPolicies`.","fileCount":38,"zipByteSize":100008},{"version":"2.7.0","createdAt":"2026-05-06T09:16:21.532Z","changelog":"Release v2.7.0","fileCount":38,"zipByteSize":99578}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s178deygezkand2ppdrw966d7s840msf:js-eyes","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s178deygezkand2ppdrw966d7s840msf:js-eyes` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/imjszhang/js-eyes before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-09T20:33:01.799Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-imjszhang-js-eyes/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":null},"readme":"Skill: js-eyes\n\nOwner: imjszhang\n\nSummary: Install, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter.\n\nTags: latest:2.10.0\n\nVersion history:\n\nv2.10.0 | 2026-07-25T07:32:57.703Z | user\n\n- **Package boundaries**: install/trust helpers live in `@js-eyes/skill-install`;\n  policy primitives live in `@js-eyes/policy`. Compatibility re-exports under\n  `@js-eyes/protocol/*` and `@js-eyes/client-sdk/policy` are removed.\n- **V1 skill activation removed**: `createOpenClawAdapter` /\n  `skill.contract.js` loading and `externalSkills.policy=legacy` are gone.\n  Migrate to V2 `skill.manifest.json` + `skill.entry.js`.\n- **First-class page interact**: `click` / `fill` / `scroll` / `wait_for` no\n  longer require `allowRawEval`; MCP safe profile exposes matching tools.\n- **Skill scaffold**: official Skills use `@js-eyes/skill-scaffold` and\n  `TOOL_DEFINITIONS` as the tool SSOT.\n- **Extension staging**: shared runtime is injected into\n  `dist/extensions-stage/{chrome,firefox}` instead of committed browser copies.\n- **OpenClaw optional peer**: `@js-eyes/openclaw-plugin` no longer pulls\n  OpenClaw into workspace production audits when the peer is absent.\n\nv2.9.0 | 2026-07-24T11:22:02.080Z | user\n\n- **Host-neutral Skill Runtime V2**: the new public\n  `@js-eyes/skill-contract`, `@js-eyes/skill-runtime`, and\n  `@js-eyes/skill-worker` packages define static manifests, discovery,\n  invocation, trust, and Worker execution independently of any host.\n- **CLI and MCP skill host**: invoke skills with `js-eyes skill call`; MCP\n  clients can discover, describe, and call the same skills through\n  `skill_list`, `skill_describe`, and `skill_call`.\n- **External-skill trust policy**: prompt and strict modes bind trust to a\n  source digest and declared permissions, with explicit inspect, trust, and\n  revoke flows.\n- **Optional OpenClaw adapter**: OpenClaw-specific configuration migration,\n  routing, watchers, and registration now live in the plugin instead of the\n  core runtime.\n- **Reliable hot reload**: linked skill directories and configuration changes\n  rebuild the runtime; updated per-skill configuration reaches the replacement\n  Worker.\n- **Static official manifests**: all eleven bundled skills expose V2 manifests\n  and entries while retaining the V1 `createOpenClawAdapter` compatibility\n  shim.\n- **Real-host validation**: the release was exercised through the CLI, MCP\n  stdio, and OpenClaw 2026.6.10, including Worker isolation and plugin hot\n  reload.\n\nv2.8.5 | 2026-07-22T07:04:27.195Z | user\n\n- **Native MCP facade**: the new public `@js-eyes/mcp-server` package exposes\n  the existing Client SDK and browser-extension runtime over standard MCP\n  stdio JSON-RPC.\n- **Safe-by-default tools**: eight browser status, tab, navigation, HTML,\n  metadata, and screenshot tools are available by default. JavaScript, CSS,\n  cookies, and file upload require the explicit `full` profile.\n- **Structured MCP results**: normal operations return both readable content\n  and `structuredContent`; screenshots use native MCP image blocks instead of\n  embedding data URLs in text.\n- **Deterministic browser targeting**: exact extension client IDs take\n  precedence, browser-name matches must be unique, and ambiguous calls fail\n  instead of selecting an arbitrary browser.\n- **Security-preserving errors**: policy approval IDs and stable error codes\n  are retained while tokens, scripts, file payloads, HTML, cookies, and image\n  base64 are excluded from logs and unknown error responses.\n- **Protocol and end-to-end coverage**: tests use the official MCP client over\n  both in-memory and real stdio transports and exercise the full MCP → Client\n  SDK → Server Core → browser-extension route.\n- **Configurable Client SDK connection timeout**: MCP status checks and lazy\n  connections can use a bounded connection timeout instead of the previous\n  fixed ten-second value.\n- **Nine-package release pipeline**: release verification and OIDC publishing\n  now include `@js-eyes/mcp-server` alongside the existing runtime packages and\n  CLI.\n\nv2.8.4 | 2026-07-19T10:16:41.698Z | user\n\n- **Chrome WebSocket compatibility**: browser extensions authenticate with the\n  published `bearer.<token>` subprotocol, the server echoes the selected\n  protocol, and credentials are no longer duplicated into WebSocket URLs.\n- **Chrome `execute_script` restored**: approved arbitrary JavaScript runs in\n  Chrome's isolated `userScripts` world instead of MV3 CSP-blocked extension\n  `eval`, including synchronous values, objects, and Promise results.\n- **Firefox startup restored**: classic background scripts now load without\n  global-scope collisions after the extension hotspot split.\n- **Quieter extension reloads**: expected missing-receiver errors are consumed\n  by the Chrome popup instead of surfacing as unchecked runtime errors.\n- **js-x-ops-skill 3.8.5**: media download/upload, Article and DraftJS support,\n  improved official API routing, retries/timeouts, promoted-content detection,\n  and expanded post/search coverage.\n- **Reproducible quality gates**: workspace tests, lint, type checking, coverage,\n  dependency audit, package smoke tests, extension sync checks, and controlled\n  release verification now run in CI.\n- **Hotspot refactor**: CLI commands, OpenClaw registration, build tooling,\n  browser background orchestration, and X post/API code are separated into\n  bounded modules without changing protocol version `1.0`.\n- **Platform bump**: CLI, extensions, OpenClaw plugin, and the eight published\n  npm packages are synchronized to `2.8.4`.\n\nv2.8.2 | 2026-05-22T08:27:57.030Z | user\n\n- **Firefox full-page screenshots**: `capture_screenshot` now supports\n\nv2.8.1 | 2026-05-19T16:38:46.394Z | user\n\n- **Visual flags**: `--visual-hud` / `--no-visual-hud` / `--visual-flash` /\n\nv2.8.0 | 2026-05-17T08:21:18.996Z | user\n\n- **Single OpenClaw tool**: the plugin registers only `js-eyes`; previous\n  built-ins such as `js_eyes_get_tabs` and per-skill tools are internalized.\n- **Path-style actions**: call `browser/get-tabs`, `browser/open-url`,\n  `skills/reload`, `security/reload`, or `skill/<skillId>/<action>` with\n  `args: { ... }`.\n- **Router-mode skills**: `SkillRegistry` keeps hot-reloadable skill bindings\n  without registering each skill action as an OpenClaw tool.\n- **Security preserved**: sensitive operations still pass through action-level\n  policy wrapping and `security.toolPolicies`.\n\nv2.7.0 | 2026-05-06T09:16:21.532Z | user\n\nRelease v2.7.0\n\nv2.6.3 | 2026-05-02T05:23:07.842Z | user\n\n- **Local launcher seeds the token file** *(2026-05-02)*:\n  [`bin/js-eyes-native-host-install.sh`](bin/js-eyes-native-host-install.sh)\n  and [`bin/js-eyes-native-host-install.ps1`](bin/js-eyes-native-host-install.ps1)\n  now run `node apps/cli/bin/js-eyes.js server token init` after the\n  `native-host install` step. `ensureToken()` is idempotent — if the file\n  already exists it's a no-op, so re-running the launcher is safe. The\n  practical effect: a freshly installed machine where the operator has never\n  started OpenClaw yet can still click **Sync Token From Host** the first\n  time and get a populated **Server Token** field. Opt out with\n  `--skip-token-init` (or `-SkipTokenInit` on Windows) / `JS_EYES_SKIP_TOKEN_INIT=1`.\n- **One-line installers seed the token file too** *(2026-05-02)*:\n  [`install.sh`](install.sh) / [`install.ps1`](install.ps1) (and their\n  `docs/`-mirrored copies that the `https://js-eyes.com/install.sh` route\n  serves) now run `npx js-eyes server token init` before the\n  `npx js-eyes native-host install --browser all` step, with the same\n  `--skip-token-init` / env-var opt-out. The closing banner gained a Tip\n  reminding operators to restart the browser before clicking **Sync Token\n  From Host**, and what to do if it still reports `token-missing`.\n- **`SKILL.md` rewritten around the \"token must exist first\" prerequisite**\n  *(2026-05-02)*:\n  - `Setup Workflow` step 8 is now an explicit three-way choice — any one\n    of (a) `js-eyes server token init`, (b) the local launcher (which now\n    does it for you), or (c) starting OpenClaw / `js-eyes server start` —\n    is enough to satisfy the prerequisite.\n  - `Browser Extension Connection` gained a dedicated \"make sure the host\n    has a token to share\" step before the launcher invocation.\n  - `Browser Extension Stays Disconnected` troubleshooting grew two new\n    rows: `Sync Token From Host` reporting `token-missing` (with the\n    `~/.js-eyes/logs/native-host.log` smoking-gun line) and `Could not\n    establish connection` from a stale browser process that hadn't seen\n    the freshly registered manifest.\n  - `Deployment Modes` Native Messaging blurb now contrasts the launcher\n    path (auto-seeds token) with the `npx` fallback (does **not** seed,\n    must be paired with `npx js-eyes server token init`).\n- **`docs/native-messaging.md`** *(2026-05-02)*: Install section made the\n  asymmetry between launcher and `npx` paths explicit, `pong` example\n  bumped to `\"version\":\"2.6.3\"`. The 排障 / troubleshooting block already\n  covered \"token 文件丢失\"; that text is unchanged but is now reachable\n  from the new SKILL troubleshooting rows.\n\nv2.6.2 | 2026-04-25T16:13:14.991Z | user\n\n- **Shell / env / fs / network call sites decoupled** *(2026-04-24)*: The five\n  static-analysis patterns flagged by ClawHub (shell exec, env + network,\n  file read + network) are dissolved by extracting each operation into a\n  small, purpose-built module: [`packages/protocol/safe-npm.js`](packages/protocol/safe-npm.js)\n  owns the only `npm` invocation (whitelisted subcommand / argv / env,\n  `shell:false`, `windowsHide:true`); [`packages/protocol/skill-runner.js`](packages/protocol/skill-runner.js)\n  owns sub-skill CLI invocation (`process.execPath` only, no PATH lookup,\n  `shell:false`, `windowsHide:true`); [`packages/protocol/openclaw-paths.js`](packages/protocol/openclaw-paths.js)\n  owns env-based path resolution; [`packages/protocol/fs-io.js`](packages/protocol/fs-io.js)\n  owns JSON / fs helpers; [`packages/protocol/registry-client.js`](packages/protocol/registry-client.js)\n  owns every `fetch(…)` against the skill registry so network I/O is never\n  co-located with `fs.readFileSync` / `createReadStream`;\n  [`openclaw-plugin/auth.mjs`](openclaw-plugin/auth.mjs) owns token reading +\n  header construction; [`openclaw-plugin/fs-utils/hash.mjs`](openclaw-plugin/fs-utils/hash.mjs)\n  streams SHA1 hashes with `createReadStream`; and\n  [`openclaw-plugin/windows-hide-patch.mjs`](openclaw-plugin/windows-hide-patch.mjs)\n  isolates the Windows-only `child_process` patch (no-op on POSIX).\n  `test/import-boundaries.test.js` prohibits these modules from importing\n  `ws` / `http` / `https` / `net` — the invariant is enforced by CI, and\n  `npm run scan:security` reproduces the ClawHub heuristic locally with an\n  allowlist of three documented residual `spawnSync` callsites.\n- **Optional integrity snapshots for `extraSkillDirs`** *(2026-04-24)*: New\n  config key `security.verifyExtraSkillDirs` (default **off**). When enabled,\n  `js-eyes skills link` writes a per-file sha256 map to\n  `~/.js-eyes/state/extras/<sha1(absPath)>.json` (outside the external dir);\n  `SkillRegistry` refuses to load an extra whose snapshot drifted and points\n  the operator at a new `js-eyes skills relink <abs-path>` command. `doctor`\n  reports the live integrity state per extra. Closes the \"extraSkillDirs\n  bypass integrity verification\" concern raised by the OpenClaw review.\n- **`js-eyes doctor --json`** *(2026-04-24)*: Emits the full security posture\n  as a single JSON document (token source, security config, loopback state,\n  per-skill integrity, policy snapshot) for auditors and CI. The human-readable\n  text output is byte-identical to 2.6.1.\n- **Local native-host launcher** *(2026-04-24)*: New scripts\n  [`bin/js-eyes-native-host-install.sh`](bin/js-eyes-native-host-install.sh) and\n  [`bin/js-eyes-native-host-install.ps1`](bin/js-eyes-native-host-install.ps1)\n  wrap `node apps/cli/bin/js-eyes.js native-host install` — zero network, zero\n  `npx`. `SKILL.md` and `docs/native-messaging.md` now recommend the local\n  launcher as the preferred path; `npx` remains a documented fallback.\n- **New documentation**: [`SECURITY_SCAN_NOTES.md`](SECURITY_SCAN_NOTES.md)\n  (per-finding response matrix), README **Security Posture** table, SKILL.md\n  **Safe Default Mode** section (capability envelope when\n  `allowRawEval=false`).\n- **CLI 子进程长尾修复** _(2026-04-25, 2.6.2 内补丁)_: `openclaw js-eyes status` / `tabs` / `server stop` 等一次性查询命令在 OpenClaw 子进程里跑完业务后会挂着不退出（chokidar `configWatcher` + `skillDirWatcher` 和 `skillRegistry` 持有 inotify/FSEvents handle 钉住 event loop），单次留下 ~50–100 MB 残留。在 [`openclaw-plugin/index.mjs`](openclaw-plugin/index.mjs) 模块顶层新增 `async exitCli(success)` helper（先 `await currentRegistration.teardown({})` 关掉 watchers / skillRegistry / WS bot，再 `setTimeout(() => process.exit(), 100).unref()` 兜底强退）和 `installCliExitHandlers()`（`uncaughtException` / `unhandledRejection` 全局兜底，仅在 `api.registerCli` 回调里调用一次，不污染 Gateway 进程）；三个一次性 CLI handler 末尾按成功/失败分别调 `await exitCli(true/false)`。**严格保持 `serverCmd.command(\"start\")` 不动** — 它是预期永不退出的 daemon。`registerService` / `registerTool` / chokidar 整体设计 / `_lastHashByPath` Map 全部原样。实测 CLI 退出时间从\"长尾几十秒至分钟级\"降到 ~2.6s（绝大部分是 plugin 冷启 skill 加载），`[js-eyes] Service stopped` 日志确认 teardown 触发。复用 js-moltbook 那次实战验证过的 pattern。Affects [openclaw-plugin/index.mjs](openclaw-plugin/index.mjs).\n\nv2.6.1 | 2026-04-23T16:58:11.494Z | user\n\n- **`MaxListenersExceededWarning` + `process.on('exit')` listener leak fixed** _(2026-04-24)_: `BrowserAutomation` no longer attaches per-instance `SIGINT` / `SIGTERM` / `exit` listeners — a module-level `Set` of active instances is now driven by a single set of process hooks installed via `_installProcessHooksOnce()`. The same fix applies to all 7 `skills/*/lib/js-eyes-client.js` copies. `skills/js-x-ops-skill/lib/xUtils.js` guards its own `process.on('exit')` with a `Symbol.for('js-eyes.skills.x-ops.xUtils.exitHook.v1')` flag so re-requires after a `require.cache` purge no longer stack duplicate exit callbacks. Affects [packages/client-sdk/index.js](packages/client-sdk/index.js), [skills/*/lib/js-eyes-client.js](skills), [skills/js-x-ops-skill/lib/xUtils.js](skills/js-x-ops-skill/lib/xUtils.js).\n- **`openclaw-plugin#register()` is now idempotent** _(2026-04-24)_: Re-entering `register()` (e.g. after a skill toggle or config edit) previously rebuilt a fresh `SkillRegistry`, chokidar watchers, WebSocket server, and `BrowserAutomation` while the old ones kept running — causing port bind races, leaked fds, and phantom reload storms. `register()` is now `async` and guards a module-level `currentRegistration` singleton: on re-entry it `await`s a deterministic `teardownRegistration(ctx)` (`reloadTimer → configWatcher → skillDirWatcher → skillRegistry.disposeAll() → bot.disconnect() → server.stop()`) before wiring the new instance. The `registerService({ id: \"js-eyes-server\" }).stop()` path routes through the same teardown and only nulls the singleton when its `api` identity matches the current one. Affects [openclaw-plugin/index.mjs](openclaw-plugin/index.mjs).\n- **Skill hot-reload now disposes adapters and detects real content changes** _(2026-04-24)_: `SkillRegistry._reloadCore` used to decide \"changed vs. unchanged\" from `sourcePath`/`skillDir` only, so edits to `skill.contract.js` that kept the same path were ignored and old adapters piled up in memory with live WebSockets + intervals. A new `computeSkillFingerprint(skillDir)` (mtime + size of `skill.contract.js` and `package.json`) is now stored on skill state and compared on every reload; the contract-level `runtime.dispose()` is called before the old module is evicted from `require.cache`, with a warn-level invariant assertion and a `Purged N cached module(s)` info log when purge actually runs. Every skill that opens a `BrowserAutomation` (`js-browser-ops`, `js-jike-ops`, `js-reddit-ops`, `js-wechat-ops`, `js-x-ops`, `js-xiaohongshu-ops`, `js-zhihu-ops`) gained a `dispose()` that drains the bot and nulls the handle. Affects [packages/protocol/skill-registry.js](packages/protocol/skill-registry.js), [skills/*/skill.contract.js](skills).\n- **Chokidar noise no longer triggers phantom reloads** _(2026-04-24)_: Editor atomic-writes, `.DS_Store` churn, and swap files on macOS used to fire `config-watch` / `skills-dir-watch` events that cascaded into full `SkillRegistry.reload()` calls. The plugin now ignores `.DS_Store`, `.git/`, `*.swp|swo|swx`, and `*~` at the watcher layer, and layers a sha1 content-hash gate (`scheduleReloadIfChanged(reason, filePath)`) so reloads only fire when the watched file's bytes actually changed. `runDiscover` also deduplicates `invalidExtraSkillDir` / skill-conflict warnings via per-registry `Set`s to stop log spam on repeated reloads. Affects [openclaw-plugin/index.mjs](openclaw-plugin/index.mjs), [packages/protocol/skill-registry.js](packages/protocol/skill-registry.js).\n\nv2.6.0 | 2026-04-21T16:33:00.462Z | user\n\n- **Sub-skill independent upgrade channel** _(2026-04-21)_: Every sub-skill under `skills/*` tracks its own `package.json#version`, decoupled from the parent `js-eyes` version (`npm run bump` intentionally skips `skills/*`). New CLI command `js-eyes skills update <skillId|--all> [--dry-run] [--allow-postinstall]` reuses the existing `planSkillInstall` / `applySkillInstall` pipeline, preserves `skillsEnabled.<id>`, and refuses to cross a `minParentVersion` gap (exit code `2`). The gate compares the registry entry's `minParentVersion` against the **client's** installed parent version (read from `apps/cli/package.json#version`), not the registry snapshot's `parentSkill.version`. Affects [apps/cli/src/cli.js](apps/cli/src/cli.js); see [CHANGELOG.md](CHANGELOG.md) for the full change surface.\n- **`install.sh` learns version-aware upgrades** _(2026-04-21)_: `install.sh` (and its mirror at [docs/install.sh](docs/install.sh)) now compares the local sub-skill's `package.json` version against the registry, prints `up to date` when they match, and upgrades in place (no `Overwrite?` prompt) when the registry is newer. `curl -fsSL https://js-eyes.com/install.sh | JS_EYES_SKILL=<id> bash` upgrades a single skill; `JS_EYES_SKILL=all` iterates every installed primary-source sub-skill. The shell path mirrors the CLI's `minParentVersion` gate by reading the local parent version from `${JS_EYES_ROOT}/package.json`.\n- **Richer `docs/skills.json` entries** _(2026-04-21)_: Each sub-skill now carries `minParentVersion`, `releasedAt`, and `changelogUrl`. Sub-skill authors can declare their parent floor via `package.json#jsEyes.minParentVersion` or `peerDependencies[\"js-eyes\"]`; `packages/devtools/lib/builder.js` backfills `releasedAt` from the sub-skill directory's latest git commit time and points `changelogUrl` at the sub-skill's `CHANGELOG.md` on GitHub when present. Older clients that parse `skills.json` see these as unknown optional fields and keep working.\n- **`skills list` surfaces update hints** _(2026-04-21)_: `js-eyes skills list` now prints `Update available: <local> -> <registry> (run: js-eyes skills update <id>)` for outdated primary-source skills, and exposes `updateAvailable` / `latestVersion` in the `--json` payload so other tooling can plumb it into dashboards.\n\nv2.5.2 | 2026-04-20T16:52:57.092Z | user\n\n- **Security config hot-reload — `egressAllowlist` without restart** _(2026-04-20)_: Editing `security.egressAllowlist` (and a small whitelist of other hot-safe fields) in `~/.js-eyes/config/config.json` now takes effect on the running JS Eyes server **without** restarting OpenClaw. Server-core now ships its own chokidar watcher on the config file (option `hotReloadConfig`, default `true`, with 300 ms debounce and graceful fallback when chokidar is not installed) plus a new `server.reloadSecurity({ source })` handle. A per-connection `PolicyContext` cache was the root cause of the previous \"I edited config but `open_url` still returns `pending-egress`\" confusion — reloads now bump `state.policyGeneration`, and `getOrCreatePolicyForClient` rebuilds stale per-connection policies from the live `state.security` on the next automation call. Hot-reloadable fields: `egressAllowlist`, `toolPolicies`, `sensitiveCookieDomains`, `allowedOrigins`, `enforcement`. Everything else (e.g. `allowAnonymous`, `allowRemoteBind`, `serverHost`/`serverPort`, token) is recorded under `ignored` in the reload summary and still requires a restart. New built-in tool `js_eyes_reload_security` (agent-driven) and new CLI preview `js-eyes security reload` (read-only dry run). New audit events: `config.hot-reload`, `config.hot-reload.error`, `automation.policy-rebuilt`. `GET /api/browser/status` now exposes `data.policy.generation` and `data.policy.egressAllowlist` for external verification. Affects [packages/server-core/index.js](packages/server-core/index.js), [packages/server-core/ws-handler.js](packages/server-core/ws-handler.js), [packages/config/index.js](packages/config/index.js) (new `resolveHotReloadableSecurity`), [apps/cli/src/cli.js](apps/cli/src/cli.js), and [openclaw-plugin/index.mjs](openclaw-plugin/index.mjs). New tests in [test/security-hot-reload.test.js](test/security-hot-reload.test.js).\n- **Skill tool schema is now visible to OpenClaw / LLM** _(2026-04-20)_: `SkillRegistry` used to register per-tool dispatchers with an empty placeholder schema (`{ type: 'object', properties: {} }`) and a generic description, so the LLM could not see `required` / `anyOf` constraints coming from skill contracts (e.g. `mastodon_get_status` silently dropped its `url`/`tabId` parameter and failed at runtime). The dispatcher now carries the contract's real `label` / `description` / `parameters` on first registration. Hot-reloads mutate the dispatcher object in place, so hosts that keep the tool object by reference see schema updates automatically; hosts that snapshot at registration time still get the correct first-load schema, with a one-time OpenClaw restart needed for subsequent schema changes. Affects [packages/protocol/skill-registry.js](packages/protocol/skill-registry.js); new tests in [test/skill-registry.test.js](test/skill-registry.test.js); docs in [docs/dev/js-eyes-skills/deployment.zh.md](docs/dev/js-eyes-skills/deployment.zh.md).\n\nv2.5.1 | 2026-04-19T22:16:56.400Z | user\n\n- **`allowRawEval`: single-toggle from the host** _(2026-04-20)_: The host now pushes `security.allowRawEval` to the browser extension via `init_ack.serverConfig.security.allowRawEval` at WebSocket handshake, and the extension applies it automatically. Previously operators had to flip the value in two places (host config **and** `chrome.storage.local`) because the extension popup never exposed a UI toggle for it — and the host value was never propagated — making the host-side switch effectively a no-op. Now only `security.allowRawEval=true` in `~/.js-eyes/config/config.json` is required; the extension picks it up on the next reconnect. The storage key remains as an explicit opt-out override for security-hardened deployments: `chrome.storage.local.set({allowRawEval:false})` (or `true`) pins the extension regardless of the host. Affects [packages/server-core/ws-handler.js](packages/server-core/ws-handler.js), [extensions/chrome/background/background.js](extensions/chrome/background/background.js), and [extensions/firefox/background/background.js](extensions/firefox/background/background.js).\n\nv2.5.0 | 2026-04-19T12:44:36.541Z | user\n\n- **Skill Hot Reload — zero-restart deployment** _(2026-04-19)_: A new `SkillRegistry` (`@js-eyes/protocol/skill-registry`) adds a tool-level dispatcher indirection layer to the OpenClaw plugin. Each tool name is registered once with OpenClaw as a stable closure; hot-loading / hot-unloading skills only updates the internal `toolBindings` map. `js-eyes skills link <path>` / `unlink <path>` / `reload`, plus a chokidar watcher on `~/.js-eyes/config/config.json` (debounced 300 ms), now apply skill changes to the running plugin **without restarting OpenClaw**. Agents can drive the flow via the new `js_eyes_reload_skills` built-in tool, which returns a diff summary (`added` / `removed` / `reloaded` / `toggledOff` / `conflicts` / `failedDispatchers`). Skills can opt into an `async runtime.dispose()` hook (see `examples/js-eyes-skills/js-hello-ops-skill/skill.contract.js`) to release WebSocket connections and timers on hot-unload; `require.cache` under the skill dir is deep-purged (preserving `node_modules`) before the next `require`. Extras discovered for the first time are auto-enabled (primary keeps its \"opt-in by default\" posture). Fallback: if the host refuses to register a brand-new tool name post-boot, the dispatcher registration failure is surfaced as `failedDispatchers` in the reload summary — a one-time OpenClaw restart is the fix for that narrow case; everything else is 0-restart. Full guide in [deployment.zh.md §5.3](./docs/dev/js-eyes-skills/deployment.zh.md#53-零重启部署skills-linkunlinkreload推荐).\n- **Multi-Source Skill Discovery (`extraSkillDirs`)** _(2026-04-19)_: New plugin config `extraSkillDirs: string[]` lets users mount read-only external skill directories without touching the primary `skillsDir`. Each entry auto-detects as a single skill (contains `skill.contract.js`) or a parent directory (scanned 1 level deep); primary wins on id conflicts; extras skip `.integrity.json` checks; `symlink`-to-directory entries are honored. CLI updates: `js-eyes doctor` lists primary + extras with kind/count; `js-eyes skills list` annotates each skill with `Source: primary | extra (<path>)` and ships a structured `--json` output (`primary` / `extras` / `skills[].source` / `skills[].sourcePath` / `conflicts`); `install` / `approve` reject ids that resolve to an extra source; `verify` prints `SKIPPED (extra source, no integrity check)` for extras; `enable` / `disable` / `skill run` all search primary → extras. New APIs in `@js-eyes/protocol/skills`: `resolveSkillSources`, `discoverSkillsFromSources`, `readSkillByIdFromSources`, `listSkillDirectories`. See [deployment mode D](./docs/dev/js-eyes-skills/deployment.zh.md#5-部署模式-dprimary--extraskilldirs).\n- **Default request timeout raised to 30 minutes**: The default `requestTimeout` now is 1800 seconds (previously 60). Long automation flows (captchas, slow SPA loads, file uploads) no longer hit a surprise 60s ceiling. The per-handler 30s safety net inside the browser extension is kept as a last-resort guard when the server `init_ack` never arrives.\n- **Server-side `requestTimeout` is now truly configurable**: `createServer()` reads `options.requestTimeout` (seconds), falling back to `@js-eyes/config` `config.requestTimeout` and finally to the protocol default. The resolved value is what the server pushes to extensions via `init_ack.serverConfig.request.defaultTimeout` and what the server uses for pending-response timeouts. Set it in `openclaw.json` → `plugins.entries[\"js-eyes\"].config.requestTimeout`, or via `js-eyes config set requestTimeout <seconds>` for the CLI server.\n- **Removed vestigial `skills/js-eyes/` parent-skill marker** _(2026-04-19)_: The in-repo `skills/js-eyes/` directory (a single `SKILL.md` with no `skill.contract.js`) has been deleted. Under the v2.0 \"single main plugin scans `skillsDir`\" model it had zero consumers — the main bundle packer (`SKILL_BUNDLE_FILES` in `packages/devtools/lib/builder.js`) only copies the repo-root `SKILL.md`, `discoverSubSkills()` skips directories without a `skill.contract.js`, and `discoverLocalSkills()` / `discoverSkillsFromSources()` gate on `hasSkillContract()`. The existing test `test/skill-bundle.test.js` → \"ignores parent skill docs without a child skill contract\" already asserts this directory shape must be skipped, so behavior is unchanged. Alongside the deletion, the soft-semantic `requires.skills: [js-eyes]` frontmatter field (only ever rendered as display text by `js_eyes_discover_skills`, never validated) was removed from `skills/js-x-ops-skill/SKILL.md` and `skills/js-browser-ops-skill/SKILL.md` so the remaining 10 child skills are consistent (the other 8 never declared it). No user-facing or packaging impact; the root `SKILL.md` remains the single source of truth for the `js-eyes` OpenClaw skill definition.\n\nv2.4.0 | 2026-04-17T10:29:45.673Z | user\n\nExtension UX + Native Messaging host. New js-eyes native-host install auto-syncs server.token/httpUrl into Chrome/Edge/Firefox. Popup streamlined to a single Sync Token From Host button with an Advanced fallback. Legacy HMAC auth, session refresh, and SSE fallback code removed. Wire protocol unchanged.\n\nv2.3.0 | 2026-04-16T20:10:54.712Z | user\n\n### Highlights\n- **Policy Engine**: New declarative rules layer in `@js-eyes/client-sdk/policy` (task origin, canary taint, egress allowlist). `BrowserAutomation.attachPolicy(ctx)` wires it into every sink; unattached SDK callers keep passing through.\n- **Pending Egress Queue**: Non-allowlisted `openUrl` calls become `runtime/pending-egress/<id>.json` records instead of executing. `js-eyes egress list|approve|allow|clear` manages the backlog.\n- **Cookie Canaries**: Every returned cookie gets a `jse-c-<hex>` canary; sinks that serialize a tainted value or canary are soft-blocked as `taint-hit`.\n- **Server-Side Fallback**: `packages/server-core/ws-handler.js` runs the same engine against raw automation WebSocket messages, covering external agents that bypass `client-sdk`.\n- **Enforcement Levels**: `off` (audit only), `soft` (default; plan-only + audit), `strict` (hard reject). Controlled via `js-eyes security enforce <level>`, `config.security.enforcement`, or `JS_EYES_POLICY_ENFORCEMENT`.\n- **HTTP Hardening**: server responses now carry `Content-Security-Policy: default-src 'none'`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer`, and `Permissions-Policy: interest-cohort=()`.\n- **Doctor Policy Report**: enforcement level, pending-egress backlog, most-recent soft-block, top-3 blocked tool/rule pairs, and skills with `platforms: ['*']` are all surfaced by `js-eyes doctor`.\n\n### Breaking Changes\n### Highlights\n- **Local Server Authentication**: Random bearer token generated on first start; WebSocket/HTTP clients must present it unless `security.allowAnonymous=true`.\n- **Origin Allowlist + Loopback Enforcement**: Server rejects non-allowlisted `Origin` and refuses non-loopback host binds without `security.allowRemoteHost=true`.\n- **Supply Chain Hardening**: `skills.json` entries ship with `sha256`/`size`, install is a two-phase `plan → approve → apply` flow, Zip Slip-safe extractor, `npm ci --ignore-scripts` with `package-lock.json` enforced.\n- **Skill Integrity Pinning**: `.integrity.json` is written on install; `registerLocalSkills` verifies files on load; `js-eyes skills verify` and `js-eyes doctor` expose drift.\n- **Sensitive Tool Consent Gateway**: `execute_script*`, `get_cookies*`, `upload_file*`, `inject_css`, `install_skill` default to `confirm` policy, with CLI `js-eyes consent` to approve/deny pending requests.\n- **Extensions**: Popups expose a \"Server Token\" field, raw `eval` disabled by default (`allowRawEval=false`), `externally_connectable` narrowed to port 18080.\n- **Audit Log**: JSONL at `logs/audit.log` with `js-eyes audit tail`.\n- **Secure Defaults on Disk**: `config.json`, `server.token`, `audit.log`, and consent files write at `0600` (POSIX) or locked via `icacls` (Windows).\n\nv2.1.0 | 2026-04-16T04:50:33.240Z | user\n\nAdd js-browser-ops-skill support and publish the 2.1.0 runtime, extension, and skill-bundle refresh.\n\nv2.0.1 | 2026-04-14T08:09:54.452Z | user\n\nOpenClaw: skill contract path resolution; discoverLocalSkills filters by skill.contract.js; parent skill SKILL.md under skills/js-eyes; bundle tests and docs alignment.\n\nv2.0.0 | 2026-04-14T04:48:07.189Z | user\n\nSwitch extension skills to host-side loading, remove child OpenClaw plugin wrappers, and prepare the 2.0.0 release line for the single-plugin install model.\n\nv1.5.1 | 2026-04-13T16:23:55.027Z | user\n\nStandardize JS Eyes as a setup-first ClawHub/OpenClaw skill bundle, align Node.js 22+ requirements, and switch extension skills to dynamic install after base plugin setup.\n\nv1.4.3 | 2026-02-25T13:46:21.864Z | auto\n\n- Major restructure: the skill bundle now directly includes the OpenClaw plugin, server, and client SDK for streamlined installation.\n- Added full server and client implementation (server/, clients/) to the published bundle.\n- Installation docs updated for ClawHub and workspace environments; clarified plugin registration path requirements.\n- Node.js 16+ is now required (was 14+).\n- Removal of legacy plugin entry files; only the new openclaw-plugin/ directory is needed.\n- Troubleshooting and deployment instructions improved, with explicit steps for npm dependencies.\n\nv1.4.2 | 2026-02-25T11:21:55.835Z | user\n\nImprove SKILL.md: add plugin files reference, prerequisites, detailed setup steps, verification and troubleshooting\n\nv1.4.1 | 2026-02-25T11:03:12.211Z | user\n\nRe-publish with plugin-only bundle (openclaw-plugin directory)\n\nv1.4.0 | 2026-02-25T10:39:42.354Z | user\n\nInitial release — browser automation plugin for AI agents via WebSocket\n\nArchive index:\n\nArchive v2.10.0: 90 files, 169720 bytes\n\nFiles: clients/js-eyes-client.js (67b), openclaw-plugin/actions/browser.mjs (12204b), openclaw-plugin/actions/management.mjs (4287b), openclaw-plugin/actions/skills.mjs (5850b), openclaw-plugin/auth.mjs (1724b), openclaw-plugin/cli-registration.mjs (4493b), openclaw-plugin/fs-utils/hash.mjs (1798b), openclaw-plugin/index.mjs (7891b), openclaw-plugin/legacy-config.mjs (1296b), openclaw-plugin/lifecycle.mjs (2144b), openclaw-plugin/native-host-setup.mjs (6874b), openclaw-plugin/openclaw.plugin.json (7905b), openclaw-plugin/package.json (453b), openclaw-plugin/registration-context.mjs (1946b), openclaw-plugin/server-service.mjs (2448b), openclaw-plugin/shared-server.mjs (1555b), openclaw-plugin/skill-config.mjs (2655b), openclaw-plugin/tool-policy.mjs (6760b), openclaw-plugin/tool-router.mjs (2281b), openclaw-plugin/watchers.mjs (5043b), openclaw-plugin/windows-hide-patch.mjs (2302b), package.json (600b), packages/client-sdk/index.js (17709b), packages/client-sdk/package.json (836b), packages/client-sdk/policy/egress.js (3112b), packages/client-sdk/policy/index.js (8649b), packages/client-sdk/policy/origin-utils.js (2397b), packages/client-sdk/policy/taint.js (2763b), packages/client-sdk/policy/task-origin.js (2087b), packages/client-sdk/tests/client.test.js (22225b), packages/config/index.js (10083b), packages/config/package.json (702b), packages/protocol/browser-operations.js (5443b), packages/protocol/extra-integrity.js (6032b), packages/protocol/fs-io.js (873b), packages/protocol/index.js (8434b), packages/protocol/package.json (969b), packages/protocol/registry-client.js (1909b), packages/protocol/safe-npm.js (5108b), packages/protocol/skill-runner.js (1903b), packages/protocol/skill-trust.js (4557b), packages/protocol/skills.js (23668b), packages/protocol/tests/extra-integrity.test.js (4943b), packages/protocol/tests/safe-npm.test.js (3015b), packages/protocol/tests/skill-trust.test.js (2506b), packages/protocol/zip-extract.js (7160b), packages/runtime-paths/index.js (6302b), packages/runtime-paths/package.json (651b), packages/runtime-paths/token.js (1992b), packages/server-core/audit.js (2254b), packages/server-core/auth.js (2631b), packages/server-core/index.js (21344b), packages/server-core/package.json (910b), packages/server-core/tests/auth.test.js (2370b), packages/server-core/tests/security-hot-reload.test.js (10178b), packages/server-core/tests/ws-handler.test.js (31649b), packages/server-core/ws-handler.js (22592b), packages/skill-contract/compatibility.js (2410b), packages/skill-contract/index.js (1294b), packages/skill-contract/manifest.js (7787b), packages/skill-contract/normalize.js (3756b), packages/skill-contract/package.json (755b), packages/skill-contract/source-digest.js (2391b), packages/skill-contract/tests/manifest.test.js (5669b), packages/skill-contract/validation.js (918b), packages/skill-recording/index.js (7732b), packages/skill-recording/package.json (716b), packages/skill-runtime/errors.js (1696b), packages/skill-runtime/host-service.js (7952b), packages/skill-runtime/index.js (468b), packages/skill-runtime/native-handlers.js (1074b), packages/skill-runtime/package.json (1023b), packages/skill-runtime/permissions.js (1847b), packages/skill-runtime/registry.js (37468b), packages/skill-runtime/runtime.js (12392b), packages/skill-runtime/tests/host-service.test.js (1826b), packages/skill-runtime/tests/permissions.test.js (1811b), packages/skill-runtime/tests/registry.test.js (23479b), packages/skill-runtime/tests/runtime.test.js (5712b), packages/skill-runtime/tests/skill-v2.test.js (7920b)\n\nFile v2.10.0:SKILL.md\n\n---\nname: js-eyes\ndescription: Install, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter.\nversion: 2.9.0\nmetadata: {\"openclaw\":{\"emoji\":\"\\U0001F441\",\"homepage\":\"https://github.com/imjszhang/js-eyes\",\"os\":[\"darwin\",\"linux\",\"win32\"],\"requires\":{\"bins\":[\"node\"]}}}\n---\n\n# JS Eyes\n\nJS Eyes is a local-first browser capability and site-skill runtime for AI\nagents. A browser extension connects to a local JS Eyes server; CLI, MCP, and\nOpenClaw are peer host surfaces over the same protocol, policy engine, and\nSkill Runtime.\n\nTreat `{baseDir}` as the root of this installed bundle. The optional OpenClaw\nadapter is `{baseDir}/openclaw-plugin`.\n\n## Use this Skill when\n\n- The user wants to install or connect JS Eyes.\n- An MCP or OpenClaw host cannot see JS Eyes tools.\n- The browser extension remains disconnected.\n- A local server, token, browser target, or security policy needs diagnosis.\n- The user wants to discover, inspect, trust, enable, or call a JS Eyes Skill.\n- An external V2 Skill needs to be linked without coupling it to OpenClaw.\n\n## Choose the host surface\n\nUse the smallest surface that fits the request:\n\n1. **CLI** — use `js-eyes` directly for server management, diagnostics, Skill\n   lifecycle, and one-off Skill calls.\n2. **MCP** — use `@js-eyes/mcp-server` for Codex, Claude, Cursor, VS Code, and\n   other local MCP clients.\n3. **OpenClaw** — load `{baseDir}/openclaw-plugin` only when OpenClaw-specific\n   lifecycle and routing are required.\n\nDo not install the OpenClaw adapter merely to use CLI or MCP.\n\n## Requirements\n\n- Node.js 22 or newer.\n- A supported Chrome, Edge, or Firefox extension.\n- A local JS Eyes server, normally at `http://localhost:18080`.\n- A shared server token unless anonymous compatibility mode was explicitly\n  selected.\n\nKeep the server bound to loopback unless the user has deliberately configured\nand secured remote access.\n\n## Standard standalone setup\n\nInstall the public CLI:\n\n```bash\nnpm install -g js-eyes\n```\n\nInitialize a token, register the optional Native Messaging bridge, and start\nthe server:\n\n```bash\njs-eyes server token init\njs-eyes native-host install --browser all\njs-eyes server start\njs-eyes doctor\n```\n\nInstall or load the browser extension, then use its popup to synchronize the\nserver URL and token. If Native Messaging is unavailable, reveal the token only\nfor the local user and paste it into the popup:\n\n```bash\njs-eyes server token show --reveal\n```\n\nNever place the token in documentation, logs, chat output, command arguments\nthat will be shared, or a remote URL.\n\n## MCP setup\n\nThe MCP facade connects lazily to an existing JS Eyes server:\n\n```json\n{\n  \"mcpServers\": {\n    \"js-eyes\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@js-eyes/mcp-server\"]\n    }\n  }\n}\n```\n\nThe default `safe` profile exposes browser status, tab, navigation, page-read,\nscreenshot, and read-only Skill Runtime tools. Raw JavaScript, CSS injection,\ncookie access, file upload, and non-read Skill calls are not discoverable.\n\nUse `--tool-profile full` only for a trusted MCP host when the requested task\nactually requires those capabilities. Server policy remains authoritative in\nboth profiles.\n\nStart diagnosis with:\n\n1. `browser_status`\n2. `browser_list_clients`\n3. `browser_list_tabs`\n\nWhen several extensions are connected, pass the exact `clientId` returned by\n`browser_list_clients`; do not select an ambiguous browser automatically.\n\n## OpenClaw setup\n\nThe ClawHub/bundle deployment uses the runtime packages and optional adapter\nshipped under `{baseDir}`:\n\n1. Run `npm install` in `{baseDir}` with Node.js 22 or newer.\n2. Resolve the OpenClaw config path in this order:\n   - `OPENCLAW_CONFIG_PATH`\n   - `OPENCLAW_STATE_DIR/openclaw.json`\n   - `OPENCLAW_HOME/.openclaw/openclaw.json`\n   - `~/.openclaw/openclaw.json`\n3. Merge the adapter path and enablement into the existing config.\n4. Add `js-eyes` to `tools.alsoAllow` or the equivalent tool allowlist.\n5. Restart or refresh OpenClaw.\n\nUse this config shape without removing unrelated entries:\n\n```json\n{\n  \"tools\": {\n    \"alsoAllow\": [\"js-eyes\"]\n  },\n  \"plugins\": {\n    \"load\": {\n      \"paths\": [\"/absolute/path/to/js-eyes/openclaw-plugin\"]\n    },\n    \"entries\": {\n      \"js-eyes\": {\n        \"enabled\": true,\n        \"config\": {\n          \"serverHost\": \"localhost\",\n          \"serverPort\": 18080,\n          \"autoStartServer\": true\n        }\n      }\n    }\n  }\n}\n```\n\nJS Eyes registers one OpenClaw tool named `js-eyes`. It routes path-style\nactions such as:\n\n- `browser/get-tabs`\n- `browser/list-clients`\n- `browser/open-url`\n- `browser/get-html`\n- `skills/discover`\n- `skills/plan-install`\n- `skills/reload`\n- `security/reload`\n- `skill/<skillId>/<action>`\n\nDo not look for or invoke the removed pre-2.8 multi-tool family.\n\nVerify OpenClaw mode in this order:\n\n```bash\nopenclaw plugins inspect js-eyes\nopenclaw js-eyes status\n```\n\nThen call the `js-eyes` tool with `action: browser/get-tabs` and `args: {}`.\n\n## Safe defaults\n\nThe recommended host posture is:\n\n- `security.allowAnonymous=false`\n- `security.allowRemoteBind=false`\n- `security.allowRawEval=false`\n- `security.enforcement=soft` or `strict`\n- a narrow `security.egressAllowlist`\n- token authentication enabled\n\nOrdinary status, tab, navigation, page-read, screenshot, and first-class\nbrowser operations should not require arbitrary JavaScript. If a specific\nlegacy or site Skill requires raw execution, explain the risk and enable\n`security.allowRawEval` only with explicit user intent. Restart the server\nafter changing that setting.\n\nReview the effective posture with:\n\n```bash\njs-eyes security show\njs-eyes doctor\njs-eyes audit tail --lines 100\n```\n\nPolicy or egress failures are decisions, not connectivity failures. Preserve\nthe returned error code and `pendingId`, let the user review the request, and\nuse the normal `js-eyes egress` or consent commands before retrying.\n\n## Skill Runtime V2\n\nJS Eyes discovers a V2 Skill from static `package.json` and\n`skill.manifest.json` metadata without executing its entry module. The\nmanifest declares compatibility, tools, schemas, risks, and capabilities.\n\nCommon lifecycle commands are:\n\n```bash\njs-eyes skills list\njs-eyes skills inspect <id>\njs-eyes skills enable <id>\njs-eyes skills disable <id>\njs-eyes skills link /absolute/path/to/skill\njs-eyes skills unlink /absolute/path/to/skill\njs-eyes skills trust <id>\njs-eyes skills revoke <id>\njs-eyes skills reload\n```\n\nCall the host-neutral runtime directly:\n\n```bash\njs-eyes skill call <id> <tool> --args '{\"key\":\"value\"}' --json\n```\n\nMCP exposes the same runtime through `skill_list`, `skill_describe`, and\n`skill_call`. OpenClaw routes the same tools through\n`skill/<skillId>/<action>`.\n\nFor external Skills under `prompt` or `strict` policy:\n\n1. Link the directory.\n2. Inspect its source, manifest, dependencies, declared permissions, and\n   execution mode.\n3. Trust it only after review.\n4. Re-review it whenever its path, source digest, dependencies, manifest,\n   capabilities, or execution mode changes.\n\nWorker mode is a crash and reachability boundary, not an operating-system\nsandbox. Direct filesystem, process, and network access cannot be completely\ncontained by a JavaScript Worker.\n\n## Native Messaging\n\nNative Messaging lets an allowlisted extension read the local server URL and\ntoken without manual copy and paste:\n\n```bash\njs-eyes native-host install --browser all\njs-eyes native-host status --browser all\n```\n\nRestart the browser or reload the extension after registration. If the popup\nreports `token-missing`, initialize the token before synchronizing. If the\nhost is unavailable, use manual token entry instead.\n\nThis mechanism protects against ordinary external web pages and unlisted\nextensions. A compromised local device or malicious local process is outside\nits threat model.\n\n## Troubleshooting\n\n### Server unavailable\n\nRun:\n\n```bash\njs-eyes status\njs-eyes doctor\n```\n\nStart the server if necessary and confirm that the configured port is not\nalready owned by an unrelated process.\n\n### Extension unavailable\n\nConfirm:\n\n- the correct extension is enabled;\n- the server URL uses the configured local host and port;\n- the extension and server share the same token;\n- the browser was restarted after Native Messaging installation;\n- at least one extension client appears in status output.\n\n### Authentication failed\n\nRotate or reinitialize the token only when the user understands that all\nconnected clients must resynchronize:\n\n```bash\njs-eyes server token rotate\n```\n\nNever reveal the replacement token in shared output.\n\n### Browser target required\n\nList clients and use the exact target ID. Do not guess when multiple browsers\nor profiles are connected.\n\n### Skill not found or disabled\n\nCheck `js-eyes skills list`, source directories, enablement, compatibility, and\ntrust state. Use `inspect` before `trust`; do not bypass strict policy by\nsilently switching it to legacy.\n\n### Skill input rejected\n\nRead the schema returned by `skill_describe` or `skills inspect`. Correct the\narguments instead of modifying the Skill to skip validation.\n\n### Raw execution refused\n\n`RAW_EVAL_DISABLED` is the safe default. Prefer a first-class operation or\nread-only Skill tool. Enable raw execution only when the task requires it and\nthe user accepts the additional authority.\n\n## Agent operating rules\n\n- Diagnose before changing configuration.\n- Repair existing configuration by merging; never overwrite unrelated hosts,\n  plugins, tools, or security settings.\n- Prefer CLI or MCP unless the task specifically requires OpenClaw.\n- Prefer read-only Skill tools and the MCP safe profile.\n- Ask for explicit intent before enabling a full profile, raw execution,\n  cookie access, file upload, destructive tools, or administrative tools.\n- Report the active host surface, connected browser target, and any policy\n  decision when handing the setup back to the user.\n\nFile v2.10.0:_meta.json\n\n{\n  \"ownerId\": \"kn70g9r4pqpqeckej65c2fznk981vvq3\",\n  \"slug\": \"js-eyes\",\n  \"version\": \"2.10.0\",\n  \"publishedAt\": 1784964777703\n}\n\nFile v2.10.0:SECURITY.md\n\n# Security and Network Behavior\n\n> **2.9.0 note**: This document covers the runtime security posture (network\n> behavior, token handling, policy engine, consent ledger, supply-chain\n> hardening since 2.2.0). For the per-finding response to the\n> [ClawHub Security Scan](https://clawhub.ai/imjszhang/js-eyes) of v2.6.1,\n> see [`SECURITY_SCAN_NOTES.md`](./SECURITY_SCAN_NOTES.md); for the one-screen\n> operator summary (risk item / current default / how to tighten / config\n> switch / verify) see the [Security Posture table in `README.md`](./README.md#security-posture-280).\n> A local reproduction of the ClawHub static heuristic is available via\n> `npm run scan:security` (zero unexpected findings on 2.6.3 — the 2.6.3\n> changes are install-time UX only and do not touch the runtime callsites\n> tracked by the scan).\n\n## Reporting a vulnerability\n\nUse GitHub's private vulnerability reporting flow from the repository's **Security** tab. Include the affected component and version or commit, reproduction steps, expected and observed impact, and any known mitigation.\n\nDo not open a public issue for a suspected vulnerability or disclose it before a fix or coordinated disclosure plan is available. Routine dependency updates and non-sensitive bugs can use normal GitHub issues.\n\n## Overview\n\nJS Eyes is a **local-first** browser automation stack. Its normal runtime loop talks only to the JS Eyes server you configure, which defaults to `localhost:18080`.\n\nThere are two deployment shapes to keep in mind:\n\n- **ClawHub / bundle deployment:** install the JS Eyes bundle, run `npm install` in the bundle root, register `openclaw-plugin`, and allow the plugin tools in OpenClaw.\n- **Source-repo / development deployment:** clone this repository, run `npm install` in the repo root, point OpenClaw at the repo-root `openclaw-plugin`, and optionally load the unpacked browser extension directly from `extensions/chrome/` or `extensions/firefox/`.\n\nThose two modes share the same local runtime behavior, but the source repository also contains release tooling, docs, site assets, and extension source files that reference public URLs for packaging and documentation workflows.\n\n## Complete OpenClaw Deployment Notes\n\nA complete local OpenClaw deployment needs all of the following:\n\n- `plugins.load.paths` points to the bundle or repo-root `openclaw-plugin` directory.\n- `plugins.entries[\"js-eyes\"].enabled` is `true`.\n- `tools.alsoAllow: [\"js-eyes\"]` or an equivalent `tools.allow` entry is present, because `js-eyes` registers optional plugin tools.\n- The browser extension is configured to connect to the chosen `serverHost` / `serverPort`.\n\nWithout the tool allowlist step, the plugin can load successfully while its\nsingle `js-eyes` router tool remains unavailable to the model.\n\n## Runtime Network Behavior\n\nBase runtime behavior:\n\n- **OpenClaw plugin:** connects via WebSocket to `ws://serverHost:serverPort` and uses HTTP only for JS Eyes server endpoints such as `/api/browser/status` and `/api/browser/tabs`.\n- **Client SDK and browser extension:** connect only to the JS Eyes server URL you configure.\n- **Server:** listens on a single HTTP+WebSocket port and does not need outbound internet access for the core browser automation loop.\n\nBy default this is all local traffic. No browser content is sent to a third-party service unless you explicitly point JS Eyes at a remote server you control.\n\n## Browser Native Messaging Host (Token Auto-Sync)\n\nJS Eyes 2.4+ ships an optional Native Messaging host (`com.js_eyes.native_host`) that lets the browser extension read `~/.js-eyes/runtime/server.token` directly, avoiding manual copy-paste.\n\n**Threat model**: this feature is designed to defend against **external web-page / cross-origin attackers** only. A compromised local device (root, malicious local process, malicious locally-loaded extension) is **explicitly out of scope** — any attacker with local code execution already has direct read access to `server.token`.\n\nSimplifications driven by this scoped threat model:\n\n- No in-extension secondary confirmation prompt.\n- No handshake / nonce / device-fingerprint binding.\n- The host simply returns the token when the browser calls it.\n\nTrust boundaries that remain in place:\n\n- Native messaging manifests whitelist specific extension IDs (Chrome: `allowed_origins`, Firefox: `allowed_extensions`) — unlisted extensions cannot launch the host.\n- The host only reads a fixed path (`~/.js-eyes/runtime/server.token`) and accepts only two messages (`ping`, `get-config`).\n- Extensions never expose the token through `externally_connectable`, so ordinary web pages cannot read it.\n- The Chrome manifest pins a stable extension ID via a `key` field so the allowlist stays authoritative after rebuilds.\n\nSee [docs/native-messaging.md](./docs/native-messaging.md) for install/uninstall commands and file-system paths.\n\n## Explicitly User-Initiated Network Access\n\nSome features intentionally access external URLs, but only when the user or agent explicitly chooses those workflows:\n\n- **Extension skill discovery/install:** `js-eyes` actions `skills/discover` and `skills/plan-install`, plus the install scripts, may fetch the configured registry URL such as `https://js-eyes.com/skills.json`.\n- **Release, docs, and packaging workflows in the source repo:** development tooling may reference GitHub Releases, project websites, Cloudflare deployment targets, Mozilla AMO, or similar public endpoints.\n- **Browser automation targets:** once connected, JS Eyes can automate whatever websites the user asks it to open; that traffic is the intended workload, not telemetry.\n\nThese are different from hidden analytics or call-home behavior. They happen only when the corresponding feature is invoked.\n\n## Why VirusTotal May Flag JS Eyes\n\nStatic analysis tools, including VirusTotal Code Insight, often flag projects that:\n\n- use `fetch()` or `WebSocket`\n- build URLs dynamically, such as `http://${host}:${port}/api/...`\n- expose an API or automation surface\n- include installer scripts or release/download URLs in the repository\n\nIn JS Eyes, those patterns map to local browser automation, optional skill installation, or developer-facing release workflows. They are not used for silent telemetry or covert outbound control.\n\n## ClawHub Bundle vs Full Repository\n\nThe ClawHub-distributed skill bundle is narrower than the full source repository:\n\n- **Included in the bundle:** the runtime pieces needed for JS Eyes skill/plugin behavior.\n- **Not shipped in the ClawHub bundle:** browser extension source, most docs, tests, and release/publishing tooling.\n\nThat means a scan of the full repository can surface external URLs that are irrelevant to the base ClawHub runtime package.\n\n## If ClawHub Shows a VirusTotal Warning\n\n- **Review the behavior in context:** the most common triggers are the local automation patterns above, not remote-control malware behavior.\n- **Report a false positive:** use the [VirusTotal false positive process](https://docs.virustotal.com/docs/false-positive) for the specific vendor(s) that flagged the file.\n- **Use manual review when needed:** if you maintain an internal allowlist or review process for OpenClaw/ClawHub skills, JS Eyes is a good candidate for a reviewed exception because its behavior is inspectable and mostly local-first.\n\n## Dependencies\n\n- **Core runtime dependency:** `ws` is required for WebSocket communication.\n- **Full development repository:** includes additional packages, build tools, docs, and browser extension assets needed for local development and release workflows.\n\n## Supply Chain Hardening (2.2.0+)\n\nJS Eyes 2.2.0 treats skill packages as untrusted inputs that must be validated end-to-end before they reach disk or are loaded into the runtime.\n\n- **Registry metadata carries integrity data.** Every entry in `dist/skills.json` now ships with `sha256` and `size`. The CLI (`js-eyes skills install`), the OpenClaw `js-eyes` action `skills/plan-install`, and `install.sh` / `install.ps1` all refuse to install a skill whose downloaded bundle does not match the expected digest.\n- **`@main` fallback URLs are refused.** The installers strip any registry fallback URL that resolves to a mutable `@main` / `refs/heads/main` CDN path. Bundles must be served from an immutable tag, release, or commit pinned URL.\n- **Safe ZIP extraction.** `packages/protocol/zip-extract.js` replaces `execSync unzip` / PowerShell `Expand-Archive` with an in-process ZIP reader that rejects Zip Slip, symlinks, and oversized entries (`maxFileSize`, `maxTotalSize`, `maxEntries`).\n- **Lockfile + `npm ci --ignore-scripts`.** `installSkillDependencies` requires `package-lock.json` and runs `npm ci --ignore-scripts --no-audit --no-fund`. The flag `security.requireLockfile=false` (or `JS_EYES_REQUIRE_LOCKFILE=0` in the install scripts) can be used to relax this during migration; doing so prints a prominent warning.\n- **Plan → approve installation.** `js-eyes skills install --plan` stages the extracted bundle in a temporary directory and writes a plan JSON to `runtime/pending-skills/<skillId>.json`. The install is only applied after `js-eyes skills approve <skillId>`. `js-eyes` action `skills/plan-install` inside OpenClaw likewise produces a plan and requires an out-of-band approval via the CLI.\n- **Runtime integrity pinning.** Every installed skill gets a `.integrity.json` manifest that records SHA-256 for each file. `registerLocalSkills` refuses to load a skill with mismatched/missing files. `js-eyes skills verify` and `js-eyes doctor` surface tamper indicators.\n- **Skills default disabled on upgrade.** `isSkillEnabled` returns `false` unless explicitly opted in via `skillsEnabled.<id>=true`. When upgrading from 2.1.x, existing skills without an explicit setting are left disabled and a warning is logged with instructions to `js-eyes skills enable <id>`.\n\n## Local Server Authentication (2.2.0+)\n\nThe local JS Eyes server no longer treats every localhost client as trusted.\n\n- **Bearer tokens.** On first start (or via `js-eyes server token init`) the server writes a random token to `runtime/server.token` (POSIX `chmod 0600`; on Windows, `icacls` restricts to the current user). Clients send the token via one of:\n  - HTTP `Authorization: Bearer <token>`\n  - WebSocket subprotocol header `Sec-WebSocket-Protocol: bearer.<token>, js-eyes` (browser extension) or `jse-token.<token>` (SDK)\n  - URL query parameter `?token=<token>` (legacy/custom loopback-only fallback; logged to the audit trail)\n  Tokens can be rotated with `js-eyes server token rotate`.\n- **Origin whitelist and CORS.** HTTP and WebSocket upgrades require an `Origin` from `security.allowedOrigins`. The defaults cover the bundled browser extensions, `http://localhost:18080`, and `http://127.0.0.1:18080`. `Access-Control-Allow-Origin` now echoes the caller only when it is on the whitelist; `*` is no longer returned.\n- **Loopback binding.** The server refuses to bind to a non-loopback host unless `security.allowRemoteBind=true`. When bound to a public address, a warning is logged and audited.\n- **`allowAnonymous` compatibility switch.** For clients that cannot yet send a token (for example, older DeepSeek Cowork installs), the operator can set `security.allowAnonymous=true`. Anonymous connections are marked in the audit log and in `js-eyes doctor`. This is explicitly a migration crutch: the log line reads `[js-eyes] WARNING: allowAnonymous=true; server accepts unauthenticated WS/HTTP clients`.\n- **Structured audit log.** Connection events, skill installs, config edits, and sensitive tool calls are written as JSONL to `logs/audit.log` with `chmod 0600`. `js-eyes audit tail` streams the last entries; sensitive values (cookies, script bodies, tokens) are redacted before being logged.\n- **File permissions.** `config.json`, `runtime/server.token`, `logs/audit.log`, and `runtime/pending-consents/*.json` are created/rewritten with `chmod 0600` (best-effort `icacls` on Windows).\n\n## Sensitive Tool Consent (2.2.0+)\n\nBuilt-in and skill-provided tools that can exfiltrate or mutate browser state are now routed through a consent gateway before execution.\n\n- **Sensitive action set.** `protocol.SENSITIVE_TOOL_NAMES` currently contains `browser/execute-script`, `browser/get-cookies`, `browser/get-cookies-by-domain`, `browser/upload-file`, `browser/inject-css`, and `skills/plan-install`. Additional actions can be added via `security.toolPolicies`.\n- **Policy modes.** Each sensitive tool resolves to one of `allow`, `confirm`, or `deny`. The OpenClaw plugin records every decision under `runtime/pending-consents/<id>.json` and logs a structured warning. `deny` short-circuits execution and returns a rejection payload. `confirm` creates a pending record and blocks the call until the operator runs `js-eyes consent approve <id>`; the approval is bound to the action and parameter digest and is consumed by the matching retry.\n- **Extension-side eval lockdown.** `handleExecuteScript` / `handleExecuteScriptRequest` (Chrome MV3 + Firefox MV2) reject raw JavaScript payloads unless `securityConfig.allowRawEval=true`. Starting with v2.5+, the extension no longer requires an independent config toggle: the host's `security.allowRawEval` is pushed down at WebSocket handshake (`init_ack.serverConfig.security.allowRawEval`) and applied automatically. The extension storage key `allowRawEval` is retained as an explicit **opt-out override** for security-hardened deployments: if an operator sets it explicitly via `chrome.storage.local.set({allowRawEval:false})` (or `true`), that value wins over the host-synced value. Chrome executes approved arbitrary source through its isolated `userScripts` world (Chrome 135+), rather than CSP-blocked extension `eval`; Chrome 138+ also requires the browser-controlled **Allow User Scripts** toggle. `RAW_EVAL_DISABLED` and `USER_SCRIPTS_UNAVAILABLE` let callers degrade gracefully.\n- **Consent log review.** Operators should periodically review `runtime/pending-consents/*.json` and the JSONL entries in `logs/audit.log`. `js-eyes consent list` summarizes recent decisions; `js-eyes consent approve <id>` / `js-eyes consent deny <id>` mark pending entries for audit.\n- **Server-supplied token propagation.** The browser extension popup exposes a \"Server Token\" field that is persisted in `chrome.storage.local`. The background service worker forwards the token as `Sec-WebSocket-Protocol: bearer.<token>` and does not duplicate it into the WebSocket URL. The server still accepts the loopback query form for older/custom clients.\n\n## Policy Engine (2.3.0+)\n\nStarting with 2.3.0 JS Eyes ships a declarative, non-interactive policy engine that sits between any tool caller (OpenClaw plugin, CLI, skill code, external agent) and the browser. It is tuned to defuse **prompt-injection-driven misuse** without relying on synchronous `confirm` dialogs.\n\n### Layers\n\n- **L4a — Same-Origin Task (`TaskOriginTracker`).** Merges a scope set from four sources: user messages (URLs / bare domains), `skill.contract.runtime.platforms`, the current active tab URL, and links found on HTML that the agent has already fetched. `getCookies` / `getCookiesByDomain` / `executeScript` / `injectCss` / `uploadFileToTab` are evaluated against this scope.\n- **L4b — Lightweight Taint (`TaintRegistry`).** Every cookie value returned by `getCookies*` is tagged with an 8-byte canary (`__canary: \"jse-c-<hex>\"`) and registered. Subsequent sink parameters (`openUrl`, `uploadFileToTab`, `executeScript`, `injectCss`) are scanned for the canary or common-encoded cookie-value variants. Hits are soft-blocked and audited as `reason: 'taint-hit'`.\n- **L5 — Egress Allowlist (`EgressGate`).** `openUrl` targets must be in: the task origin scope, `security.egressAllowlist` (static config), or the session allowlist (populated by prior approvals / explicit user-message URLs). Unmatched targets write a `runtime/pending-egress/<uuid>.json` record and return `{ status: 'pending-egress' }`; the browser extension never sees the navigation.\n- **L6 — Rule Engine Location.** The engine lives in `@js-eyes/client-sdk/policy` so that skills and the OpenClaw plugin share one implementation. `@js-eyes/server-core/ws-handler` re-instantiates the same engine to cover raw WebSocket callers (external agents that bypass `client-sdk`).\n\n### Enforcement Levels\n\n- `off` — audit only (no blocking, no pending-egress). Useful for troubleshooting false positives.\n- `soft` (default) — violating calls are not executed; `openUrl` returns `pending-egress`, other sinks return `POLICY_SOFT_BLOCK`. Agents observe the decision and can re-plan.\n- `strict` — same as `soft` but with escalation paths closed (cookie-canary hits never pass, taint values never traverse sinks).\n\nEnvironment and config overrides: `JS_EYES_POLICY_ENFORCEMENT`, `config.security.enforcement`, `js-eyes security enforce <level>`.\n\n### Operator Tooling\n\n- `js-eyes security show` prints the resolved policy (enforcement level, task-origin sources, egress allowlist, taint mode).\n- `js-eyes egress list|approve <id>|allow <domain>|clear` manages pending-egress plans and session/static allowlists.\n- `js-eyes doctor` reports enforcement mode, pending-egress backlog, last soft-block event, top-3 blocked tool/rule pairs, and skills whose `runtime.platforms` is `['*']`.\n- `logs/audit.log` carries `rule_decision`, `task_origin`, `taint_hit`, `egress_matched`, `enforcement`, `rule`, `reasons`, and `pendingId` for every policy-related event.\n\n### HTTP Response Hardening\n\n`packages/server-core` now emits `Content-Security-Policy: default-src 'none'; frame-ancestors 'none'`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer`, and `Permissions-Policy: interest-cohort=()` on every HTTP response. This closes the Chrome `externally_connectable` surface against any future accidental HTML response on port 18080.\n\n### Non-Goals (2.5.x)\n\n- Interactive `confirm` dialogs (still excluded by design).\n- Task profiles (L3) and reader sub-agent (L5') — remain opt-in additions on the roadmap and stay off by default.\n\n## Host-Synced `allowRawEval` (2.5.1+)\n\nHistorically, enabling raw `execute_script` required flipping `security.allowRawEval=true` on the host **and** manually seeding `chrome.storage.local.allowRawEval=true` on the extension (no popup UI exposed the latter), so the host-side toggle was effectively a no-op in practice. Starting with 2.5.1:\n\n- The host pushes `security.allowRawEval` to the browser extension via `init_ack.serverConfig.security.allowRawEval` at WebSocket handshake; the extension applies the value automatically.\n- The extension storage key `allowRawEval` is retained as an explicit **opt-out override** — set it to `true` or `false` via `chrome.storage.local.set({allowRawEval:false})` (or `true`) to pin the extension regardless of the host. Useful for security-hardened deployments that want to force-disable raw eval even if the host flips it on.\n- Everyday users only need to touch `~/.js-eyes/config/config.json`. Restart the server / OpenClaw after changing it so the extension picks up the new value on the next reconnect.\n\n## Security Config Hot-Reload (2.5.2+)\n\nA small whitelist of `security.*` fields can now be swapped into the running JS Eyes server **without** restarting OpenClaw or the server. Server-core ships its own chokidar watcher on `~/.js-eyes/config/config.json` (separate from the plugin's skill watcher) plus a `server.reloadSecurity()` handle that the `js-eyes` router action `security/reload` calls on demand.\n\n- **Hot-reloadable** (swap takes effect on the next automation call, ~300 ms from fs write; also immediately via the `security/reload` router action): `security.egressAllowlist`, `security.toolPolicies`, `security.sensitiveCookieDomains`, `security.allowedOrigins`, `security.enforcement`.\n- **Not hot-reloadable — server restart required** (changing these appears under `ignored` in the reload summary, with a one-line warning in the gateway log): `serverHost`, `serverPort`, `allowAnonymous`, `allowRemoteBind`, `allowRawEval`, `requireLockfile`, and anything outside `security.*` (token rotation, `requestTimeout`, etc.).\n- **Caveat — session-level egress approvals reset**: when the allowlist flips, each live automation connection rebuilds its `PolicyContext`, which means per-session `js-eyes egress approve <id>` grants are dropped. Agents re-issue the approval on the next `pending-egress` response; no action needed for standard `allow <domain>` edits because those are part of the static allowlist and get picked up automatically.\n- **Operator triggers** (any one is sufficient):\n  1. Edit `~/.js-eyes/config/config.json` and save — chokidar debounces 300 ms and fires `reloadSecurity({ source: 'fs-watch' })`.\n  2. Agent call: the `js-eyes` tool with `action: security/reload` (returns `{ changed, applied, ignored, generation, egressAllowlist }`).\n  3. CLI preview: `js-eyes security reload` — read-only dry run that prints what would be applied (CLI does not own the server event loop, so trigger #1 or #2 is required for the actual swap).\n- **Observability**: the audit log (`~/.js-eyes/logs/audit.log`) gains three new events — `config.hot-reload`, `config.hot-reload.error`, `automation.policy-rebuilt` — and `GET /api/browser/status` now includes `data.policy.generation` / `data.policy.egressAllowlist` so operators can externally confirm the live generation.\n\n---\n\n*Last updated: 2026-07-24 — covers the policy engine, Native Messaging host,\nhost-synced `allowRawEval`, security hot reload, the single OpenClaw router,\nand the host-neutral Skill Runtime V2 trust boundary.*\n\nFile v2.10.0:skill-card.md\n\n## Description:\n\nInstall, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[imjszhang](https://clawhub.ai/user/imjszhang)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators use JS Eyes to install, connect, operate, and troubleshoot local browser automation and JS Eyes Skill Runtime integrations across CLI, MCP, and OpenClaw hosts.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Local browser automation and JS Eyes runtime support can expose sensitive browser actions when broader authority is enabled.\n\nMitigation: Use the safe MCP profile where possible, keep raw eval disabled unless the task truly requires it, and require explicit operator intent before enabling sensitive actions.\n\nRisk: Skill install and discovery paths include review-worthy unsafe remote install and broad network-fetch behavior.\n\nMitigation: Use the staged skills/plan-install plus CLI approval path, review install plans before approval, and avoid untrusted custom registries.\n\nRisk: A local browser automation server can be exposed beyond the intended user if remote binding or anonymous access is enabled.\n\nMitigation: Keep the server on localhost with token authentication, leave anonymous access disabled, and avoid remote binding unless it is deliberately configured and secured.\n\nRisk: Native Messaging auto-install and skill directory watchers add local integration surface in hardened environments.\n\nMitigation: Consider disabling Native Messaging auto-install and skill directory watchers where local change monitoring or browser token synchronization is not required.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/imjszhang/skills/js-eyes)\n- [Project homepage from ClawDIS metadata](https://github.com/imjszhang/js-eyes)\n- [Artifact skill instructions](artifact/SKILL.md)\n- [Artifact security documentation](artifact/SECURITY.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with JSON and shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces setup, diagnosis, and policy-aware operation guidance; it does not produce binary artifacts.]\n\n## Skill Version(s):\n\n2.10.0 (source: server release evidence; artifact frontmatter and package manifests report 2.9.0)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment.\n\nFile v2.10.0:openclaw-plugin/openclaw.plugin.json\n\n{\n  \"id\": \"js-eyes\",\n  \"activation\": {\n    \"onStartup\": true\n  },\n  \"name\": \"JS Eyes\",\n  \"description\": \"浏览器自动化工具 — 通过 WebSocket 为 AI Agent 提供远程浏览器控制能力（标签页管理、内容获取、脚本执行等）\",\n  \"version\": \"2.9.0\",\n  \"contracts\": {\n    \"tools\": [\n      \"js-eyes\"\n    ]\n  },\n  \"toolMetadata\": {\n    \"js-eyes\": {\n      \"optional\": true\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"serverHost\": {\n        \"type\": \"string\",\n        \"default\": \"localhost\",\n        \"description\": \"JS-Eyes 服务器监听地址\"\n      },\n      \"serverPort\": {\n        \"type\": \"number\",\n        \"default\": 18080,\n        \"description\": \"JS-Eyes 服务器端口\"\n      },\n      \"autoStartServer\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"是否随插件加载自动启动内置服务器\"\n      },\n      \"requestTimeout\": {\n        \"type\": \"number\",\n        \"default\": 1800,\n        \"description\": \"浏览器操作请求超时（秒），默认 1800（30 分钟）\"\n      },\n      \"skillsRegistryUrl\": {\n        \"type\": \"string\",\n        \"default\": \"https://js-eyes.com/skills.json\",\n        \"description\": \"扩展技能注册表 URL\"\n      },\n      \"skillsDir\": {\n        \"type\": \"string\",\n        \"default\": \"\",\n        \"description\": \"扩展技能安装目录（空值则使用技能包内的 skills/ 目录）\"\n      },\n      \"extraSkillDirs\": {\n        \"type\": \"array\",\n        \"items\": {\n          \"type\": \"string\"\n        },\n        \"default\": [],\n        \"description\": \"额外只读技能来源（绝对路径列表）。每条可以是单个 V2/V1 技能目录或父目录（扫描 1 层子目录）。同 id 冲突时 primary 优先；可通过 host security.verifyExtraSkillDirs 启用快照校验。\"\n      },\n      \"skills\": {\n        \"type\": \"object\",\n        \"additionalProperties\": {\n          \"type\": \"object\"\n        },\n        \"default\": {},\n        \"description\": \"按技能 ID 配置运行参数；plugins config 覆盖 host config 中的同名技能配置。\"\n      },\n      \"externalSkills\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"default\": {\n          \"policy\": \"prompt\",\n          \"defaultExecution\": \"worker\"\n        },\n        \"description\": \"外部技能的发现、信任和执行策略。legacy 保持兼容；prompt 要求批准；strict 还要求 V2 静态 Manifest。\",\n        \"properties\": {\n          \"policy\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"legacy\",\n              \"prompt\",\n              \"strict\"\n            ],\n            \"default\": \"prompt\"\n          },\n          \"defaultExecution\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"in-process\",\n              \"worker\"\n            ],\n            \"default\": \"worker\"\n          }\n        }\n      },\n      \"watchConfig\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"通过 chokidar 监听 ~/.js-eyes/config/config.json，配置变更时（含 js-eyes skills link/unlink/enable/disable）零重启热加载技能。\"\n      },\n      \"devWatchSkills\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"开发模式：监听已发现技能目录的文件变更（默认 ~300ms 防抖），改完 Skill 源文件自动 reload。仅推荐在本地开发用；生产可关闭以减少 fs 监听负载。\"\n      },\n      \"nativeHost\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"default\": {\n          \"autoInstall\": true,\n          \"browser\": \"all\",\n          \"repairStale\": true,\n          \"warnOnly\": false\n        },\n        \"description\": \"浏览器 Native Messaging host 自检/修复配置，用于支持扩展 popup 的“从本机同步 token”。\",\n        \"properties\": {\n          \"autoInstall\": {\n            \"type\": \"boolean\",\n            \"default\": true,\n            \"description\": \"OpenClaw 加载插件时自动检查并安装/修复 JS Eyes Native Messaging host。\"\n          },\n          \"browser\": {\n            \"type\": \"string\",\n            \"default\": \"all\",\n            \"enum\": [\n              \"all\",\n              \"chromium\",\n              \"chrome\",\n              \"chrome-canary\",\n              \"edge\",\n              \"brave\",\n              \"firefox\"\n            ],\n            \"description\": \"要检查/安装的浏览器范围。\"\n          },\n          \"repairStale\": {\n            \"type\": \"boolean\",\n            \"default\": true,\n            \"description\": \"manifest 指向旧 launcher 或允许的扩展 ID 不匹配时自动重写。\"\n          },\n          \"warnOnly\": {\n            \"type\": \"boolean\",\n            \"default\": false,\n            \"description\": \"仅检查并记录日志，不写入 manifest、launcher 或 Windows 注册表。\"\n          }\n        }\n      }\n    }\n  },\n  \"uiHints\": {\n    \"serverHost\": {\n      \"label\": \"服务器地址\",\n      \"placeholder\": \"localhost\",\n      \"help\": \"JS-Eyes WebSocket/HTTP 服务器的监听地址\"\n    },\n    \"serverPort\": {\n      \"label\": \"服务器端口\",\n      \"placeholder\": \"18080\",\n      \"help\": \"JS-Eyes 服务器监听端口，需与浏览器扩展中配置的端口一致\"\n    },\n    \"autoStartServer\": {\n      \"label\": \"自动启动服务器\",\n      \"help\": \"启用后 OpenClaw 启动时自动拉起 JS-Eyes 内置服务器；禁用则需手动启动\"\n    },\n    \"requestTimeout\": {\n      \"label\": \"请求超时（秒）\",\n      \"help\": \"单次浏览器操作的最大等待时间，默认 1800 秒（30 分钟）\",\n      \"advanced\": true\n    },\n    \"skillsRegistryUrl\": {\n      \"label\": \"技能注册表 URL\",\n      \"placeholder\": \"https://js-eyes.com/skills.json\",\n      \"help\": \"扩展技能注册表地址，用于发现和安装扩展技能\",\n      \"advanced\": true\n    },\n    \"skillsDir\": {\n      \"label\": \"技能安装目录\",\n      \"placeholder\": \"\",\n      \"help\": \"扩展技能的安装目录（primary）。留空则自动使用技能包根目录下的 skills/ 子目录。js-eyes skills install/approve/verify 都作用在此目录。\",\n      \"advanced\": true\n    },\n    \"extraSkillDirs\": {\n      \"label\": \"额外只读技能目录\",\n      \"placeholder\": \"[\\\"/Users/you/my-skills\\\"]\",\n      \"help\": \"在 primary 之外纳入外部技能目录。目录保持只读；V2 prompt/strict 需要 trust，且可启用额外目录快照校验。运行中可用 js-eyes skills link/unlink 零重启增删。\",\n      \"advanced\": true\n    },\n    \"skills\": {\n      \"label\": \"技能运行配置\",\n      \"help\": \"按技能 ID 提供 config；插件配置覆盖 ~/.js-eyes/config/config.json 中的同名项。\",\n      \"advanced\": true\n    },\n    \"externalSkills\": {\n      \"label\": \"外部技能策略\",\n      \"help\": \"legacy 保持现有自动启用语义；prompt 要求先批准；strict 仅允许已批准且带 skill.manifest.json 的外部技能。\",\n      \"advanced\": true\n    },\n    \"watchConfig\": {\n      \"label\": \"监听宿主配置\",\n      \"help\": \"默认开启。关闭后 js-eyes skills link/unlink/enable/disable 等会写 ~/.js-eyes/config/config.json 的命令将不再触发自动热加载，需要手动调用 js-eyes skills reload 或通过 js-eyes 工具调用 action=skills/reload。\",\n      \"advanced\": true\n    },\n    \"devWatchSkills\": {\n      \"label\": \"监听技能目录（开发模式）\",\n      \"help\": \"默认开启。监听已发现技能目录里的文件变更，改完 Skill 源文件自动 reload。生产环境可关闭。\",\n      \"advanced\": true\n    },\n    \"nativeHost\": {\n      \"label\": \"Native Messaging 自动部署\",\n      \"help\": \"默认开启。OpenClaw 启动 JS Eyes 插件时检查并安装/修复浏览器 Native Messaging host，使扩展可以从本机同步 server token。修复后浏览器通常需要完整重启。\",\n      \"advanced\": true\n    }\n  }\n}\n\nFile v2.10.0:openclaw-plugin/package.json\n\n{\n  \"name\": \"js-eyes\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Optional OpenClaw plugin component for JS Eyes\",\n  \"type\": \"module\",\n  \"main\": \"index.mjs\",\n  \"engines\": {\n    \"node\": \">=22.0.0\"\n  },\n  \"files\": [\n    \"index.mjs\",\n    \"openclaw.plugin.json\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"chokidar\": \"^3.6.0\"\n  },\n  \"peerDependencies\": {\n    \"openclaw\": \">=0.0.0\"\n  },\n  \"openclaw\": {\n    \"extensions\": [\n      \"./index.mjs\"\n    ]\n  }\n}\n\nFile v2.10.0:package.json\n\n{\n  \"name\": \"js-eyes-skill-bundle\",\n  \"version\": \"2.9.0\",\n  \"private\": true,\n  \"description\": \"Installable JS Eyes runtime and skill bundle with optional host integrations\",\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"dependencies\": {\n    \"@js-eyes/skill-contract\": \"2.9.0\",\n    \"@js-eyes/client-sdk\": \"2.9.0\",\n    \"@js-eyes/config\": \"2.9.0\",\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\",\n    \"@js-eyes/server-core\": \"2.9.0\",\n    \"@js-eyes/skill-recording\": \"2.9.0\",\n    \"@js-eyes/skill-runtime\": \"2.9.0\"\n  },\n  \"engines\": {\n    \"node\": \">=22.0.0\"\n  },\n  \"license\": \"MIT\"\n}\n\nFile v2.10.0:packages/client-sdk/package.json\n\n{\n  \"name\": \"@js-eyes/client-sdk\",\n  \"version\": \"2.9.0\",\n  \"description\": \"JS Eyes BrowserAutomation client SDK\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"node --test tests/*.test.js\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"policy/\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/client-sdk\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"sdk\",\n    \"browser-automation\",\n    \"websocket\",\n    \"openclaw\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\",\n    \"ws\": \"^8.19.0\"\n  }\n}\n\nFile v2.10.0:packages/config/package.json\n\n{\n  \"name\": \"@js-eyes/config\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Runtime config helpers for JS Eyes CLI\",\n  \"main\": \"index.js\",\n  \"files\": [\n    \"index.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/config\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"config\",\n    \"cli\",\n    \"runtime\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\"\n  }\n}\n\nFile v2.10.0:packages/protocol/package.json\n\n{\n  \"name\": \"@js-eyes/protocol\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Shared protocol constants for JS Eyes runtime packages\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"node --test tests/*.test.js\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"browser-operations.js\",\n    \"skills.js\",\n    \"zip-extract.js\",\n    \"fs-io.js\",\n    \"safe-npm.js\",\n    \"extra-integrity.js\",\n    \"skill-trust.js\",\n    \"skill-runner.js\",\n    \"registry-client.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/protocol\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"protocol\",\n    \"browser-automation\",\n    \"openclaw\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/skill-contract\": \"2.9.0\"\n  }\n}\n\nFile v2.10.0:packages/runtime-paths/package.json\n\n{\n  \"name\": \"@js-eyes/runtime-paths\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Runtime directories for JS Eyes CLI and services\",\n  \"main\": \"index.js\",\n  \"files\": [\n    \"index.js\",\n    \"token.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/runtime-paths\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"runtime\",\n    \"paths\",\n    \"filesystem\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n\nFile v2.10.0:packages/server-core/package.json\n\n{\n  \"name\": \"@js-eyes/server-core\",\n  \"version\": \"2.9.0\",\n  \"description\": \"JS Eyes HTTP + WebSocket server core\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"node --test tests/*.test.js\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"ws-handler.js\",\n    \"audit.js\",\n    \"auth.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/server-core\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"server\",\n    \"websocket\",\n    \"http\",\n    \"browser-automation\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/client-sdk\": \"2.9.0\",\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\",\n    \"ws\": \"^8.19.0\"\n  }\n}\n\nArchive v2.9.0: 90 files, 176783 bytes\n\nFiles: clients/js-eyes-client.js (67b), openclaw-plugin/actions/browser.mjs (11813b), openclaw-plugin/actions/management.mjs (4281b), openclaw-plugin/actions/skills.mjs (5850b), openclaw-plugin/auth.mjs (1724b), openclaw-plugin/cli-registration.mjs (4493b), openclaw-plugin/fs-utils/hash.mjs (1798b), openclaw-plugin/index.mjs (8214b), openclaw-plugin/legacy-config.mjs (1296b), openclaw-plugin/lifecycle.mjs (2144b), openclaw-plugin/native-host-setup.mjs (6874b), openclaw-plugin/openclaw.plugin.json (7911b), openclaw-plugin/package.json (453b), openclaw-plugin/registration-context.mjs (1743b), openclaw-plugin/server-service.mjs (2448b), openclaw-plugin/shared-server.mjs (1555b), openclaw-plugin/skill-config.mjs (2655b), openclaw-plugin/skill-runtime-options.mjs (2648b), openclaw-plugin/tool-policy.mjs (6760b), openclaw-plugin/tool-router.mjs (2224b), openclaw-plugin/watchers.mjs (5037b), openclaw-plugin/windows-hide-patch.mjs (2302b), package.json (638b), packages/client-sdk/index.js (18545b), packages/client-sdk/package.json (836b), packages/client-sdk/policy/egress.js (3112b), packages/client-sdk/policy/index.js (8649b), packages/client-sdk/policy/origin-utils.js (2397b), packages/client-sdk/policy/taint.js (2763b), packages/client-sdk/policy/task-origin.js (2087b), packages/client-sdk/tests/client.test.js (21589b), packages/config/index.js (9968b), packages/config/package.json (702b), packages/protocol/extra-integrity.js (6032b), packages/protocol/fs-io.js (873b), packages/protocol/index.js (8178b), packages/protocol/package.json (965b), packages/protocol/registry-client.js (1909b), packages/protocol/safe-npm.js (5108b), packages/protocol/skill-registry.js (36849b), packages/protocol/skill-runner.js (1903b), packages/protocol/skill-trust.js (4557b), packages/protocol/skills.js (24243b), packages/protocol/tests/extra-integrity.test.js (4943b), packages/protocol/tests/safe-npm.test.js (3015b), packages/protocol/tests/skill-registry.test.js (23254b), packages/protocol/tests/skill-trust.test.js (2506b), packages/protocol/tests/skill-v2.test.js (7881b), packages/protocol/zip-extract.js (7160b), packages/runtime-paths/index.js (6302b), packages/runtime-paths/package.json (651b), packages/runtime-paths/token.js (1992b), packages/server-core/audit.js (2254b), packages/server-core/auth.js (2631b), packages/server-core/index.js (21344b), packages/server-core/package.json (910b), packages/server-core/tests/auth.test.js (2370b), packages/server-core/tests/security-hot-reload.test.js (10178b), packages/server-core/tests/ws-handler.test.js (31649b), packages/server-core/ws-handler.js (22789b), packages/skill-contract/compatibility.js (2410b), packages/skill-contract/index.js (1294b), packages/skill-contract/manifest.js (7787b), packages/skill-contract/normalize.js (3756b), packages/skill-contract/package.json (755b), packages/skill-contract/source-digest.js (2391b), packages/skill-contract/tests/manifest.test.js (5669b), packages/skill-contract/validation.js (918b), packages/skill-recording/index.js (7732b), packages/skill-recording/package.json (716b), packages/skill-runtime/errors.js (1578b), packages/skill-runtime/host-service.js (5529b), packages/skill-runtime/index.js (204b), packages/skill-runtime/legacy-entry.js (1058b), packages/skill-runtime/package.json (1034b), packages/skill-runtime/runtime.js (12392b), packages/skill-runtime/tests/host-service.test.js (1675b), packages/skill-runtime/tests/runtime.test.js (5706b), packages/skill-worker/host.js (8149b), packages/skill-worker/index.js (119b)\n\nFile v2.9.0:SKILL.md\n\n---\nname: js-eyes\ndescription: Install, configure, verify, and troubleshoot JS Eyes browser automation for OpenClaw.\nversion: 2.8.3\nmetadata: {\"openclaw\":{\"emoji\":\"\\U0001F441\",\"homepage\":\"https://github.com/imjszhang/js-eyes\",\"os\":[\"darwin\",\"linux\",\"win32\"],\"requires\":{\"bins\":[\"node\"]}}}\n---\n\n# JS Eyes\n\nUse this skill to turn a ClawHub-installed `js-eyes` bundle into a working OpenClaw browser automation stack.\n\nTreat `{baseDir}` as the installed skill root. The plugin path that must be registered in OpenClaw is `{baseDir}/openclaw-plugin`, not `{baseDir}` itself.\n\n## Use This Skill When\n\n- The user wants to install or configure JS Eyes from a ClawHub skill bundle.\n- `js_eyes_*` tools are missing after installation.\n- The browser extension is installed but still shows `Disconnected`.\n- The user wants to verify the built-in server, plugin config, or extension connection.\n- The user wants to discover or install JS Eyes extension skills after the base stack is working.\n- The user wants to mount a **custom / external** extension skill (a directory outside the bundle that contains a `skill.contract.js`) into a running OpenClaw, or to verify that such a skill is actually loaded.\n- The user wants to **author a new extension skill from scratch** — in that case, point them at the starter template and authoring guide (see `Authoring A New Extension Skill` below) rather than writing files from nothing.\n\n## What Success Looks Like\n\nA successful setup has all of the following:\n\n1. `npm install` has been run in `{baseDir}` with Node.js 22 or newer.\n2. OpenClaw loads `{baseDir}/openclaw-plugin` via `plugins.load.paths`.\n3. `plugins.entries[\"js-eyes\"].enabled` is `true`.\n4. `tools.alsoAllow` (preferred) or `tools.allow` includes `js-eyes`, so the plugin's optional tools are actually exposed to the model.\n5. The user can run `openclaw js-eyes status`.\n6. The browser extension is connected to `http://<serverHost>:<serverPort>`, the popup **Server Token** field is populated (2.2.0+), and `js-eyes` with `action: browser/get-tabs` returns real tabs.\n7. The bundled first-party extension skills under `{baseDir}/skills` are enabled by default in the JS Eyes host config, and the main plugin auto-loads enabled skills from `{baseDir}/skills` or the configured `skillsDir` (primary), plus any read-only directories listed in `extraSkillDirs` (extras). The user can later use `js-eyes` actions `skills/discover` and `skills/plan-install` to add more extension skills dynamically.\n8. `js-eyes doctor` reports an acceptable security posture for this skill's deployment (token present, `allowAnonymous=false`, **`allowRawEval=true` in `~/.js-eyes/config/config.json`**, host bound to loopback, skill integrity OK). `doctor` will still label raw eval as insecure — that is expected when following this skill.\n\n## Deployment Modes\n\nTreat `{baseDir}` as the bundle or repository root that contains `openclaw-plugin/`, `skills/`, and the package manifests.\n\nThere are two supported complete deployment modes:\n\n1. ClawHub / bundle deployment\n   - `{baseDir}` is the installed JS Eyes bundle root.\n   - Run `npm install` in `{baseDir}` so the plugin runtime can resolve its dependencies.\n   - Register `{baseDir}/openclaw-plugin` in OpenClaw.\n\n2. Source-repo / development deployment\n   - `{baseDir}` is the root of a local `js-eyes` git clone.\n   - Run `npm install` in the repo root, not inside `openclaw-plugin/`.\n   - Point OpenClaw `plugins.load.paths` at the repo-root `openclaw-plugin` directory.\n   - If you are debugging the browser side, load the extension from `extensions/chrome/` or `extensions/firefox/manifest.json` as appropriate.\n   - **Restart scope**: only changes to files **under `openclaw-plugin/` itself** (or any `packages/*` module the plugin imports directly) require restarting / refreshing OpenClaw so the plugin module is re-`require`d. Edits to individual skill files (`skills/<id>/skill.contract.js`, an `extraSkillDirs` entry's contract, etc.) are picked up hot by the `SkillRegistry` + chokidar watcher — no restart needed.\n\nFor **both** deployment modes above, treat **host-side raw eval** as part of the default install: merge `security.allowRawEval: true` into `~/.js-eyes/config/config.json` (Windows: `%USERPROFILE%/.js-eyes/config/config.json`) **during** deployment — not in `openclaw.json`. The js-eyes server reads this file; the browser extension syncs the value on WebSocket handshake (2.5.1+). Restart the server / OpenClaw after changing it so `execute_script` raw JavaScript is not blocked with `RAW_EVAL_DISABLED`.\n\nAlso for **both** modes, if the operator will use the extension popup **Sync Token From Host** / 从本机同步 (2.4.0+), register the Native Messaging host on that machine. **Preferred (local launcher, no network):** from the checked-out repo run `bin/js-eyes-native-host-install.sh --browser all` (macOS/Linux) or `./bin/js-eyes-native-host-install.ps1 -Browser all` (Windows); both forward to `node apps/cli/bin/js-eyes.js native-host install`, which never touches the npm registry. Since 2.6.3 the launchers also run `js-eyes server token init` (idempotent) at the end, so the host has a token file to read on the very first popup sync attempt — without that step the host returns `token-missing` until the operator either runs `js-eyes server token init` manually or starts OpenClaw / the server (`ensureToken()` runs on server boot). Pass `--skip-token-init` (`-SkipTokenInit` on Windows) to opt out of the auto-init. **Fallback:** `npx js-eyes native-host install --browser all` — only recommended when `js-eyes` is globally installed and the operator trusts the npm registry at install time; this fallback does **not** seed the token, so pair it with `npx js-eyes server token init` explicitly. Confirm with `node apps/cli/bin/js-eyes.js native-host status` (manifest + launcher must exist; on Windows the `.bat` lives under `%LOCALAPPDATA%\\js-eyes\\native-host\\`). Then restart the browser or reload the extension. Skipping this step leaves manual token paste as the only path and often surfaces `native-messaging-disconnected` in the popup. See `docs/native-messaging.md`.\n\n## Safe Default Mode (no raw eval)\n\nThis section is **informational** — the default Setup Workflow below still opts\ninto `allowRawEval=true` for full compatibility with the 2.6.x SKILL contract.\nIf an operator explicitly wants the host-hardened posture (ClawHub's\n`security.allowRawEval=false` default), use the guidance here; nothing outside\nthis section changes.\n\n- **What still works without `allowRawEval`**: `js-eyes` actions such as\n  `browser/open-url`, `browser/get-tabs`, `skills/reload`, `security/reload`,\n  plus every extension-skill action that avoids raw JavaScript. For the\n  vast majority of browsing / form-filling / data-extraction flows this is\n  sufficient.\n- **What gets refused with `RAW_EVAL_DISABLED`**: `browser/execute-script` and\n  other raw-JS entry points. Sensitive actions\n  that also happen to run raw JS (e.g. some `inject_css` variants when a skill\n  passes inline scripts) will soft-fail the same way; the dispatcher prints\n  `reason: RAW_EVAL_DISABLED` in the audit log.\n- **`doctor` output differs**: when `allowRawEval=false`,\n  `js-eyes doctor` / `js-eyes doctor --json` reports **no** \"expected insecure\"\n  footnote on that row — the default value is the safe value, so the tool\n  treats it as a clean posture. Everything else (token presence,\n  `allowAnonymous=false`, loopback bind, skill integrity, `extraSkillDirs`\n  integrity if `verifyExtraSkillDirs=true`) is reported identically to the\n  standard SKILL deployment.\n- **How to opt in**: omit the `security.allowRawEval: true` merge from step 5\n  of the Setup Workflow (or set it to `false` in an existing\n  `~/.js-eyes/config/config.json`), restart the js-eyes server / OpenClaw, and\n  optionally flip `security.verifyExtraSkillDirs=true` to close the\n  extraSkillDirs gap described in\n  [SECURITY_SCAN_NOTES.md](./SECURITY_SCAN_NOTES.md#c-extraskilldirs-bypass-integrity-verification).\n- **Behaviour guarantee**: if an operator follows the default SKILL workflow\n  below without any of these tweaks, the runtime behaviour in 2.6.3 is\n  identical to 2.6.1 — Safe Default Mode is purely additive guidance.\n  (2.6.3 only changes the install-time UX around `server.token` seeding;\n  it does not alter the policy / consent / egress runtime.)\n\n## Setup Workflow\n\nWhen the user asks to install, configure, or repair JS Eyes, follow this exact order:\n\n1. Determine the operating system first and choose commands accordingly.\n2. Resolve the OpenClaw config path before editing anything.\n3. Verify prerequisites:\n   - `node -v` must be `>= 22`\n   - if the user expects OpenClaw plugin mode, `openclaw --version` should work\n4. From `{baseDir}`, run `npm install` if dependencies are missing or if the user just installed the bundle.\n5. Update the resolved `openclaw.json`:\n   - ensure `plugins.load.paths` contains the absolute path to `{baseDir}/openclaw-plugin`\n   - ensure `plugins.entries[\"js-eyes\"].enabled` is `true`\n   - ensure `tools.alsoAllow` contains `js-eyes` (preferred additive mode), or ensure `tools.allow` includes `js-eyes`\n   - if needed, create `plugins.entries[\"js-eyes\"].config` with:\n     - `serverHost: \"localhost\"`\n     - `serverPort: 18080`\n     - `autoStartServer: true`\n   - merge or create the **JS Eyes host config** at `~/.js-eyes/config/config.json` (Windows: `%USERPROFILE%/.js-eyes/config/config.json`) with `security.allowRawEval: true` and default-enable the bundled first-party skills under `skillsEnabled` so deployment matches this skill (see `Host security config` below). Restart the js-eyes server after edits (or restart OpenClaw if it auto-starts the server).\n6. Restart or refresh OpenClaw so the plugin is reloaded.\n7. Verify with `openclaw js-eyes status`.\n8. Make sure `~/.js-eyes/runtime/server.token` exists **before** anyone clicks the popup's **Sync Token From Host** / 从本机同步 button — otherwise the native host replies `token-missing` and the popup falls back to manual paste. Three ways to create it, any one is enough:\n   - Run `js-eyes server token init` directly (idempotent — no-op if the file already exists).\n   - Run the local launcher `bin/js-eyes-native-host-install.sh --browser all` (macOS/Linux) / `./bin/js-eyes-native-host-install.ps1 -Browser all` (Windows) — since 2.6.3 it does the `token init` for you (skip with `--skip-token-init`).\n   - Start OpenClaw (with `autoStartServer: true`) or `js-eyes server start` once — the server calls `ensureToken()` on boot.\n\n   Then run the local launcher above (or the equivalent `node apps/cli/bin/js-eyes.js native-host install --browser all`) to register the Native Messaging manifest **without hitting the npm registry**. `npx js-eyes native-host install` remains as a fallback when the operator already has `js-eyes` globally installed; the npx path does **not** seed the token, so pair it with `npx js-eyes server token init`. If the operator can't or won't use Native Messaging at all, run `js-eyes server token show --reveal` and paste the value into the extension popup **Server Token** field under **Advanced**.\n9. If the server is healthy but no browser is connected, guide the user through browser extension installation, server-token entry, and connection.\n10. After the base setup works, pick the right path for extension skills:\n    - **Registry / first-party skills**: prefer the `js-eyes` tool actions `skills/discover` + `skills/plan-install` — 2.2.0+ writes a plan under `runtime/pending-skills/<id>.json`; finalize with `js-eyes skills approve <id>` then `js-eyes skills enable <id>`.\n    - **Custom / external skills** (a directory the user already has on disk): prefer `js-eyes skills link <abs-path>` — it appends the path to `extraSkillDirs`, auto-enables it on first discovery, and the running plugin hot-loads it within ~300 ms via the config watcher. Reverse with `js-eyes skills unlink <abs-path>`. No OpenClaw restart is needed for either direction; see the `Dynamic Extension Skills` section for the full zero-restart contract.\n11. Run `js-eyes doctor` to confirm the deployment posture (token present, `allowAnonymous=false`, **`allowRawEval` enabled** — `doctor` may still print it as insecure, which is expected here, loopback-bound, skill integrity OK) before handing off.\n\nWhen asked to fix a broken setup, prefer repairing the existing config instead of repeating the whole installation.\n\n## Resolve The OpenClaw Config Path\n\nUse this precedence order:\n\n1. `OPENCLAW_CONFIG_PATH`\n2. `OPENCLAW_STATE_DIR/openclaw.json`\n3. `OPENCLAW_HOME/.openclaw/openclaw.json`\n4. Default:\n   - macOS / Linux: `~/.openclaw/openclaw.json`\n   - Windows: `%USERPROFILE%/.openclaw/openclaw.json`\n\nDo not assume `~/.openclaw/openclaw.json` if any of the environment variables above are set.\n\n## Recommended Config Shape\n\nUpdate the resolved OpenClaw config so it contains the plugin path and enablement entry. Append to existing arrays and objects; do not remove unrelated plugins.\n\n```json\n{\n  \"tools\": {\n    \"alsoAllow\": [\"js-eyes\"]\n  },\n  \"plugins\": {\n    \"load\": {\n      \"paths\": [\"/absolute/path/to/js-eyes/openclaw-plugin\"]\n    },\n    \"entries\": {\n      \"js-eyes\": {\n        \"enabled\": true,\n        \"config\": {\n          \"serverHost\": \"localhost\",\n          \"serverPort\": 18080,\n          \"autoStartServer\": true\n        }\n      }\n    }\n  }\n}\n```\n\n### Host security config (`~/.js-eyes/config/config.json`)\n\nThis file is **not** `openclaw.json`. For deployments following this skill, ensure at least:\n\n```json\n{\n  \"skillsEnabled\": {\n    \"js-bilibili-ops-skill\": true,\n    \"js-browser-ops-skill\": true,\n    \"js-github-ops-skill\": true,\n    \"js-hn-ops-skill\": true,\n    \"js-jike-ops-skill\": true,\n    \"js-reddit-ops-skill\": true,\n    \"js-wechat-ops-skill\": true,\n    \"js-x-ops-skill\": true,\n    \"js-xiaohongshu-ops-skill\": true,\n    \"js-youtube-ops-skill\": true,\n    \"js-zhihu-ops-skill\": true\n  },\n  \"security\": {\n    \"allowRawEval\": true\n  }\n}\n```\n\nMerge with existing keys (for example `skillsDir`, `skillsEnabled`). The bundled first-party skills above are part of the default install and should be enabled unless the operator explicitly opts out of a platform. Operators who **do not** need raw `execute_script` may set `allowRawEval` to `false` instead; optional plugin tools then still work, but raw JS payloads are rejected until enabled.\n\nImportant details:\n\n- The path must end in `openclaw-plugin`.\n- On Windows JSON paths, prefer forward slashes such as `C:/Users/name/skills/js-eyes/openclaw-plugin`.\n- If `paths` or `entries` already exist, merge rather than overwrite.\n- `js-eyes` registers one optional plugin tool, so a complete deployment also needs `tools.alsoAllow: [\"js-eyes\"]` or an equivalent `tools.allow` entry.\n- `skillsEnabled` lives in the JS Eyes host config, not in `openclaw.json`. Enabling a bundled skill exposes its actions through the main `js-eyes` router; disabling it leaves the files on disk but skips loading it.\n- To mount extension skills from outside `{baseDir}/skills` (e.g. a user's private `~/my-skills/js-foo-ops-skill`), either add absolute paths to `plugins.entries[\"js-eyes\"].config.extraSkillDirs: [...]` directly, or let the CLI handle it: `js-eyes skills link <abs-path>` does the dedup append and also triggers an in-memory reload on the running plugin. Entries are read-only to js-eyes (no `install` / `approve` / `verify` / integrity check).\n- Two new optional plugin config booleans control the hot-reload watchers (both default `true`): `watchConfig` (listen on `~/.js-eyes/config/config.json`) and `devWatchSkills` (listen on discovered skill directories). Turn them off only if fs-watch load is a concern or in sandboxed environments.\n\n#### Host security hot-reload (2.5.2+)\n\nSome `security.*` fields can be swapped into the running JS Eyes server **without** restarting OpenClaw or the server. The server-core ships its own chokidar watcher on `~/.js-eyes/config/config.json` (separate from the plugin's skill watcher) and a `reloadSecurity()` handle that the `js-eyes` action `security/reload` calls on demand.\n\n- **Hot-reloadable** (swap takes effect on the next automation call, ~500 ms from fs write; also immediately via `js-eyes` action `security/reload`):\n  - `security.egressAllowlist`\n  - `security.toolPolicies`\n  - `security.sensitiveCookieDomains`\n  - `security.allowedOrigins`\n  - `security.enforcement`\n- **Not hot-reloadable — server restart required** (changing these appears under `ignored` in the reload summary, with a one-line warning in the gateway log): `serverHost`, `serverPort`, `allowAnonymous`, `allowRemoteBind`, `allowRawEval`, `requireLockfile`, and anything outside `security.*` (token rotation, `requestTimeout`, etc.).\n- **Caveat — session-level egress approvals reset**: when the allowlist flips, each live automation connection rebuilds its `PolicyContext`, which means per-session `js-eyes egress approve <id>` grants are dropped. Agents re-issue the approval on the next `pending-egress` response; no action needed for standard `allow <domain>` edits because those are part of the static allowlist and get picked up automatically.\n- **Operator triggers** (any one is sufficient):\n  1. Edit `~/.js-eyes/config/config.json` and save — chokidar debounces 300 ms and fires `reloadSecurity({ source: 'fs-watch' })`.\n  2. Agent call: `js-eyes` with `action: security/reload` (returns `{ changed, applied, ignored, generation, egressAllowlist }`).\n  3. CLI preview: `js-eyes security reload` — read-only dry run that prints what would be applied (CLI does not own the server event loop, so trigger #1 or #2 is required for the actual swap).\n- **Observability**: the audit log (`~/.js-eyes/logs/audit.log`) gains three new events — `config.hot-reload`, `config.hot-reload.error`, `automation.policy-rebuilt` — and `GET /api/browser/status` now includes `data.policy.generation` / `data.policy.egressAllowlist` so operators can externally confirm the live generation.\n\n## Verification Workflow\n\nAfter setup, verify the stack in this order:\n\n1. `openclaw plugins inspect js-eyes`\n2. `openclaw js-eyes status`\n3. Check whether the built-in server is reachable and reports uptime.\n4. Confirm that at least one browser extension client is connected.\n5. Ask the agent to use `js-eyes` with `action: browser/get-tabs` or run `openclaw js-eyes tabs`.\n6. If the user wants extension skills, call `js-eyes` with `action: skills/discover` only after the base stack works.\n\nExpected status checks:\n\n- `openclaw plugins inspect js-eyes` shows the plugin as loaded.\n- Server responds on `http://localhost:18080` by default.\n- `openclaw js-eyes status` shows uptime and browser client counts.\n- `browser/get-tabs` returns tabs instead of an empty browser list.\n\n### Verifying A Specific Extension Skill Is Loaded\n\nWhen the user asks \"did my skill get picked up?\", check all four:\n\n1. `~/.js-eyes/config/config.json` has `skillsEnabled[\"<id>\"]: true` and (for externals) the skill's directory or a parent is listed in `extraSkillDirs`.\n2. Tail the gateway log and look for one of these lines from `[js-eyes]`:\n   - `Skill sources: primary=<dir> extras=<N>` — confirms extras were seen at startup.\n   - `Loaded local skill \"<id>\" with K tool(s)` — initial load at plugin boot.\n   - `Hot-loaded skill \"<id>\" with K tool(s)` — loaded at runtime by the config / skill-dir watcher.\n   - `Discovered <N> skill(s): <K> active` — gives a numeric sanity check.\n3. Ask the agent to call `js-eyes` with `action: skills/reload`; the returned summary must contain the id under `added` or `reloaded`.\n4. Run `js-eyes skills list` from the host shell; each entry is annotated with `Source: primary` or `Source: extra (<path>)`.\n\nIf steps 2-4 all fail for a freshly linked external skill, see the `Custom Extension Skill Not Picked Up` troubleshooting entry below.\n\n## Browser Extension Connection\n\nIf the plugin is enabled but no browser is connected:\n\n1. Install the JS Eyes browser extension separately from GitHub Releases or the website.\n2. **Make sure the host has a token to share**: confirm `~/.js-eyes/runtime/server.token` exists (Windows: `%USERPROFILE%/.js-eyes/runtime/server.token`). If it doesn't, run `js-eyes server token init`, or start OpenClaw / `js-eyes server start` once so the server's `ensureToken()` creates it. Without this file the native host returns `token-missing` and the popup sync silently falls back to manual paste.\n3. (Preferred, 2.4.0+) Run the local launcher `bin/js-eyes-native-host-install.sh --browser all` (macOS/Linux) or `./bin/js-eyes-native-host-install.ps1 -Browser all` (Windows) — equivalent to `node apps/cli/bin/js-eyes.js native-host install --browser all`; this never contacts the npm registry. Since 2.6.3 the launcher also runs `js-eyes server token init` for you (skip with `--skip-token-init` / `-SkipTokenInit`), so steps 2 and 3 collapse into one command in the common case. `npx js-eyes native-host install --browser all` remains as a fallback but does **not** seed the token — pair it with `npx js-eyes server token init` explicitly. Either path sets up Native Messaging so the extension auto-syncs `server.token` and the HTTP URL; **restart the browser (or reload the extension)** so it picks up the new manifest, then open the popup and click **Sync Token From Host**.\n4. Manual fallback: open the extension popup, expand **Advanced**, set the server address to `http://<serverHost>:<serverPort>`, paste the output of `js-eyes server token show --reveal` into the **Server Token (2.2.0+)** field, and click `Connect`.\n5. Re-run `openclaw js-eyes status`.\n\nThe browser extension is not bundled inside the main ClawHub skill. It must be installed separately. Connections without a matching server token are rejected unless the operator has set `security.allowAnonymous=true`.\n\n## Authoring A New Extension Skill\n\nWhen the user wants to create a brand-new extension skill (not install / mount an existing one), do not scaffold files from scratch. Guide them through the canonical starter flow:\n\n1. **Copy the reference starter** `examples/js-eyes-skills/js-hello-ops-skill/` to a directory of their choice (typically `~/my-skills/js-<domain>-ops-skill/`). Point out that the starter already ships a working `skill.contract.js`, `package.json`, an `async runtime.dispose()` hook, a sample tool, and a `SKILL.md` frontmatter.\n2. **Rename the three identifiers in lockstep**: `package.json.name`, `SKILL.md` frontmatter `name:`, and `skill.contract.js` → `id` + `name`. Discovery resolves id via `contract.id || pkg.name || path.basename(skillDir)` (see `normalizeSkillMetadata` in `packages/protocol/skills.js`), so mismatches do not break load — but `skillsEnabled.<id>`, `js-eyes skills link/enable/disable <id>`, and log messages all key off whatever the contract finally resolves to. Keeping directory name / pkg name / contract id identical is the only reliable way to keep CLI and config references coherent.\n3. **Read the authoring guides before wiring real logic** — the canonical references are:\n   - `docs/dev/js-eyes-skills/authoring.zh.md` — directory layout, discovery rules, quick-start.\n   - `docs/dev/js-eyes-skills/contract.zh.md` — `skill.contract.js` surface (tools / runtime / `runtime.dispose()` lifecycle).\n   - `docs/dev/js-eyes-skills/deployment.zh.md` — the zero-restart deployment flow the skill will end up in.\n4. **Install local deps** with `npm install` inside the new skill directory so `ws` / `@js-eyes/client-sdk` resolve at load time.\n5. **Mount it zero-restart** with `js-eyes skills link <abs-path>`; the running plugin auto-discovers it within ~300 ms. Iterate on `skill.contract.js` in place — saves are hot-reloaded by the `SkillRegistry` skill-dir watcher; no OpenClaw restart is needed because all skill capabilities route through the single `js-eyes` tool.\n6. **When ready to publish**, decide between contributing it back to the first-party `skills/` directory (registry / ClawHub distribution) or keeping it external via `extraSkillDirs` / `link` forever — both paths are supported and zero-restart after mount.\n\nDo not invent a different layout. Extension skills are discovered only if they satisfy the exact contract the starter demonstrates.\n\n## Dynamic Extension Skills\n\nThe main `js-eyes` bundle ships first-party extension skills under `{baseDir}/skills`. A complete default install enables those bundled skills through `~/.js-eyes/config/config.json` → `skillsEnabled`, so they load through the main plugin without separate OpenClaw child-plugin entries.\n\nBundled first-party skills:\n\n- `js-bilibili-ops-skill`\n- `js-browser-ops-skill`\n- `js-github-ops-skill`\n- `js-hn-ops-skill`\n- `js-jike-ops-skill`\n- `js-reddit-ops-skill`\n- `js-wechat-ops-skill`\n- `js-x-ops-skill`\n- `js-xiaohongshu-ops-skill`\n- `js-youtube-ops-skill`\n- `js-zhihu-ops-skill`\n\nThere are two complementary discovery surfaces — pick the right one when the user asks \"what skills do I have?\":\n\n- **Local / installed view** (what is actually mounted right now): `js-eyes skills list` from the host shell, or `js-eyes` action `skills/reload` which returns a live diff. Each entry carries a `Source: primary` vs `Source: extra (<path>)` annotation.\n- **Registry / installable view** (what could be installed from `skills.json`): `js-eyes` action `skills/discover`. Installed rows are marked `✓ 已安装`, installable rows `○ 未安装`.\n\nAfter the base plugin works:\n\n- Bundled first-party skills should already be enabled by the default host config above; use `js-eyes skills list` or `js-eyes` action `skills/reload` to verify they are loaded.\n- Use `js-eyes` action `skills/discover` to list registry skills when the user wants to install a skill that is not already present in `{baseDir}/skills`, or to compare installed versions with the registry.\n- Use `js-eyes` action `skills/plan-install` to stage a **plan** — 2.2.0+ downloads the bundle, verifies its `sha256` against `skills.json`, and writes `runtime/pending-skills/<id>.json` without installing.\n- Finalize the plan with `js-eyes skills approve <id>`, then enable it with `js-eyes skills enable <id>`.\n- Use `js-eyes skills verify` (or `js-eyes doctor`) to confirm `.integrity.json` still matches the on-disk skill files.\n- Since 2026-04-19 the main plugin **hot-loads** newly enabled or linked skills (and hot-disposes disabled ones) via `SkillRegistry` + a chokidar watcher on the host config — no OpenClaw restart needed. For external custom skills, prefer `js-eyes skills link <abs-path>` / `js-eyes skills unlink <abs-path>`; to force a refresh, call `js-eyes skills reload` or have the agent invoke `js-eyes` action `skills/reload` (it returns an `added` / `removed` / `reloaded` / `toggledOff` / `conflicts` diff).\n\n### Skill Lifecycle Cheat Sheet\n\nUse this table to pick the correct command for any user intent. All rows are zero-restart unless otherwise noted.\n\n| Intent | Registry skill (shipped in `skills.json`) | External skill (arbitrary directory on disk) |\n|---|---|---|\n| Inspect what is installed locally | `js-eyes skills list` | same (entries annotated `Source: extra (<path>)`) |\n| Browse what can be installed | `js-eyes` action `skills/discover` | N/A (externals are out-of-registry by definition) |\n| Install / mount | `js-eyes` action `skills/plan-install` → `js-eyes skills approve <id>` → `js-eyes skills enable <id>` | `js-eyes skills link <abs-path>` (auto-enables on first discovery) |\n| Upgrade to the latest registry version | `js-eyes skills update <id>` (preserves `skillsEnabled`, honors `minParentVersion`); `js-eyes skills update --all` for every primary-source skill; rerunning `curl … \\| JS_EYES_SKILL=<id> bash` works too | N/A — externals are managed in their source tree; pull/rebuild there |\n| Temporarily stop without removing | `js-eyes skills disable <id>` — `runtime.dispose()` fires, tools stop responding, files stay on disk | `js-eyes skills disable <id>` (works the same; the `link` path stays in `extraSkillDirs`) |\n| Re-enable | `js-eyes skills enable <id>` | `js-eyes skills enable <id>` |\n| Replace / edit in place | Edit `{baseDir}/skills/<id>/skill.contract.js` and save — picked up by the skill-dir watcher, or call `js-eyes skills reload` | Same, against the external directory |\n| Verify integrity | `js-eyes skills verify [<id>]` — checks `.integrity.json` | N/A — integrity manifests only exist for registry installs |\n| Remove / uninstall | **The CLI intentionally has no `uninstall` subcommand.** Soft-remove: `js-eyes skills disable <id>` (recommended). Hard-remove: after disable, delete `{baseDir}/skills/<id>/` manually, then optionally clear the `skillsEnabled.<id>` key from `~/.js-eyes/config/config.json` to keep it tidy. | `js-eyes skills unlink <abs-path>` — removes the path from `extraSkillDirs` and hot-unloads every skill that was sourced from it |\n| Force a re-scan | `js-eyes skills reload` or `js-eyes` action `skills/reload` | Same |\n\nThe agent SHOULD execute these commands directly when it has shell access. If it does not (read-only / \"ask\" mode), it SHOULD print the exact command for the user to run and then re-verify via `js-eyes skills list` or `js-eyes` action `skills/reload` afterwards.\n\nDo not instruct the user to register child-skill plugin paths manually. Child skills no longer ship their own `openclaw-plugin` wrappers.\n\nPrefer the built-in install flow over manual zip extraction when the user wants additional JS Eyes capabilities.\n\n## Troubleshooting\n\n### `Cannot find module 'ws'`\n\nRun `npm install` in `{baseDir}`. The bundle expects dependencies to be installed from the skill root.\n\n### `js-eyes` tool does not appear\n\nCheck:\n\n1. `plugins.load.paths` points to `{baseDir}/openclaw-plugin`.\n2. `plugins.entries[\"js-eyes\"].enabled` is `true`.\n3. `tools.alsoAllow` or `tools.allow` includes `js-eyes`.\n4. For items 1-3 (OpenClaw-level plugin config), OpenClaw has been restarted or refreshed since the config change — the plugin module itself is loaded once per OpenClaw process. **Skill-level** changes (`skillsEnabled.<id>`, `extraSkillDirs`, edits to a `skill.contract.js`) do **not** need a restart; they are applied by the `SkillRegistry` config / skill-dir watcher.\n5. If this is an extension skill, confirm it is not disabled in the JS Eyes host config (`skillsEnabled.<id>: true`) and that legacy OpenClaw child-plugin entries are removed.\n\n### Custom Extension Skill Not Picked Up\n\nFor a custom external skill mounted via `js-eyes skills link <abs-path>` where no `skill/<id>/<action>` actions work and the log has no `Loaded local skill \"<id>\"` / `Hot-loaded skill \"<id>\"` line, check in order:\n\n1. **Path actually landed in config**: `~/.js-eyes/config/config.json` → `extraSkillDirs` contains the path; `skillsEnabled[\"<id>\"]` is `true`.\n2. **Skill is self-contained**: `cd <abs-path> && ls skill.contract.js package.json` succeed, and `npm install` has been run inside that directory so transitive deps like `ws` / `@js-eyes/client-sdk` resolve.\n3. **Contract actually loads**: the gateway log contains no `Failed to load skill \"<id>\"` entry; if it does, the error message identifies the offending `require` or syntax issue. Fix in place and call `js-eyes skills reload` (or `js-eyes` action `skills/reload`) — no OpenClaw restart needed.\n4. **Id conflict with primary**: look for `Skipping extra skill ... same id already loaded from primary`. Primary wins by design; rename the custom skill's `id` in its `package.json` / `skill.contract.js` or move it into primary.\n5. **Plugin is running an outdated version** (after a `git pull` / upgrade but before restart): the running plugin may predate the single-tool router. In the gateway log look for `[js-eyes] Watching host config: ...` and verify OpenClaw exposes only `js-eyes`; if not, restart OpenClaw **once** to pick up the new plugin code; subsequent skill changes stay zero-restart.\n\n### Browser Extension Stays Disconnected\n\nCheck:\n\n1. `openclaw js-eyes status`\n2. `serverHost` / `serverPort` in plugin config\n3. The extension popup server URL\n4. Whether `autoStartServer` is `true`\n5. (2.2.0+) The popup **Server Token** field matches `js-eyes server token show --reveal`. On 2.4.0+ installs, prefer re-running the popup's **Sync Token From Host** button (powered by the Native Messaging host — see `docs/native-messaging.md`). Tail `logs/audit.log` via `js-eyes audit tail` — `conn.reject` with `reason: token` or `reason: origin` points to token/Origin mismatches.\n6. **`Sync Token From Host` reports `token-missing`**: the manifest is registered but `~/.js-eyes/runtime/server.token` doesn't exist yet. Either run `js-eyes server token init` (idempotent), start OpenClaw / `js-eyes server start` once so `ensureToken()` creates it, or re-run the local launcher `bin/js-eyes-native-host-install.sh` / `.ps1` (2.6.3+ seeds the token automatically). Tail `~/.js-eyes/logs/native-host.log` to confirm — a `get-config: token-missing` line on every popup click is the smoking gun.\n7. **`Sync Token From Host` does nothing / errors with `Could not establish connection`**: the manifest isn't actually registered for this browser, or the browser was open before `native-host install` ran. Re-run `node apps/cli/bin/js-eyes.js native-host status` to confirm the manifest + launcher exist for the right browser, then **fully restart the browser (not just reload the extension)** so it re-scans the NativeMessagingHosts directory.\n\n### Sensitive Tool Calls Hang Without Output (2.2.0+)\n\n`execute_script*`, `get_cookies*`, `upload_file*`, `inject_css`, and `install_skill` default to the `confirm` policy and wait for operator approval.\n\n1. `js-eyes consent list` to see pending requests.\n2. `js-eyes consent approve <id>` or `js-eyes consent deny <id>` to resolve.\n3. To disable the gate for a specific tool, set `security.toolPolicies.<tool>=allow` in `config.json` (logs an audit event).\n\n### Open URL or automation tools fail with egress / policy messages (2.3.0+)\n\nIf `js_eyes_open_url` or other browser tools return text mentioning **pending-egress**, **出站策略**, or **POLICY_SOFT_BLOCK**, the server applied the policy engine **before** the extension ran the action (navigation may never reach the browser).\n\n1. Run `js-eyes security show` and inspect `egressAllowlist` and `taskOrigin` (hosts must be in static allowlist, session scope, or task-origin scope — see `SECURITY.md` Policy Engine).\n2. Run `js-eyes egress list`; use `js-eyes egress approve <id>` for a queued host or `js-eyes egress allow <domain>` to append to `security.egressAllowlist`.\n3. If you rely on **active-tab** scope, call `js-eyes` with `action: browser/get-tabs` (or ensure the automation client has seeded tab state) so the active tab's host is in scope before opening URLs on that host.\n\nThis is separate from **consent** (`js-eyes consent …`) and from extension disconnect issues.\n\n### Skill Fails to Load With Integrity Error (2.2.0+)\n\nThe main plugin refuses to register skills whose files no longer match `.integrity.json`.\n\n1. `js-eyes skills verify <id>` to see which files drifted.\n2. Re-install: `js-eyes skills install <id>` → `js-eyes skills approve <id>` → `js-eyes skills enable <id>`.\n3. If the drift was expected (manual patch), re-generate the manifest by reinstalling; do not edit `.integrity.json` by hand.\n\n### Custom OpenClaw Config Location\n\nAlways resolve `OPENCLAW_CONFIG_PATH`, `OPENCLAW_STATE_DIR`, and `OPENCLAW_HOME` before editing config or telling the user where to look.\n\n## Notes For The Agent\n\n- Prefer performing the setup steps for the user instead of only explaining them.\n- Modify existing OpenClaw config carefully; preserve unrelated plugin entries.\n- For plugin setup, edit JSON directly rather than asking the user to do it manually unless you are blocked by permissions.\n- Once setup is complete, switch from installation guidance to normal use of `js_eyes_*` tools.\n\nFile v2.9.0:_meta.json\n\n{\n  \"ownerId\": \"kn70g9r4pqpqeckej65c2fznk981vvq3\",\n  \"slug\": \"js-eyes\",\n  \"version\": \"2.9.0\",\n  \"publishedAt\": 1784892122080\n}\n\nFile v2.9.0:SECURITY.md\n\n# Security and Network Behavior\n\n> **2.8.3 note**: This document covers the runtime security posture (network\n> behavior, token handling, policy engine, consent ledger, supply-chain\n> hardening since 2.2.0). For the per-finding response to the\n> [ClawHub Security Scan](https://clawhub.ai/imjszhang/js-eyes) of v2.6.1,\n> see [`SECURITY_SCAN_NOTES.md`](./SECURITY_SCAN_NOTES.md); for the one-screen\n> operator summary (risk item / current default / how to tighten / config\n> switch / verify) see the [Security Posture table in `README.md`](./README.md#security-posture-280).\n> A local reproduction of the ClawHub static heuristic is available via\n> `npm run scan:security` (zero unexpected findings on 2.6.3 — the 2.6.3\n> changes are install-time UX only and do not touch the runtime callsites\n> tracked by the scan).\n\n## Reporting a vulnerability\n\nUse GitHub's private vulnerability reporting flow from the repository's **Security** tab. Include the affected component and version or commit, reproduction steps, expected and observed impact, and any known mitigation.\n\nDo not open a public issue for a suspected vulnerability or disclose it before a fix or coordinated disclosure plan is available. Routine dependency updates and non-sensitive bugs can use normal GitHub issues.\n\n## Overview\n\nJS Eyes is a **local-first** browser automation stack. Its normal runtime loop talks only to the JS Eyes server you configure, which defaults to `localhost:18080`.\n\nThere are two deployment shapes to keep in mind:\n\n- **ClawHub / bundle deployment:** install the JS Eyes bundle, run `npm install` in the bundle root, register `openclaw-plugin`, and allow the plugin tools in OpenClaw.\n- **Source-repo / development deployment:** clone this repository, run `npm install` in the repo root, point OpenClaw at the repo-root `openclaw-plugin`, and optionally load the unpacked browser extension directly from `extensions/chrome/` or `extensions/firefox/`.\n\nThose two modes share the same local runtime behavior, but the source repository also contains release tooling, docs, site assets, and extension source files that reference public URLs for packaging and documentation workflows.\n\n## Complete OpenClaw Deployment Notes\n\nA complete local OpenClaw deployment needs all of the following:\n\n- `plugins.load.paths` points to the bundle or repo-root `openclaw-plugin` directory.\n- `plugins.entries[\"js-eyes\"].enabled` is `true`.\n- `tools.alsoAllow: [\"js-eyes\"]` or an equivalent `tools.allow` entry is present, because `js-eyes` registers optional plugin tools.\n- The browser extension is configured to connect to the chosen `serverHost` / `serverPort`.\n\nWithout the tool allowlist step, the plugin can load successfully while `js_eyes_*` tools still remain unavailable to the model.\n\n## Runtime Network Behavior\n\nBase runtime behavior:\n\n- **OpenClaw plugin:** connects via WebSocket to `ws://serverHost:serverPort` and uses HTTP only for JS Eyes server endpoints such as `/api/browser/status` and `/api/browser/tabs`.\n- **Client SDK and browser extension:** connect only to the JS Eyes server URL you configure.\n- **Server:** listens on a single HTTP+WebSocket port and does not need outbound internet access for the core browser automation loop.\n\nBy default this is all local traffic. No browser content is sent to a third-party service unless you explicitly point JS Eyes at a remote server you control.\n\n## Browser Native Messaging Host (Token Auto-Sync)\n\nJS Eyes 2.4+ ships an optional Native Messaging host (`com.js_eyes.native_host`) that lets the browser extension read `~/.js-eyes/runtime/server.token` directly, avoiding manual copy-paste.\n\n**Threat model**: this feature is designed to defend against **external web-page / cross-origin attackers** only. A compromised local device (root, malicious local process, malicious locally-loaded extension) is **explicitly out of scope** — any attacker with local code execution already has direct read access to `server.token`.\n\nSimplifications driven by this scoped threat model:\n\n- No in-extension secondary confirmation prompt.\n- No handshake / nonce / device-fingerprint binding.\n- The host simply returns the token when the browser calls it.\n\nTrust boundaries that remain in place:\n\n- Native messaging manifests whitelist specific extension IDs (Chrome: `allowed_origins`, Firefox: `allowed_extensions`) — unlisted extensions cannot launch the host.\n- The host only reads a fixed path (`~/.js-eyes/runtime/server.token`) and accepts only two messages (`ping`, `get-config`).\n- Extensions never expose the token through `externally_connectable`, so ordinary web pages cannot read it.\n- The Chrome manifest pins a stable extension ID via a `key` field so the allowlist stays authoritative after rebuilds.\n\nSee [docs/native-messaging.md](./docs/native-messaging.md) for install/uninstall commands and file-system paths.\n\n## Explicitly User-Initiated Network Access\n\nSome features intentionally access external URLs, but only when the user or agent explicitly chooses those workflows:\n\n- **Extension skill discovery/install:** `js-eyes` actions `skills/discover` and `skills/plan-install`, plus the install scripts, may fetch the configured registry URL such as `https://js-eyes.com/skills.json`.\n- **Release, docs, and packaging workflows in the source repo:** development tooling may reference GitHub Releases, project websites, Cloudflare deployment targets, Mozilla AMO, or similar public endpoints.\n- **Browser automation targets:** once connected, JS Eyes can automate whatever websites the user asks it to open; that traffic is the intended workload, not telemetry.\n\nThese are different from hidden analytics or call-home behavior. They happen only when the corresponding feature is invoked.\n\n## Why VirusTotal May Flag JS Eyes\n\nStatic analysis tools, including VirusTotal Code Insight, often flag projects that:\n\n- use `fetch()` or `WebSocket`\n- build URLs dynamically, such as `http://${host}:${port}/api/...`\n- expose an API or automation surface\n- include installer scripts or release/download URLs in the repository\n\nIn JS Eyes, those patterns map to local browser automation, optional skill installation, or developer-facing release workflows. They are not used for silent telemetry or covert outbound control.\n\n## ClawHub Bundle vs Full Repository\n\nThe ClawHub-distributed skill bundle is narrower than the full source repository:\n\n- **Included in the bundle:** the runtime pieces needed for JS Eyes skill/plugin behavior.\n- **Not shipped in the ClawHub bundle:** browser extension source, most docs, tests, and release/publishing tooling.\n\nThat means a scan of the full repository can surface external URLs that are irrelevant to the base ClawHub runtime package.\n\n## If ClawHub Shows a VirusTotal Warning\n\n- **Review the behavior in context:** the most common triggers are the local automation patterns above, not remote-control malware behavior.\n- **Report a false positive:** use the [VirusTotal false positive process](https://docs.virustotal.com/docs/false-positive) for the specific vendor(s) that flagged the file.\n- **Use manual review when needed:** if you maintain an internal allowlist or review process for OpenClaw/ClawHub skills, JS Eyes is a good candidate for a reviewed exception because its behavior is inspectable and mostly local-first.\n\n## Dependencies\n\n- **Core runtime dependency:** `ws` is required for WebSocket communication.\n- **Full development repository:** includes additional packages, build tools, docs, and browser extension assets needed for local development and release workflows.\n\n## Supply Chain Hardening (2.2.0+)\n\nJS Eyes 2.2.0 treats skill packages as untrusted inputs that must be validated end-to-end before they reach disk or are loaded into the runtime.\n\n- **Registry metadata carries integrity data.** Every entry in `dist/skills.json` now ships with `sha256` and `size`. The CLI (`js-eyes skills install`), the OpenClaw `js-eyes` action `skills/plan-install`, and `install.sh` / `install.ps1` all refuse to install a skill whose downloaded bundle does not match the expected digest.\n- **`@main` fallback URLs are refused.** The installers strip any registry fallback URL that resolves to a mutable `@main` / `refs/heads/main` CDN path. Bundles must be served from an immutable tag, release, or commit pinned URL.\n- **Safe ZIP extraction.** `packages/protocol/zip-extract.js` replaces `execSync unzip` / PowerShell `Expand-Archive` with an in-process ZIP reader that rejects Zip Slip, symlinks, and oversized entries (`maxFileSize`, `maxTotalSize`, `maxEntries`).\n- **Lockfile + `npm ci --ignore-scripts`.** `installSkillDependencies` requires `package-lock.json` and runs `npm ci --ignore-scripts --no-audit --no-fund`. The flag `security.requireLockfile=false` (or `JS_EYES_REQUIRE_LOCKFILE=0` in the install scripts) can be used to relax this during migration; doing so prints a prominent warning.\n- **Plan → approve installation.** `js-eyes skills install --plan` stages the extracted bundle in a temporary directory and writes a plan JSON to `runtime/pending-skills/<skillId>.json`. The install is only applied after `js-eyes skills approve <skillId>`. `js-eyes` action `skills/plan-install` inside OpenClaw likewise produces a plan and requires an out-of-band approval via the CLI.\n- **Runtime integrity pinning.** Every installed skill gets a `.integrity.json` manifest that records SHA-256 for each file. `registerLocalSkills` refuses to load a skill with mismatched/missing files. `js-eyes skills verify` and `js-eyes doctor` surface tamper indicators.\n- **Skills default disabled on upgrade.** `isSkillEnabled` returns `false` unless explicitly opted in via `skillsEnabled.<id>=true`. When upgrading from 2.1.x, existing skills without an explicit setting are left disabled and a warning is logged with instructions to `js-eyes skills enable <id>`.\n\n## Local Server Authentication (2.2.0+)\n\nThe local JS Eyes server no longer treats every localhost client as trusted.\n\n- **Bearer tokens.** On first start (or via `js-eyes server token init`) the server writes a random token to `runtime/server.token` (POSIX `chmod 0600`; on Windows, `icacls` restricts to the current user). Clients send the token via one of:\n  - HTTP `Authorization: Bearer <token>`\n  - WebSocket subprotocol header `Sec-WebSocket-Protocol: bearer.<token>, js-eyes` (browser extension) or `jse-token.<token>` (SDK)\n  - URL query parameter `?token=<token>` (legacy/custom loopback-only fallback; logged to the audit trail)\n  Tokens can be rotated with `js-eyes server token rotate`.\n- **Origin whitelist and CORS.** HTTP and WebSocket upgrades require an `Origin` from `security.allowedOrigins`. The defaults cover the bundled browser extensions, `http://localhost:18080`, and `http://127.0.0.1:18080`. `Access-Control-Allow-Origin` now echoes the caller only when it is on the whitelist; `*` is no longer returned.\n- **Loopback binding.** The server refuses to bind to a non-loopback host unless `security.allowRemoteHost=true`. When bound to a public address, a warning is logged and audited.\n- **`allowAnonymous` compatibility switch.** For clients that cannot yet send a token (for example, older DeepSeek Cowork installs), the operator can set `security.allowAnonymous=true`. Anonymous connections are marked in the audit log and in `js-eyes doctor`. This is explicitly a migration crutch: the log line reads `[js-eyes] WARNING: allowAnonymous=true; server accepts unauthenticated WS/HTTP clients`.\n- **Structured audit log.** Connection events, skill installs, config edits, and sensitive tool calls are written as JSONL to `logs/audit.log` with `chmod 0600`. `js-eyes audit tail` streams the last entries; sensitive values (cookies, script bodies, tokens) are redacted before being logged.\n- **File permissions.** `config.json`, `runtime/server.token`, `logs/audit.log`, and `runtime/pending-consents/*.json` are created/rewritten with `chmod 0600` (best-effort `icacls` on Windows).\n\n## Sensitive Tool Consent (2.2.0+)\n\nBuilt-in and skill-provided tools that can exfiltrate or mutate browser state are now routed through a consent gateway before execution.\n\n- **Sensitive action set.** `protocol.SENSITIVE_TOOL_NAMES` currently contains `browser/execute-script`, `browser/get-cookies`, `browser/get-cookies-by-domain`, `browser/upload-file`, `browser/inject-css`, and `skills/plan-install`. Additional actions can be added via `security.toolPolicies`.\n- **Policy modes.** Each sensitive tool resolves to one of `allow`, `confirm`, or `deny`. The OpenClaw plugin's `wrapSensitiveTool` records every decision to `runtime/pending-consents/<id>.json` (JSONL-friendly) and logs a structured warning. `deny` short-circuits execution and returns a rejection payload to the calling agent. `confirm` currently emits an auto-confirmation log entry and records the decision so operators can review it; future versions will block until an operator runs `js-eyes consent approve <id>`.\n- **Extension-side eval lockdown.** `handleExecuteScript` / `handleExecuteScriptRequest` (Chrome MV3 + Firefox MV2) reject raw JavaScript payloads unless `securityConfig.allowRawEval=true`. Starting with v2.5+, the extension no longer requires an independent config toggle: the host's `security.allowRawEval` is pushed down at WebSocket handshake (`init_ack.serverConfig.security.allowRawEval`) and applied automatically. The extension storage key `allowRawEval` is retained as an explicit **opt-out override** for security-hardened deployments: if an operator sets it explicitly via `chrome.storage.local.set({allowRawEval:false})` (or `true`), that value wins over the host-synced value. Chrome executes approved arbitrary source through its isolated `userScripts` world (Chrome 135+), rather than CSP-blocked extension `eval`; Chrome 138+ also requires the browser-controlled **Allow User Scripts** toggle. `RAW_EVAL_DISABLED` and `USER_SCRIPTS_UNAVAILABLE` let callers degrade gracefully.\n- **Consent log review.** Operators should periodically review `runtime/pending-consents/*.json` and the JSONL entries in `logs/audit.log`. `js-eyes consent list` summarizes recent decisions; `js-eyes consent approve <id>` / `js-eyes consent deny <id>` mark pending entries for audit.\n- **Server-supplied token propagation.** The browser extension popup exposes a \"Server Token\" field that is persisted in `chrome.storage.local`. The background service worker forwards the token as `Sec-WebSocket-Protocol: bearer.<token>` and does not duplicate it into the WebSocket URL. The server still accepts the loopback query form for older/custom clients.\n\n## Policy Engine (2.3.0+)\n\nStarting with 2.3.0 JS Eyes ships a declarative, non-interactive policy engine that sits between any tool caller (OpenClaw plugin, CLI, skill code, external agent) and the browser. It is tuned to defuse **prompt-injection-driven misuse** without relying on synchronous `confirm` dialogs.\n\n### Layers\n\n- **L4a — Same-Origin Task (`TaskOriginTracker`).** Merges a scope set from four sources: user messages (URLs / bare domains), `skill.contract.runtime.platforms`, the current active tab URL, and links found on HTML that the agent has already fetched. `getCookies` / `getCookiesByDomain` / `executeScript` / `injectCss` / `uploadFileToTab` are evaluated against this scope.\n- **L4b — Lightweight Taint (`TaintRegistry`).** Every cookie value returned by `getCookies*` is tagged with an 8-byte canary (`__canary: \"jse-c-<hex>\"`) and registered. Subsequent sink parameters (`openUrl`, `uploadFileToTab`, `executeScript`, `injectCss`) are scanned for the canary or common-encoded cookie-value variants. Hits are soft-blocked and audited as `reason: 'taint-hit'`.\n- **L5 — Egress Allowlist (`EgressGate`).** `openUrl` targets must be in: the task origin scope, `security.egressAllowlist` (static config), or the session allowlist (populated by prior approvals / explicit user-message URLs). Unmatched targets write a `runtime/pending-egress/<uuid>.json` record and return `{ status: 'pending-egress' }`; the browser extension never sees the navigation.\n- **L6 — Rule Engine Location.** The engine lives in `@js-eyes/client-sdk/policy` so that skills and the OpenClaw plugin share one implementation. `@js-eyes/server-core/ws-handler` re-instantiates the same engine to cover raw WebSocket callers (external agents that bypass `client-sdk`).\n\n### Enforcement Levels\n\n- `off` — audit only (no blocking, no pending-egress). Useful for troubleshooting false positives.\n- `soft` (default) — violating calls are not executed; `openUrl` returns `pending-egress`, other sinks return `POLICY_SOFT_BLOCK`. Agents observe the decision and can re-plan.\n- `strict` — same as `soft` but with escalation paths closed (cookie-canary hits never pass, taint values never traverse sinks).\n\nEnvironment and config overrides: `JS_EYES_POLICY_ENFORCEMENT`, `config.security.enforcement`, `js-eyes security enforce <level>`.\n\n### Operator Tooling\n\n- `js-eyes security show` prints the resolved policy (enforcement level, task-origin sources, egress allowlist, taint mode).\n- `js-eyes egress list|approve <id>|allow <domain>|clear` manages pending-egress plans and session/static allowlists.\n- `js-eyes doctor` reports enforcement mode, pending-egress backlog, last soft-block event, top-3 blocked tool/rule pairs, and skills whose `runtime.platforms` is `['*']`.\n- `logs/audit.log` carries `rule_decision`, `task_origin`, `taint_hit`, `egress_matched`, `enforcement`, `rule`, `reasons`, and `pendingId` for every policy-related event.\n\n### HTTP Response Hardening\n\n`packages/server-core` now emits `Content-Security-Policy: default-src 'none'; frame-ancestors 'none'`, `X-Content-Type-Options: nosniff`, `X-Frame-Options: DENY`, `Referrer-Policy: no-referrer`, and `Permissions-Policy: interest-cohort=()` on every HTTP response. This closes the Chrome `externally_connectable` surface against any future accidental HTML response on port 18080.\n\n### Non-Goals (2.5.x)\n\n- Interactive `confirm` dialogs (still excluded by design).\n- Task profiles (L3) and reader sub-agent (L5') — remain opt-in additions on the roadmap and stay off by default.\n\n## Host-Synced `allowRawEval` (2.5.1+)\n\nHistorically, enabling raw `execute_script` required flipping `security.allowRawEval=true` on the host **and** manually seeding `chrome.storage.local.allowRawEval=true` on the extension (no popup UI exposed the latter), so the host-side toggle was effectively a no-op in practice. Starting with 2.5.1:\n\n- The host pushes `security.allowRawEval` to the browser extension via `init_ack.serverConfig.security.allowRawEval` at WebSocket handshake; the extension applies the value automatically.\n- The extension storage key `allowRawEval` is retained as an explicit **opt-out override** — set it to `true` or `false` via `chrome.storage.local.set({allowRawEval:false})` (or `true`) to pin the extension regardless of the host. Useful for security-hardened deployments that want to force-disable raw eval even if the host flips it on.\n- Everyday users only need to touch `~/.js-eyes/config/config.json`. Restart the server / OpenClaw after changing it so the extension picks up the new value on the next reconnect.\n\n## Security Config Hot-Reload (2.5.2+)\n\nA small whitelist of `security.*` fields can now be swapped into the running JS Eyes server **without** restarting OpenClaw or the server. Server-core ships its own chokidar watcher on `~/.js-eyes/config/config.json` (separate from the plugin's skill watcher) plus a `server.reloadSecurity()` handle that the built-in `js_eyes_reload_security` tool calls on demand.\n\n- **Hot-reloadable** (swap takes effect on the next automation call, ~300 ms from fs write; also immediately via `js_eyes_reload_security`): `security.egressAllowlist`, `security.toolPolicies`, `security.sensitiveCookieDomains`, `security.allowedOrigins`, `security.enforcement`.\n- **Not hot-reloadable — server restart required** (changing these appears under `ignored` in the reload summary, with a one-line warning in the gateway log): `serverHost`, `serverPort`, `allowAnonymous`, `allowRemoteBind`, `allowRawEval`, `requireLockfile`, and anything outside `security.*` (token rotation, `requestTimeout`, etc.).\n- **Caveat — session-level egress approvals reset**: when the allowlist flips, each live automation connection rebuilds its `PolicyContext`, which means per-session `js-eyes egress approve <id>` grants are dropped. Agents re-issue the approval on the next `pending-egress` response; no action needed for standard `allow <domain>` edits because those are part of the static allowlist and get picked up automatically.\n- **Operator triggers** (any one is sufficient):\n  1. Edit `~/.js-eyes/config/config.json` and save — chokidar debounces 300 ms and fires `reloadSecurity({ source: 'fs-watch' })`.\n  2. Agent call: `js_eyes_reload_security` built-in tool (returns `{ changed, applied, ignored, generation, egressAllowlist }`).\n  3. CLI preview: `js-eyes security reload` — read-only dry run that prints what would be applied (CLI does not own the server event loop, so trigger #1 or #2 is required for the actual swap).\n- **Observability**: the audit log (`~/.js-eyes/logs/audit.log`) gains three new events — `config.hot-reload`, `config.hot-reload.error`, `automation.policy-rebuilt` — and `GET /api/browser/status` now includes `data.policy.generation` / `data.policy.egressAllowlist` so operators can externally confirm the live generation.\n\n---\n\n*Last updated: 2026-04-21 — covers the 2.3.0 policy engine, 2.4.0 Native Messaging host, 2.5.1 host-synced `allowRawEval`, and 2.5.2 security config hot-reload.*\n\nFile v2.9.0:skill-card.md\n\n## Description: <br>\nInstall, configure, verify, and troubleshoot JS Eyes browser automation for OpenClaw. <br>\n\nThis skill is ready for commercial/non-commercial use. <br>\n\n## Publisher: <br>\n[imjszhang](https://clawhub.ai/user/imjszhang) <br>\n\n### License/Terms of Use: <br>\nMIT-0 <br>\n\n\n## Use Case: <br>\nDevelopers and operators use this skill to install, configure, verify, and troubleshoot JS Eyes browser automation in OpenClaw, including plugin registration, browser extension connection, and extension-skill lifecycle workflows. <br>\n\n### Deployment Geography for Use: <br>\nGlobal <br>\n\n## Known Risks and Mitigations: <br>\nRisk: JS Eyes gives OpenClaw high-impact control over browser tabs, page content, cookies, script execution, and dynamically loaded skills. <br>\nMitigation: Install it only for intended browser automation deployments, keep the server bound to localhost, require token authentication, and review consent prompts and audit logs before approving sensitive actions. <br>\nRisk: Raw JavaScript execution can increase exposure when automating a real browser profile. <br>\nMitigation: Leave allowRawEval disabled unless raw script execution is required, and enable it only for trusted workflows after reviewing the requested action. <br>\nRisk: Linked or installed extension skills can extend browser automation behavior and introduce supply-chain risk. <br>\nMitigation: Prefer staged skill discovery, install, and approve flows; inspect external skills before linking; and keep integrity checks enabled for installed skills. <br>\nRisk: Remote binding or anonymous access can expose the local automation server beyond the intended operator. <br>\nMitigation: Keep allowAnonymous false, avoid non-loopback binding unless explicitly required, rotate tokens when needed, and verify posture with js-eyes doctor. <br>\n\n\n## Reference(s): <br>\n- [ClawHub Skill Page](https://clawhub.ai/imjszhang/skills/js-eyes) <br>\n- [Publisher Profile](https://clawhub.ai/user/imjszhang) <br>\n- [JS Eyes Homepage](https://github.com/imjszhang/js-eyes) <br>\n- [Security and Network Behavior](SECURITY.md) <br>\n\n\n## Skill Output: <br>\n**Output Type(s):** [Guidance, Shell commands, Configuration, Code] <br>\n**Output Format:** [Markdown with inline shell commands and JSON configuration snippets] <br>\n**Output Parameters:** [1D] <br>\n**Other Properties Related to Output:** [May include OS-specific OpenClaw and JS Eyes setup, verification, and troubleshooting steps.] <br>\n\n## Skill Version(s): <br>\n2.9.0 (source: server release metadata and package.json) <br>\n\n## Ethical Considerations: <br>\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment. <br>\n\nFile v2.9.0:openclaw-plugin/openclaw.plugin.json\n\n{\n  \"id\": \"js-eyes\",\n  \"activation\": {\n    \"onStartup\": true\n  },\n  \"name\": \"JS Eyes\",\n  \"description\": \"浏览器自动化工具 — 通过 WebSocket 为 AI Agent 提供远程浏览器控制能力（标签页管理、内容获取、脚本执行等）\",\n  \"version\": \"2.9.0\",\n  \"contracts\": {\n    \"tools\": [\n      \"js-eyes\"\n    ]\n  },\n  \"toolMetadata\": {\n    \"js-eyes\": {\n      \"optional\": true\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"serverHost\": {\n        \"type\": \"string\",\n        \"default\": \"localhost\",\n        \"description\": \"JS-Eyes 服务器监听地址\"\n      },\n      \"serverPort\": {\n        \"type\": \"number\",\n        \"default\": 18080,\n        \"description\": \"JS-Eyes 服务器端口\"\n      },\n      \"autoStartServer\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"是否随插件加载自动启动内置服务器\"\n      },\n      \"requestTimeout\": {\n        \"type\": \"number\",\n        \"default\": 1800,\n        \"description\": \"浏览器操作请求超时（秒），默认 1800（30 分钟）\"\n      },\n      \"skillsRegistryUrl\": {\n        \"type\": \"string\",\n        \"default\": \"https://js-eyes.com/skills.json\",\n        \"description\": \"扩展技能注册表 URL\"\n      },\n      \"skillsDir\": {\n        \"type\": \"string\",\n        \"default\": \"\",\n        \"description\": \"扩展技能安装目录（空值则使用技能包内的 skills/ 目录）\"\n      },\n      \"extraSkillDirs\": {\n        \"type\": \"array\",\n        \"items\": {\n          \"type\": \"string\"\n        },\n        \"default\": [],\n        \"description\": \"额外只读技能来源（绝对路径列表）。每条可以是单个 V2/V1 技能目录或父目录（扫描 1 层子目录）。同 id 冲突时 primary 优先；可通过 host security.verifyExtraSkillDirs 启用快照校验。\"\n      },\n      \"skills\": {\n        \"type\": \"object\",\n        \"additionalProperties\": {\n          \"type\": \"object\"\n        },\n        \"default\": {},\n        \"description\": \"按技能 ID 配置运行参数；plugins config 覆盖 host config 中的同名技能配置。\"\n      },\n      \"externalSkills\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"default\": {\n          \"policy\": \"legacy\",\n          \"defaultExecution\": \"worker\"\n        },\n        \"description\": \"外部技能的发现、信任和执行策略。legacy 保持兼容；prompt 要求批准；strict 还要求 V2 静态 Manifest。\",\n        \"properties\": {\n          \"policy\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"legacy\",\n              \"prompt\",\n              \"strict\"\n            ],\n            \"default\": \"legacy\"\n          },\n          \"defaultExecution\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"in-process\",\n              \"worker\"\n            ],\n            \"default\": \"worker\"\n          }\n        }\n      },\n      \"watchConfig\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"通过 chokidar 监听 ~/.js-eyes/config/config.json，配置变更时（含 js-eyes skills link/unlink/enable/disable）零重启热加载技能。\"\n      },\n      \"devWatchSkills\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"开发模式：监听已发现技能目录的文件变更（默认 ~300ms 防抖），改完 skill.contract.js 自动 reload。仅推荐在本地开发用；生产可关闭以减少 fs 监听负载。\"\n      },\n      \"nativeHost\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"default\": {\n          \"autoInstall\": true,\n          \"browser\": \"all\",\n          \"repairStale\": true,\n          \"warnOnly\": false\n        },\n        \"description\": \"浏览器 Native Messaging host 自检/修复配置，用于支持扩展 popup 的“从本机同步 token”。\",\n        \"properties\": {\n          \"autoInstall\": {\n            \"type\": \"boolean\",\n            \"default\": true,\n            \"description\": \"OpenClaw 加载插件时自动检查并安装/修复 JS Eyes Native Messaging host。\"\n          },\n          \"browser\": {\n            \"type\": \"string\",\n            \"default\": \"all\",\n            \"enum\": [\n              \"all\",\n              \"chromium\",\n              \"chrome\",\n              \"chrome-canary\",\n              \"edge\",\n              \"brave\",\n              \"firefox\"\n            ],\n            \"description\": \"要检查/安装的浏览器范围。\"\n          },\n          \"repairStale\": {\n            \"type\": \"boolean\",\n            \"default\": true,\n            \"description\": \"manifest 指向旧 launcher 或允许的扩展 ID 不匹配时自动重写。\"\n          },\n          \"warnOnly\": {\n            \"type\": \"boolean\",\n            \"default\": false,\n            \"description\": \"仅检查并记录日志，不写入 manifest、launcher 或 Windows 注册表。\"\n          }\n        }\n      }\n    }\n  },\n  \"uiHints\": {\n    \"serverHost\": {\n      \"label\": \"服务器地址\",\n      \"placeholder\": \"localhost\",\n      \"help\": \"JS-Eyes WebSocket/HTTP 服务器的监听地址\"\n    },\n    \"serverPort\": {\n      \"label\": \"服务器端口\",\n      \"placeholder\": \"18080\",\n      \"help\": \"JS-Eyes 服务器监听端口，需与浏览器扩展中配置的端口一致\"\n    },\n    \"autoStartServer\": {\n      \"label\": \"自动启动服务器\",\n      \"help\": \"启用后 OpenClaw 启动时自动拉起 JS-Eyes 内置服务器；禁用则需手动启动\"\n    },\n    \"requestTimeout\": {\n      \"label\": \"请求超时（秒）\",\n      \"help\": \"单次浏览器操作的最大等待时间，默认 1800 秒（30 分钟）\",\n      \"advanced\": true\n    },\n    \"skillsRegistryUrl\": {\n      \"label\": \"技能注册表 URL\",\n      \"placeholder\": \"https://js-eyes.com/skills.json\",\n      \"help\": \"扩展技能注册表地址，用于发现和安装扩展技能\",\n      \"advanced\": true\n    },\n    \"skillsDir\": {\n      \"label\": \"技能安装目录\",\n      \"placeholder\": \"\",\n      \"help\": \"扩展技能的安装目录（primary）。留空则自动使用技能包根目录下的 skills/ 子目录。js-eyes skills install/approve/verify 都作用在此目录。\",\n      \"advanced\": true\n    },\n    \"extraSkillDirs\": {\n      \"label\": \"额外只读技能目录\",\n      \"placeholder\": \"[\\\"/Users/you/my-skills\\\"]\",\n      \"help\": \"在 primary 之外纳入外部技能目录。目录保持只读；V2 prompt/strict 需要 trust，且可启用额外目录快照校验。运行中可用 js-eyes skills link/unlink 零重启增删。\",\n      \"advanced\": true\n    },\n    \"skills\": {\n      \"label\": \"技能运行配置\",\n      \"help\": \"按技能 ID 提供 config；插件配置覆盖 ~/.js-eyes/config/config.json 中的同名项。\",\n      \"advanced\": true\n    },\n    \"externalSkills\": {\n      \"label\": \"外部技能策略\",\n      \"help\": \"legacy 保持现有自动启用语义；prompt 要求先批准；strict 仅允许已批准且带 skill.manifest.json 的外部技能。\",\n      \"advanced\": true\n    },\n    \"watchConfig\": {\n      \"label\": \"监听宿主配置\",\n      \"help\": \"默认开启。关闭后 js-eyes skills link/unlink/enable/disable 等会写 ~/.js-eyes/config/config.json 的命令将不再触发自动热加载，需要手动调用 js-eyes skills reload 或通过 js-eyes 工具调用 action=skills/reload。\",\n      \"advanced\": true\n    },\n    \"devWatchSkills\": {\n      \"label\": \"监听技能目录（开发模式）\",\n      \"help\": \"默认开启。监听已发现技能目录里的文件变更，改完 skill.contract.js 自动 reload。生产环境可关闭。\",\n      \"advanced\": true\n    },\n    \"nativeHost\": {\n      \"label\": \"Native Messaging 自动部署\",\n      \"help\": \"默认开启。OpenClaw 启动 JS Eyes 插件时检查并安装/修复浏览器 Native Messaging host，使扩展可以从本机同步 server token。修复后浏览器通常需要完整重启。\",\n      \"advanced\": true\n    }\n  }\n}\n\nFile v2.9.0:openclaw-plugin/package.json\n\n{\n  \"name\": \"js-eyes\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Optional OpenClaw plugin component for JS Eyes\",\n  \"type\": \"module\",\n  \"main\": \"index.mjs\",\n  \"engines\": {\n    \"node\": \">=22.0.0\"\n  },\n  \"files\": [\n    \"index.mjs\",\n    \"openclaw.plugin.json\"\n  ],\n  \"license\": \"MIT\",\n  \"dependencies\": {\n    \"chokidar\": \"^3.6.0\"\n  },\n  \"peerDependencies\": {\n    \"openclaw\": \">=0.0.0\"\n  },\n  \"openclaw\": {\n    \"extensions\": [\n      \"./index.mjs\"\n    ]\n  }\n}\n\nFile v2.9.0:package.json\n\n{\n  \"name\": \"js-eyes-skill-bundle\",\n  \"version\": \"2.9.0\",\n  \"private\": true,\n  \"description\": \"Installable JS Eyes runtime and skill bundle with optional host integrations\",\n  \"workspaces\": [\n    \"packages/*\"\n  ],\n  \"dependencies\": {\n    \"@js-eyes/skill-contract\": \"2.9.0\",\n    \"@js-eyes/client-sdk\": \"2.9.0\",\n    \"@js-eyes/config\": \"2.9.0\",\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\",\n    \"@js-eyes/server-core\": \"2.9.0\",\n    \"@js-eyes/skill-recording\": \"2.9.0\",\n    \"@js-eyes/skill-runtime\": \"2.9.0\",\n    \"@js-eyes/skill-worker\": \"2.9.0\"\n  },\n  \"engines\": {\n    \"node\": \">=22.0.0\"\n  },\n  \"license\": \"MIT\"\n}\n\nFile v2.9.0:packages/client-sdk/package.json\n\n{\n  \"name\": \"@js-eyes/client-sdk\",\n  \"version\": \"2.9.0\",\n  \"description\": \"JS Eyes BrowserAutomation client SDK\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"node --test tests/*.test.js\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"policy/\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/client-sdk\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"sdk\",\n    \"browser-automation\",\n    \"websocket\",\n    \"openclaw\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\",\n    \"ws\": \"^8.19.0\"\n  }\n}\n\nFile v2.9.0:packages/config/package.json\n\n{\n  \"name\": \"@js-eyes/config\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Runtime config helpers for JS Eyes CLI\",\n  \"main\": \"index.js\",\n  \"files\": [\n    \"index.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/config\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"config\",\n    \"cli\",\n    \"runtime\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\"\n  }\n}\n\nFile v2.9.0:packages/protocol/package.json\n\n{\n  \"name\": \"@js-eyes/protocol\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Shared protocol constants for JS Eyes runtime packages\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"node --test tests/*.test.js\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"skills.js\",\n    \"zip-extract.js\",\n    \"fs-io.js\",\n    \"safe-npm.js\",\n    \"extra-integrity.js\",\n    \"skill-registry.js\",\n    \"skill-trust.js\",\n    \"skill-runner.js\",\n    \"registry-client.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/protocol\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"protocol\",\n    \"browser-automation\",\n    \"openclaw\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/skill-contract\": \"2.9.0\"\n  }\n}\n\nFile v2.9.0:packages/runtime-paths/package.json\n\n{\n  \"name\": \"@js-eyes/runtime-paths\",\n  \"version\": \"2.9.0\",\n  \"description\": \"Runtime directories for JS Eyes CLI and services\",\n  \"main\": \"index.js\",\n  \"files\": [\n    \"index.js\",\n    \"token.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/runtime-paths\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"runtime\",\n    \"paths\",\n    \"filesystem\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  }\n}\n\nFile v2.9.0:packages/server-core/package.json\n\n{\n  \"name\": \"@js-eyes/server-core\",\n  \"version\": \"2.9.0\",\n  \"description\": \"JS Eyes HTTP + WebSocket server core\",\n  \"main\": \"index.js\",\n  \"scripts\": {\n    \"test\": \"node --test tests/*.test.js\"\n  },\n  \"files\": [\n    \"index.js\",\n    \"ws-handler.js\",\n    \"audit.js\",\n    \"auth.js\"\n  ],\n  \"license\": \"MIT\",\n  \"author\": \"imjszhang <ortle3x3@gmail.com>\",\n  \"homepage\": \"https://js-eyes.com\",\n  \"repository\": {\n    \"type\": \"git\",\n    \"url\": \"git+https://github.com/imjszhang/js-eyes.git\",\n    \"directory\": \"packages/server-core\"\n  },\n  \"bugs\": {\n    \"url\": \"https://github.com/imjszhang/JS-Eyes/issues\"\n  },\n  \"keywords\": [\n    \"js-eyes\",\n    \"server\",\n    \"websocket\",\n    \"http\",\n    \"browser-automation\"\n  ],\n  \"publishConfig\": {\n    \"access\": \"public\"\n  },\n  \"dependencies\": {\n    \"@js-eyes/client-sdk\": \"2.9.0\",\n    \"@js-eyes/protocol\": \"2.9.0\",\n    \"@js-eyes/runtime-paths\": \"2.9.0\",\n    \"ws\": \"^8.19.0\"\n  }\n}\n\nArchive v2.8.5: 57 files, 129691 bytes\n\nFiles: clients/js-eyes-client.js (67b), openclaw-plugin/actions/browser.mjs (11813b), openclaw-plugin/actions/management.mjs (4281b), openclaw-plugin/actions/skills.mjs (5850b), openclaw-plugin/auth.mjs (1724b), openclaw-plugin/cli-registration.mjs (4493b), openclaw-plugin/fs-utils/hash.mjs (1798b), openclaw-plugin/index.mjs (7657b), openclaw-plugin/lifecycle.mjs (2144b), openclaw-plugin/native-host-setup.mjs (6874b), openclaw-plugin/openclaw.plugin.json (6491b), openclaw-plugin/package.json (453b), openclaw-plugin/registration-context.mjs (1743b), openclaw-plugin/server-service.mjs (2448b), openclaw-plugin/shared-server.mjs (1555b), openclaw...","readmeExcerpt":"Skill: js-eyes Owner: imjszhang Summary: Install, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter. Tags: latest:2.10.0 Version history: v2.10.0 | 2026-07-25T07:32:57.703Z | user - **Package boundaries**: install/trust helpers live in @js-eyes/skill-install; policy primitives live in @js-eyes/policy. Compatibility re-exports under @j","codeSnippets":[],"executableExamples":[{"language":"bash","snippet":"npm install -g js-eyes"},{"language":"bash","snippet":"js-eyes server token init\njs-eyes native-host install --browser all\njs-eyes server start\njs-eyes doctor"},{"language":"bash","snippet":"js-eyes server token show --reveal"},{"language":"json","snippet":"{\n  \"mcpServers\": {\n    \"js-eyes\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@js-eyes/mcp-server\"]\n    }\n  }\n}"},{"language":"json","snippet":"{\n  \"tools\": {\n    \"alsoAllow\": [\"js-eyes\"]\n  },\n  \"plugins\": {\n    \"load\": {\n      \"paths\": [\"/absolute/path/to/js-eyes/openclaw-plugin\"]\n    },\n    \"entries\": {\n      \"js-eyes\": {\n        \"enabled\": true,\n        \"config\": {\n          \"serverHost\": \"localhost\",\n          \"serverPort\": 18080,\n          \"autoStartServer\": true\n        }\n      }\n    }\n  }\n}"},{"language":"bash","snippet":"openclaw plugins inspect js-eyes\nopenclaw js-eyes status"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"SKILL.md","content":"---\nname: js-eyes\ndescription: Install, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter.\nversion: 2.9.0\nmetadata: {\"openclaw\":{\"emoji\":\"\\U0001F441\",\"homepage\":\"https://github.com/imjszhang/js-eyes\",\"os\":[\"darwin\",\"linux\",\"win32\"],\"requires\":{\"bins\":[\"node\"]}}}\n---\n\n# JS Eyes\n\nJS Eyes is a local-first browser capability and site-skill runtime for AI\nagents. A browser extension connects to a local JS Eyes server; CLI, MCP, and\nOpenClaw are peer host surfaces over the same protocol, policy engine, and\nSkill Runtime.\n\nTreat `{baseDir}` as the root of this installed bundle. The optional OpenClaw\nadapter is `{baseDir}/openclaw-plugin`.\n\n## Use this Skill when\n\n- The user wants to install or connect JS Eyes.\n- An MCP or OpenClaw host cannot see JS Eyes tools.\n- The browser extension remains disconnected.\n- A local server, token, browser target, or security policy needs diagnosis.\n- The user wants to discover, inspect, trust, enable, or call a JS Eyes Skill.\n- An external V2 Skill needs to be linked without coupling it to OpenClaw.\n\n## Choose the host surface\n\nUse the smallest surface that fits the request:\n\n1. **CLI** — use `js-eyes` directly for server management, diagnostics, Skill\n   lifecycle, and one-off Skill calls.\n2. **MCP** — use `@js-eyes/mcp-server` for Codex, Claude, Cursor, VS Code, and\n   other local MCP clients.\n3. **OpenClaw** — load `{baseDir}/openclaw-plugin` only when OpenClaw-specific\n   lifecycle and routing are required.\n\nDo not install the OpenClaw adapter merely to use CLI or MCP.\n\n## Requirements\n\n- Node.js 22 or newer.\n- A supported Chrome, Edge, or Firefox extension.\n- A local JS Eyes server, normally at `http://localhost:18080`.\n- A shared server token unless anonymous compatibility mode was explicitly\n  selected.\n\nKeep the server bound to loopback unless the user has deliberately configured\nand secured remote access.\n\n## Standard standalone setup\n\nInstall the public CLI:\n\n```bash\nnpm install -g js-eyes\n```\n\nInitialize a token, register the optional Native Messaging bridge, and start\nthe server:\n\n```bash\njs-eyes server token init\njs-eyes native-host install --browser all\njs-eyes server start\njs-eyes doctor\n```\n\nInstall or load the browser extension, then use its popup to synchronize the\nserver URL and token. If Native Messaging is unavailable, reveal the token only\nfor the local user and paste it into the popup:\n\n```bash\njs-eyes server token show --reveal\n```\n\nNever place the token in documentation, logs, chat output, command arguments\nthat will be shared, or a remote URL.\n\n## MCP setup\n\nThe MCP facade connects lazily to an existing JS Eyes server:\n\n```json\n{\n  \"mcpServers\": {\n    \"js-eyes\": {\n      \"command\": \"npx\",\n      \"args\": [\"-y\", \"@js-eyes/mcp-server\"]\n    }\n  }\n}\n```\n\nThe default `safe` profile exposes browser status, tab, navigation, page-read,\nscreenshot, and read-only Skill Runtime tools. Raw JavaScript, CSS injection,\ncookie acc"},{"path":"_meta.json","content":"{\n  \"ownerId\": \"kn70g9r4pqpqeckej65c2fznk981vvq3\",\n  \"slug\": \"js-eyes\",\n  \"version\": \"2.10.0\",\n  \"publishedAt\": 1784964777703\n}"},{"path":"SECURITY.md","content":"# Security and Network Behavior\n\n> **2.9.0 note**: This document covers the runtime security posture (network\n> behavior, token handling, policy engine, consent ledger, supply-chain\n> hardening since 2.2.0). For the per-finding response to the\n> [ClawHub Security Scan](https://clawhub.ai/imjszhang/js-eyes) of v2.6.1,\n> see [`SECURITY_SCAN_NOTES.md`](./SECURITY_SCAN_NOTES.md); for the one-screen\n> operator summary (risk item / current default / how to tighten / config\n> switch / verify) see the [Security Posture table in `README.md`](./README.md#security-posture-280).\n> A local reproduction of the ClawHub static heuristic is available via\n> `npm run scan:security` (zero unexpected findings on 2.6.3 — the 2.6.3\n> changes are install-time UX only and do not touch the runtime callsites\n> tracked by the scan).\n\n## Reporting a vulnerability\n\nUse GitHub's private vulnerability reporting flow from the repository's **Security** tab. Include the affected component and version or commit, reproduction steps, expected and observed impact, and any known mitigation.\n\nDo not open a public issue for a suspected vulnerability or disclose it before a fix or coordinated disclosure plan is available. Routine dependency updates and non-sensitive bugs can use normal GitHub issues.\n\n## Overview\n\nJS Eyes is a **local-first** browser automation stack. Its normal runtime loop talks only to the JS Eyes server you configure, which defaults to `localhost:18080`.\n\nThere are two deployment shapes to keep in mind:\n\n- **ClawHub / bundle deployment:** install the JS Eyes bundle, run `npm install` in the bundle root, register `openclaw-plugin`, and allow the plugin tools in OpenClaw.\n- **Source-repo / development deployment:** clone this repository, run `npm install` in the repo root, point OpenClaw at the repo-root `openclaw-plugin`, and optionally load the unpacked browser extension directly from `extensions/chrome/` or `extensions/firefox/`.\n\nThose two modes share the same local runtime behavior, but the source repository also contains release tooling, docs, site assets, and extension source files that reference public URLs for packaging and documentation workflows.\n\n## Complete OpenClaw Deployment Notes\n\nA complete local OpenClaw deployment needs all of the following:\n\n- `plugins.load.paths` points to the bundle or repo-root `openclaw-plugin` directory.\n- `plugins.entries[\"js-eyes\"].enabled` is `true`.\n- `tools.alsoAllow: [\"js-eyes\"]` or an equivalent `tools.allow` entry is present, because `js-eyes` registers optional plugin tools.\n- The browser extension is configured to connect to the chosen `serverHost` / `serverPort`.\n\nWithout the tool allowlist step, the plugin can load successfully while its\nsingle `js-eyes` router tool remains unavailable to the model.\n\n## Runtime Network Behavior\n\nBase runtime behavior:\n\n- **OpenClaw plugin:** connects via WebSocket to `ws://serverHost:serverPort` and uses HTTP only for JS Eyes server endpoints such as `/api/browser/status` and `/api/b"},{"path":"skill-card.md","content":"## Description:\n\nInstall, connect, operate, and troubleshoot the host-neutral JS Eyes browser and Skill Runtime from CLI, MCP, or the optional OpenClaw adapter.\n\nThis skill is ready for commercial/non-commercial use.\n\n## Publisher:\n\n[imjszhang](https://clawhub.ai/user/imjszhang)\n\n### License/Terms of Use:\n\nMIT-0\n\n## Use Case:\n\nDevelopers and operators use JS Eyes to install, connect, operate, and troubleshoot local browser automation and JS Eyes Skill Runtime integrations across CLI, MCP, and OpenClaw hosts.\n\n### Deployment Geography for Use:\n\nGlobal\n\n## Known Risks and Mitigations:\n\nRisk: Local browser automation and JS Eyes runtime support can expose sensitive browser actions when broader authority is enabled.\n\nMitigation: Use the safe MCP profile where possible, keep raw eval disabled unless the task truly requires it, and require explicit operator intent before enabling sensitive actions.\n\nRisk: Skill install and discovery paths include review-worthy unsafe remote install and broad network-fetch behavior.\n\nMitigation: Use the staged skills/plan-install plus CLI approval path, review install plans before approval, and avoid untrusted custom registries.\n\nRisk: A local browser automation server can be exposed beyond the intended user if remote binding or anonymous access is enabled.\n\nMitigation: Keep the server on localhost with token authentication, leave anonymous access disabled, and avoid remote binding unless it is deliberately configured and secured.\n\nRisk: Native Messaging auto-install and skill directory watchers add local integration surface in hardened environments.\n\nMitigation: Consider disabling Native Messaging auto-install and skill directory watchers where local change monitoring or browser token synchronization is not required.\n\n## Reference(s):\n\n- [ClawHub skill page](https://clawhub.ai/imjszhang/skills/js-eyes)\n- [Project homepage from ClawDIS metadata](https://github.com/imjszhang/js-eyes)\n- [Artifact skill instructions](artifact/SKILL.md)\n- [Artifact security documentation](artifact/SECURITY.md)\n\n## Skill Output:\n\n**Output Type(s):** [Text, Markdown, Code, Shell commands, Configuration, Guidance]\n\n**Output Format:** [Markdown guidance with JSON and shell command examples]\n\n**Output Parameters:** [1D]\n\n**Other Properties Related to Output:** [Produces setup, diagnosis, and policy-aware operation guidance; it does not produce binary artifacts.]\n\n## Skill Version(s):\n\n2.10.0 (source: server release evidence; artifact frontmatter and package manifests report 2.9.0)\n\n## Ethical Considerations:\n\nUsers should evaluate whether this skill is appropriate for their environment, review any generated or modified files before relying on them, and apply their organization's safety, security, and compliance requirements before deployment."},{"path":"openclaw-plugin/openclaw.plugin.json","content":"{\n  \"id\": \"js-eyes\",\n  \"activation\": {\n    \"onStartup\": true\n  },\n  \"name\": \"JS Eyes\",\n  \"description\": \"浏览器自动化工具 — 通过 WebSocket 为 AI Agent 提供远程浏览器控制能力（标签页管理、内容获取、脚本执行等）\",\n  \"version\": \"2.9.0\",\n  \"contracts\": {\n    \"tools\": [\n      \"js-eyes\"\n    ]\n  },\n  \"toolMetadata\": {\n    \"js-eyes\": {\n      \"optional\": true\n    }\n  },\n  \"configSchema\": {\n    \"type\": \"object\",\n    \"additionalProperties\": false,\n    \"properties\": {\n      \"serverHost\": {\n        \"type\": \"string\",\n        \"default\": \"localhost\",\n        \"description\": \"JS-Eyes 服务器监听地址\"\n      },\n      \"serverPort\": {\n        \"type\": \"number\",\n        \"default\": 18080,\n        \"description\": \"JS-Eyes 服务器端口\"\n      },\n      \"autoStartServer\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"是否随插件加载自动启动内置服务器\"\n      },\n      \"requestTimeout\": {\n        \"type\": \"number\",\n        \"default\": 1800,\n        \"description\": \"浏览器操作请求超时（秒），默认 1800（30 分钟）\"\n      },\n      \"skillsRegistryUrl\": {\n        \"type\": \"string\",\n        \"default\": \"https://js-eyes.com/skills.json\",\n        \"description\": \"扩展技能注册表 URL\"\n      },\n      \"skillsDir\": {\n        \"type\": \"string\",\n        \"default\": \"\",\n        \"description\": \"扩展技能安装目录（空值则使用技能包内的 skills/ 目录）\"\n      },\n      \"extraSkillDirs\": {\n        \"type\": \"array\",\n        \"items\": {\n          \"type\": \"string\"\n        },\n        \"default\": [],\n        \"description\": \"额外只读技能来源（绝对路径列表）。每条可以是单个 V2/V1 技能目录或父目录（扫描 1 层子目录）。同 id 冲突时 primary 优先；可通过 host security.verifyExtraSkillDirs 启用快照校验。\"\n      },\n      \"skills\": {\n        \"type\": \"object\",\n        \"additionalProperties\": {\n          \"type\": \"object\"\n        },\n        \"default\": {},\n        \"description\": \"按技能 ID 配置运行参数；plugins config 覆盖 host config 中的同名技能配置。\"\n      },\n      \"externalSkills\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"default\": {\n          \"policy\": \"prompt\",\n          \"defaultExecution\": \"worker\"\n        },\n        \"description\": \"外部技能的发现、信任和执行策略。legacy 保持兼容；prompt 要求批准；strict 还要求 V2 静态 Manifest。\",\n        \"properties\": {\n          \"policy\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"legacy\",\n              \"prompt\",\n              \"strict\"\n            ],\n            \"default\": \"prompt\"\n          },\n          \"defaultExecution\": {\n            \"type\": \"string\",\n            \"enum\": [\n              \"in-process\",\n              \"worker\"\n            ],\n            \"default\": \"worker\"\n          }\n        }\n      },\n      \"watchConfig\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"通过 chokidar 监听 ~/.js-eyes/config/config.json，配置变更时（含 js-eyes skills link/unlink/enable/disable）零重启热加载技能。\"\n      },\n      \"devWatchSkills\": {\n        \"type\": \"boolean\",\n        \"default\": true,\n        \"description\": \"开发模式：监听已发现技能目录的文件变更（默认 ~300ms 防抖），改完 Skill 源文件自动 reload。仅推荐在本地开发用；生产可关闭以减少 fs 监听负载。\"\n      },\n      \"nativeHost\": {\n        \"type\": \"object\",\n        \"additionalProperties\": false,\n        \"default\": {\n          \"a"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2522,"uniquenessScore":41,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T07:26:49.542Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-09T20:33:01.804Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}