npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

surfwright

v0.1.3

Published

Guard/discoverability package that ships the same SurfWright CLI runtime

Readme

SurfWright

SurfWright is a CLI-first browser control surface designed for agents:

  • Composable commands (small enough to chain, strong enough to trust)
  • Deterministic output (machines like JSON; humans like brevity)
  • Real observability (console, errors, network) without devtools theater

Think: “surf the web”, but with a board that does not talk back.

The Contract

SurfWright aims to be boring in all the right ways:

  • Outputs are bounded and predictable (no surprise novels).
  • State is explicit (handles in, handles out).
  • Failures are typed (short codes, actionable messages).
  • Every operation is interruptible (timeouts and aborts are mandatory).

Noise vs Signal

noisy tooling:
  .------------------------------------------.
  | [INFO] ...                               |
  | [INFO] ... [INFO] ... [WARN] ...         |
  | [INFO] ... [INFO] ... [INFO] ...         |
  | [DEBUG] ... [INFO] ... [TRACE] ...       |
  '------------------------------------------'

surfwright:
  .------------------------------------------.
  | {"ok":true,"targetId":"t1","url":"..."}   |
  '------------------------------------------'

Why This Exists

Browser automation is easy to demo and hard to operate. Most tools either:

  • dump walls of text,
  • hide state in magic globals,
  • or fuse 12 actions into one brittle macro.

SurfWright goes the other way:

  • return handles (targetId, sessionId),
  • keep outputs bounded,
  • make every step explicit,
  • and let agents compose the run.

What It Is (High Level)

SurfWright is an agent-native browser harness:

  • a CLI (surfwright)
  • a local daemon path enabled by default for fast, stateful command loops
  • using Chrome/Chromium via CDP, with Playwright as the control engine

Daemon Flags (Single Source Of Truth)

| Variable | Values | Behavior | | --- | --- | --- | | SURFWRIGHT_DAEMON | 0 | Hard-off mode: daemon must not spawn and CLI must not proxy through daemon. | | SURFWRIGHT_DAEMON | 1 | Force daemon-enabled path (subject to documented bypass classes). | | SURFWRIGHT_DAEMON | unset | Lean v1 default: daemon-on. | | SURFWRIGHT_DAEMON_IDLE_MS | <ms> | Override idle shutdown timing for diagnostics/tuning. | | SURFWRIGHT_DEBUG_LOGS | 1 | Enable verbose local diagnostics logging (default is off). |

Availability

Pre-alpha. Core session.* and the open -> target.* flow are stable enough for daily agent loops. Network, plan-runner ergonomics, and experimental effects are still moving.

Quick Start (Recommended)

Install the skill:

npx skills add marcohefti/surfwright

Then tell your agent to use SurfWright. The skill contains the operational guidance.

Optional: if you run the CLI manually, check the runtime contract:

surfwright contract

Use surfwright contract for low-token bootstrap output (no full id catalogs). Use surfwright contract --profile browser-core for a compact mission-first browser-control schema bundle. Use surfwright contract --full when you need full commandIds/errorCodes catalogs. Use surfwright contract --command <id> for compact per-command flags/positionals/examples (low-token command lookup). Use surfwright contract --commands <id1,id2,...> for one-shot compact schemas across multiple commands. contract --command also accepts CLI path form (for example target snapshot) and returns command.argvPath for machine-executable command tokens. contract --command/--commands also resolves common legacy aliases (for example openSession, targetFill, targetWaitFor) to canonical IDs. Agent no-arg probe calls like surfwright open or surfwright target.click auto-route to contract --command <id> instead of failing, reducing discovery thrash.

Set global output shaping when you want smaller payloads without changing command behavior:

surfwright --output-shape compact open https://example.com
SURFWRIGHT_OUTPUT_SHAPE=proof surfwright target click <targetId> --text "Pricing" --proof

CLI Install (Optional)

npm i -g @marcohefti/surfwright
brew tap marcohefti/homebrew-tap && brew install surfwright

then

surfwright skill install

Command Map

  • workspace.*: project-local browser profiles and profile locks.
  • session.*: create/reuse/attach/clear browser sessions.
  • extension.*: register/reload/uninstall unpacked extension builds for managed launch coupling.
  • open: open a URL and get a targetId + sessionId.
  • target.*: inspect/read/click/eval/network against one explicit target.
  • run: execute a JSON plan and optionally record/replay it.
  • update.*: check/apply rollback-safe updates.

Everything is JSON-first by default.

Session Hygiene

