Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions skills/browser-to-api/REFERENCE.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,9 +98,17 @@ Workflow:
# during capture, alongside browser-trace
browse network on
# ...drive...
# IMPORTANT: snapshot the dir before it gets reused
cp -r "$(browse network path | jq -r .path)" .o11y/<run>/cdp/network/bodies/
browse network off
# IMPORTANT: snapshot the dir before another `browse network on` overwrites it.
# The helper handles the mkdir + cp + `browse network off` sequence.
node ../browser-trace/scripts/snapshot-bodies.mjs <run>

# Equivalent manual form if you want to do it by hand. The mkdir is required
# because `cp -r src dest/` fails on macOS BSD cp when dest's parent doesn't
# exist yet. start-capture.mjs already creates `cdp/network/`, but older runs
# may not have it — the mkdir is cheap insurance.
# mkdir -p .o11y/<run>/cdp/network
# cp -R "$(browse network path | jq -r .path)" .o11y/<run>/cdp/network/bodies
# browse network off
```

Internals (matched in `lib/io.mjs` + `load.mjs`):
Expand Down
9 changes: 4 additions & 5 deletions skills/browser-to-api/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,10 @@ browse network on # capture request/response
browse open https://example.com
# ...drive whatever flows you want covered...

# Snapshot the bodies dir BEFORE turning capture off (the temp dir is shared
# per-session, so subsequent `browse network on` runs would mix your bodies
# with whatever a future capture writes if you skip this step).
cp -r "$(browse network path | jq -r .path)" .o11y/my-site/cdp/network/bodies/
browse network off
# Snapshot the bodies dir BEFORE another `browse network on` overwrites it
# (the temp dir is shared per-session). The helper creates
# .o11y/my-site/cdp/network/bodies/ and runs `browse network off` for you.
node ../browser-trace/scripts/snapshot-bodies.mjs my-site

node ../browser-trace/scripts/stop-capture.mjs my-site
node ../browser-trace/scripts/bisect-cdp.mjs my-site
Expand Down
90 changes: 90 additions & 0 deletions skills/browser-trace/scripts/snapshot-bodies.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env node
// Snapshot the `browse network` bodies dir into a run before the next capture
// overwrites it.
//
// Usage:
// node scripts/snapshot-bodies.mjs <run-id> [--no-off] [--bodies <path>]
//
// What it does:
// 1. Resolves the `browse network` capture dir (live, via `browse network path`,
// or an explicit `--bodies <path>` override).
// 2. Copies its contents into `<run>/cdp/network/bodies/`.
// 3. Calls `browse network off` so a future `browse network on` starts clean
// (skip with `--no-off`).
//
// The manual `cp -r "$(browse network path | jq -r .path)" <run>/cdp/network/bodies`
// pattern is fragile across BSD vs GNU `cp` (trailing-slash semantics differ and
// the parent dir must already exist). This script encodes the safe path so the
// docs can refer to one command.

import fs from 'node:fs';
import path from 'node:path';
import { spawnSync } from 'node:child_process';

import { runDir, ensureDir } from './lib.mjs';

const args = process.argv.slice(2);
if (args.length === 0 || args[0].startsWith('--')) {
console.error('usage: snapshot-bodies.mjs <run-id> [--no-off] [--bodies <path>]');
process.exit(2);
}
const runId = args[0];
let bodiesOverride = null;
let runOff = true;
for (let i = 1; i < args.length; i++) {
if (args[i] === '--no-off') { runOff = false; continue; }
if (args[i] === '--bodies') { bodiesOverride = args[++i]; continue; }
console.error(`unknown arg: ${args[i]}`);
process.exit(2);
}

const RD = runDir(runId);
if (!fs.existsSync(RD)) {
console.error(`run dir not found: ${RD}`);
process.exit(1);
}

let src = bodiesOverride;
if (!src) {
const out = spawnSync('browse', ['network', 'path', '--json'], { encoding: 'utf8' });
if (out.status !== 0) {
console.error('failed to resolve `browse network path`:');
console.error(out.stderr || out.stdout);
process.exit(1);
Comment on lines +50 to +53
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fall back when browse network path --json exits non-zero

The script exits immediately when browse network path --json returns a non-zero status, so the documented compatibility fallback to plain browse network path never runs in the common “unknown flag” case on older browse versions. In those environments, snapshot-bodies.mjs fails even though the non-JSON command could still provide a valid path, blocking body snapshotting for the whole workflow.

Useful? React with 👍 / 👎.

}
try {
src = JSON.parse(out.stdout).path;
} catch {
// older `browse` versions don't take --json; fall back to plain stdout.
src = (spawnSync('browse', ['network', 'path'], { encoding: 'utf8' }).stdout || '').trim();
}
}
if (!src || !fs.existsSync(src)) {
console.error(`bodies source dir not found: ${src ?? '(unresolved)'}`);
console.error('Did you run `browse network on` before capturing?');
process.exit(1);
}

const dest = path.join(RD, 'cdp', 'network', 'bodies');
ensureDir(path.dirname(dest));
// fs.cpSync avoids the BSD-vs-GNU cp portability footgun: cp's trailing-slash
// and missing-parent semantics differ across macOS and Linux. Node's recursive
// copy is the same everywhere.
fs.cpSync(src, dest, { recursive: true });
const fileCount = fs.readdirSync(dest).length;

if (runOff) {
const off = spawnSync('browse', ['network', 'off'], { encoding: 'utf8' });
if (off.status !== 0) {
console.error('warning: `browse network off` failed (continuing):');
console.error(off.stderr || off.stdout);
}
}

console.log(JSON.stringify({
run_id: runId,
bodies_src: src,
bodies_dest: dest,
files: fileCount,
ran_off: runOff,
}));
5 changes: 5 additions & 0 deletions skills/browser-trace/scripts/start-capture.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,11 @@ const domainArgs = domainsList.flatMap(d => ['--domain', d]);

const RD = runDir(runId);
ensureDir(path.join(RD, 'cdp'));
// `cdp/network/` is also created by bisect-cdp.mjs, but users typically snapshot
// `browse network` bodies into `cdp/network/bodies/` BEFORE bisect runs. Create
// the parent dir up front so `cp -r ... cdp/network/bodies` works without an
// extra `mkdir -p` step in the docs.
ensureDir(path.join(RD, 'cdp', 'network'));
ensureDir(path.join(RD, 'screenshots'));
ensureDir(path.join(RD, 'dom'));

Expand Down