npm.io
1.0.0 • Published 1 week ago

@taprun/from-stagehand

Licence
MIT
Version
1.0.0
Deps
0
Size
25 kB
Vulns
0
Weekly
0
Stars
8

@taprun/from-stagehand

Convert Stagehand scripts into Tap Plan v2 objects. Complement to Stagehand, not a replacement.

npm install @taprun/from-stagehand @taprun/spec

What this is for

Stagehand (Browserbase) ships natural-language browser automation on top of Playwright. Two API surfaces coexist in user scripts:

  1. Deterministic Playwrightpage.goto / click / fill / type / press / waitForSelector / waitForTimeout. These have fixed selectors and stable behavior.
  2. Natural-language Stagehandstagehand.act("..."), stagehand.extract("...", schema), stagehand.observe(), stagehand.agent().execute("..."). These resolve to actions only at runtime via an LLM.

This adapter takes a pragmatic stance:

Stagehand API → plan-v2 op Verifiable?
page.goto(url) { op: "nav", url }
page.click(s) { op: "input", kind: "click", target }
page.fill(s, v) { op: "input", kind: "fill", target, value }
page.type / press / waitForSelector / waitForTimeout (same as @taprun/from-playwright)
stagehand.act(prompt) { op: "eval", returns: { type: "object" }, fn: TODO with prompt }
stagehand.extract(prompt, schema) { op: "eval", returns: { type: "object" }, fn: TODO }
stagehand.observe(...) { op: "eval", returns: { type: "array" }, fn: TODO }
stagehand.agent().execute(prompt) { op: "eval", returns: { type: "object" }, fn: TODO }

Result: a partially deterministic v2 Plan. Tap can doctor and heal the deterministic portions. The NL portions land on op:eval with a TODO marker in fn — author refines returns.type and replaces the stub with deterministic ops or a real eval body before runtime. v2 has no op:exec and no allowUnverifiable flag; the LLM-required steps are visible by inspecting op types.

Positioning

This is not a Stagehand replacement. It's a Tap-side bridge so Stagehand users can:

  • Add structural drift detection on the deterministic portions of their scripts
  • Audit which steps in their automation actually require an LLM
  • Produce a portable .tap.json artifact for compliance / reproducibility logs

Usage

import { readFile, writeFile } from "node:fs/promises";
import { stagehandToTap } from "@taprun/from-stagehand";
import { runConformance } from "@taprun/spec";

const source = await readFile("scripts/my-stagehand-script.ts", "utf8");
const plan = stagehandToTap(source, {
  site: "github",
  name: "browserbase-search",
  intent: "read",
});

const v = runConformance(plan);
if (!v.pass) throw new Error(JSON.stringify(v.failures));

await writeFile("github/browserbase-search.plan.json", JSON.stringify(plan, null, 2));

Scope notes

  • Lifecycle calls (stagehand.init, stagehand.close, browser.newPage, etc.) are silently dropped — they're scaffolding, not user actions.
  • Plain Playwright deterministic calls follow exactly the same regex as @taprun/from-playwright (no behavioral divergence).
  • The MVP regex scanner has the same limitations as the Playwright/Puppeteer adapters: variable-bound selectors, template-string interpolation, and trailing line comments are best-effort.

Part of the Tap ecosystem

Tap is local-first browser automation — compile your scraper once, run it in your own browser forever, and diff the drift when sites change. The local-first runtime means your act() and extract() calls hit your already-logged-in session — no Browserbase egress, no shared cloud browser.

License

MIT.