SurfWright now performs opportunistic idle process parking on normal command ingress (no persistent daemon required):

  • managed browser processes idle longer than 30m are shut down in a detached maintenance worker
  • maintenance pressure mode (default on) automatically tightens GC interval/idle TTL and increases sweep throughput when managed-session load is high
  • no hard session cap is enforced; high-load behavior uses adaptive cleanup instead of rejecting new sessions
  • session metadata/profile state is kept so the next command can transparently restart the session
  • attached sessions are never process-killed by this path
  • stale disk artifacts are opportunistically pruned with bounded retention (runs, captures, orphan session profiles)
  • stale daemon metadata/start locks are opportunistically swept (daemon.json, daemon.start.lock) when records are dead/invalid

Tuning knobs:

SURFWRIGHT_GC_ENABLED=0                  # disable opportunistic maintenance (parking + disk prune)
SURFWRIGHT_GC_MIN_INTERVAL_MS=600000     # minimum trigger interval (default: 10m)
SURFWRIGHT_IDLE_PROCESS_TTL_MS=1800000   # idle threshold (default: 30m)
SURFWRIGHT_IDLE_PROCESS_SWEEP_CAP=6      # max managed sessions parked per run
SURFWRIGHT_GC_PRESSURE_ENABLED=0         # disable adaptive pressure mode (default: enabled)
SURFWRIGHT_GC_PRESSURE_MANAGED_THRESHOLD=20      # managed-session count to enter pressure mode
SURFWRIGHT_GC_PRESSURE_HIGH_MANAGED_THRESHOLD=80 # managed-session count to enter high pressure mode
SURFWRIGHT_GC_DISK_PRUNE_ENABLED=0       # disable opportunistic disk pruning
SURFWRIGHT_GC_RUNS_MAX_AGE_HOURS=168     # prune ~/.surfwright/runs older than N hours
SURFWRIGHT_GC_RUNS_MAX_TOTAL_MB=1024     # keep runs within total size budget (MB)
SURFWRIGHT_GC_CAPTURES_MAX_AGE_HOURS=72  # prune ~/.surfwright/captures older than N hours
SURFWRIGHT_GC_CAPTURES_MAX_TOTAL_MB=1024 # keep captures within total size budget (MB)
SURFWRIGHT_GC_ORPHAN_PROFILES_MAX_AGE_HOURS=24  # prune orphan ~/.surfwright/profiles dirs older than N hours
SURFWRIGHT_GC_WORKSPACE_PROFILES_MAX_AGE_HOURS=off  # optional: prune old workspace profiles when explicitly enabled

Manual disk cleanup command:

surfwright state disk-prune --dry-run
surfwright state disk-prune --workspace-profiles-max-age-hours 336

Common Flows

Explore and act on a page:

surfwright open https://example.com
surfwright target snapshot <targetId> --mode orient
surfwright target find <targetId> --text "Pricing" --first
surfwright target click <targetId> --text "Pricing"
surfwright target read <targetId> --selector main --chunk-size 1200 --chunk 1

Fast first-pass flow with explicit reuse/readiness controls:

surfwright open https://example.com --reuse active --wait-until commit
surfwright open https://example.com --session task-s1 --ensure-session if-missing
surfwright target click <targetId> --text "Pricing" --visible-only --proof
surfwright --output-shape compact target click <targetId> --text "Delete" --visible-only --repeat 3
surfwright target fill <targetId> --selector "#email" --value "[email protected]" --wait-network-idle --proof
surfwright target fill <targetId> --selector "#search" --value "surfwright" --event-mode realistic
surfwright target select-option <targetId> --selector "#role" --label "Editor" --proof
surfwright target click <targetId> --text "Sort" --within "#results-table" --proof
surfwright target click <targetId> --selector "#agree" --proof --proof-check-state
surfwright target click <targetId> --selector ".todo-item" --nth 2 --count-after
surfwright target click <targetId> --selector ".todo-item" --nth 2 --expect-count-after 4
surfwright target click-read <targetId> --text "Pricing" --read-selector main --chunk-size 1200 --chunk 1
surfwright target keypress <targetId> --key Enter --selector "#search" --wait-for-selector ".results" --proof
surfwright target upload <targetId> --selector "input[type=file]" --file ./fixture.txt --submit-selector "button[type=submit]" --expect-uploaded-filename fixture.txt --wait-for-result --result-selector "#uploaded-files" --result-filename-regex "fixture\\.txt"
surfwright target spawn <targetId> --selector "a[target=_blank]" --proof --assert-title "Docs"
surfwright target style <targetId> --selector ".btn.btn-primary" --properties background-color,color,font-size,border-radius
surfwright target attr <targetId> --selector "img.avatar" --name src
surfwright --output-shape proof target style <targetId> --selector ".btn.btn-primary"
surfwright target extract <targetId> --kind docs-commands --selector main --limit 5
surfwright target extract <targetId> --kind command-lines --selector main --limit 12
surfwright --output-shape proof target extract <targetId> --kind docs-commands --selector main --limit 5
surfwright target extract <targetId> --kind table-rows --schema-json '{"name":"record.Name","price":"record.Price"}' --dedupe-by name
surfwright target extract <targetId> --kind headings --selector main --limit 12
surfwright target download <targetId> --text "Export CSV" --fallback-to-fetch --proof

target find match rows include text, visible, selectorHint, href, and tag. target attr reads one matched element attribute by deterministic index (--index|--nth) and resolves URL-like attributes (href|src|action|...) to absolute URLs. open --ensure-session <off|if-missing|fresh> can bootstrap/fork managed sessions for open without a separate session command (--profile cannot be combined). open and session.* managed reports include additive extension-runtime evidence: extensionSetFingerprint plus appliedExtensions[] (state=runtime-installed|registry-only). Managed session reachability checks restart deterministically when configured extension set fingerprint drifts (for example after extension reload or rebuilt unpacked assets). target snapshot --mode orient now includes additive counters (headingsCount, buttonsCount, linksCount, navCount) and optional count controls (--count-scope <full|bounded>, --count-filter headings,buttons,links,nav). target click --proof now includes additive proof.countAfter for selector-mode clicks (when post-action counting is available). target click --count-after adds additive top-level countAfter without enabling full proof payloads; pair with --expect-count-after <n> for typed post-click assertions. target click --proof-check-state adds additive checkbox/radio state evidence (proof.checkState.before/after/changed) for toggle workflows. target click --repeat <n> executes repeated deterministic clicks and returns final click fields plus repeat metadata (requested, completed, actionIds, pickedIndices). target click mismatch failures now include bounded candidate samples and withinSelector context for faster disambiguation. target fill|keypress|upload|drag-drop|dialog now support the same post-action wait controls (--wait-for-text|--wait-for-selector|--wait-network-idle, --wait-timeout-ms) and optional --proof. target upload --submit-selector <query> runs attach + submit in one deterministic action so form uploads can be completed atomically. target upload --wait-for-result enables one-shot upload result verification using --result-selector, --result-text-contains, and/or --result-filename-regex; --expect-uploaded-filename now projects uploadedFilename + uploadVerified in the same action report. target select-option provides first-class native <select> control by --value, --label, or --option-index, returning selectedValue, selectedText, and selectedIndex. target spawn --proof --assert-title <text> adds compact spawn proof fields and optional title assertion for deterministic new-window checks. open|target click|target fill|target keypress|target upload|target drag-drop|target dialog|target download|target wait support additive post-action assertions: --assert-url-prefix, --assert-selector, --assert-text. open and target url-assert include additive blockType (auth|captcha|consent|unknown) for navigation gating triage. target download includes additive top-level fields (downloadStarted, downloadMethod, downloadStatus, downloadFinalUrl, downloadFileName, downloadBytes, downloadedFilename, downloadedBytes) and canonical nested download.* fields (fileName, bytes); use --fallback-to-fetch for event-missed downloads and --allow-missing-download-event for deterministic non-started envelopes. Strict timeout failures now return typed E_DOWNLOAD_TIMEOUT (retryable=true, phase=download_event_wait). target extract --kind command-lines emits normalized runnable command entries (item.command) from docs/code blocks for low-friction command harvesting. target style --proof includes compact fields (found, targetText, styleBg, styleColor, styleFontSize, styleRadius) for mission checks. target extract --summary adds compact summary/proof fields (itemCount, totalRawCount, count, firstTitle, firstUrl, firstCommand) for direct proof collection. --output-shape proof now also projects compact target extract proof fields without requiring --summary. run pipeline step coverage includes fill, upload, click-read, scroll-plan (including scrollMode: "relative"), bounded repeat-until loops (including untilDeltaGte), top-level result projections (outputField -> sourcePath), and top-level require assertions (equals|contains|gte|truthy|exists) so plans can execute full workflows and emit/validate mission fields without shell-loop + jq glue. run upload steps now honor submitSelector, expectUploadedFilename, and result-verification fields (waitForResult, resultSelector, resultTextContains, resultFilenameRegex) for deterministic attach+submit+verify flows. JSON output is default; use --no-json for human summaries and --pretty for multiline JSON. In JSON mode, parse failures emit only typed JSON failures (no appended Commander help text), so output remains machine-safe. --help output is intentionally disabled; rely on surfwright contract lookup for command discovery. Typed failures now include additive recovery metadata when deterministic next-step routing is available (for example command lookup, required positionals, and handle-type mismatch recovery). Handle misuse is now explicit: E_HANDLE_TYPE_MISMATCH is returned when sessionId and targetId are swapped. Prefer target extract, target style, target attr, and target read before target eval; when you need eval, --expr-b64/--script-b64 avoid shell escaping overhead and --output-shape compact keeps payloads lean.

Use workspace profile for persistent login state:

surfwright workspace init
surfwright open https://github.com/login --profile auth --browser-mode headed
surfwright open https://github.com --profile auth

Use deterministic unpacked extension coupling with workspace profiles:

surfwright workspace init
surfwright extension load ./dist/my-unpacked-extension
surfwright open https://example.com --profile auth
surfwright extension reload my-unpacked-extension
surfwright open https://example.com --profile auth

extension load|reload updates the managed launch set. The next managed ensure/open applies the latest extension build automatically; if the fingerprint changed, SurfWright restarts the managed profile session and reports the applied runtime set in appliedExtensions. Extension runtime verification defaults to strict mode (SURFWRIGHT_EXTENSION_RUNTIME_MODE=strict): when runtime installation is not observed, SurfWright returns typed E_EXTENSION_RUNTIME_NOT_LOADED and includes launch/runtime diagnostics (launchArgs, preference files checked, CDP extension targets observed). For non-blocking dev flows, set SURFWRIGHT_EXTENSION_RUNTIME_MODE=warn to continue with appliedExtensions[*].state evidence while still exposing runtime drift. You can tune the observation budget with SURFWRIGHT_EXTENSION_RUNTIME_OBSERVED_WAIT_MS. Managed launches support browser executable override via global --browser-executable <path> or SURFWRIGHT_BROWSER_EXECUTABLE=<path>. This is the recommended path for unpacked-extension automation on Chromium/CfT builds when stock Chrome blocks side-load flags. surfwright doctor now performs a bounded unpacked side-load runtime probe and reports chrome.unpackedExtensionSideload.{checked,supported,reason} plus selected executable metadata so operators can preflight capability before running strict extension workflows.

Attach to remote CDP endpoints (HTTP(S) discovery URL or direct WS endpoint):

surfwright session attach --cdp https://browser.example.com/relay?token=abc123
surfwright session attach --cdp wss://browser.example.com/devtools/browser/<id>?token=abc123

Capture network evidence around an action:

surfwright target network-begin <targetId> --action-id checkout --profile api
surfwright target click <targetId> --text "Checkout"
surfwright target network-end <captureId> --view summary

Docs

  • Runtime contract: surfwright contract
  • Architecture map: ARCHITECTURE.md
  • Release policy: docs/release-governance.md
  • ZCL browser-control campaign runbook: docs/campaigns/browser-control-zcl-native.md
  • SurfWright scoped benchmark loop runbook: docs/campaigns/browser-control-surfwright-loop.md
  • Loop assets: bench/agent-loop/config.json, bench/agent-loop/AGENT_LOOP.md, tmp/zerocontext/bench-loop/scopes/<scopeId>/history.jsonl, tmp/zerocontext/bench-loop/scopes/<scopeId>/RESULT_SHEET.md
  • Loop iteration semantics: default optimize (change -> run -> evaluate); use --mode sample only for explicit variance/baseline sampling.
  • Loop fan-out control: set agentsPerMission in bench/agent-loop/config.json (or override with --agents-per-mission) to run parallel fresh-agent attempts per mission in one run.
  • ZCL browser-control prompt/oracle assets: missions/browser-control/prompts/ + missions/browser-control/oracles/
  • Skill source: skills/surfwright/SKILL.md

ZERO_CONTEXT_DAY

Declared: February 13, 2026

We celebrate this as the milestone where fresh agents, with near-zero guidance, successfully discovered and used SurfWright workflows on first try.

  ┌─────────────────────────────────────────────┐
  │                                             │
  │   Z E R O   C O N T E X T   D A Y           │
  │                                             │
  │   the surface spoke for itself.             │
  │                                             │
  └─────────────────────────────────────────────┘

Status

Pre-alpha. Everything can break, fast, on purpose, until the surface is right.

The Vibe

Agent tooling should feel like a clean instrument: no noise, no surprises, just tight feedback loops.