77// bun scripts/cli.ts api <target> <group.endpoint> [json]
88// bun scripts/cli.ts mcp <target> tools | call <tool> [json]
99// bun scripts/cli.ts ledger <target> [workos|autumn]
10- // bun scripts/cli.ts browser <target> up|goto|click|fill|press|eval|look|down
1110// bun scripts/cli.ts logs <target>
1211// bun scripts/cli.ts down <target>
1312//
14- // Develop against a live instance with the exact machinery the tests use (same
15- // boot recipe, same Target/identity/surfaces), then write scenarios with those
16- // same surfaces . `up` leaves the instance running until `down` — it IS the
17- // handoff demo (AGENTS.md: evidence, not assertions). `--share` makes it
18- // reachable over the user's tailnet.
13+ // Develop against a live instance with the exact machinery the tests use
14+ // (same boot recipe, same Target/identity/surfaces), then crystallize the
15+ // journey into a scenario . `up` leaves the instance running until `down` —
16+ // it IS the handoff demo (AGENTS.md: evidence, not assertions). `--share`
17+ // makes it reachable over the user's tailnet.
1918//
2019// Instances are tracked in .dev/<target>.json: a state file marks a
2120// DELIBERATE long-lived instance (not a leak). Cloud's WorkOS/Autumn
@@ -444,59 +443,6 @@ const ledger = async (targetName: string, service = "workos") => {
444443 console . log ( JSON . stringify ( entries , null , 2 ) ) ;
445444} ;
446445
447- // --- browser (drive the live app while developing) -------------------------
448- // Spin up a real, logged-in browser pointed at the running instance and target
449- // it: drive it with the verbs here, or connect anything that speaks CDP to the
450- // printed endpoint. The same browser the Browser test surface uses, so this and
451- // a scenario() are the same primitive — no recording, no codegen.
452-
453- const printObservation = ( obs : import ( "../src/devbrowser" ) . Observation ) => {
454- console . log ( `→ ${ obs . url } ${ JSON . stringify ( obs . title ) } ` ) ;
455- if ( obs . cdpUrl ) console . log ( ` cdp: ${ obs . cdpUrl } (point any CDP browser tool here)` ) ;
456- console . log ( ` screenshot: ${ obs . screenshot } ` ) ;
457- if ( obs . evalResult !== undefined ) console . log ( ` eval: ${ obs . evalResult } ` ) ;
458- if ( obs . controls . length > 0 ) {
459- console . log ( "controls (role · name):" ) ;
460- for ( const control of obs . controls . slice ( 0 , 40 ) ) {
461- console . log ( ` ${ control . role . padEnd ( 9 ) } ${ control . name } ` ) ;
462- }
463- if ( obs . controls . length > 40 ) console . log ( ` … ${ obs . controls . length - 40 } more` ) ;
464- }
465- } ;
466-
467- const browser = async ( raw : ReadonlyArray < string > ) => {
468- const target = raw [ 0 ] ;
469- const verb = raw [ 1 ] ;
470- if ( ! target || ! verb ) {
471- throw new Error (
472- "usage: browser <target> up [--headed] [--no-org] | goto <path> | click <text> | " +
473- "fill <field> <value> | type <text> | press <key> | eval <js> | look | down" ,
474- ) ;
475- }
476- const { spinUp, drive, shut } = await import ( "../src/devbrowser" ) ;
477-
478- if ( verb === "down" ) {
479- await shut ( devDir , target ) ;
480- return console . log ( `${ target } : browser down` ) ;
481- }
482- if ( verb === "up" ) {
483- const { target : resolved } = await loadTarget ( target ) ;
484- const identity = await runEffect < import ( "../src/target" ) . Identity > (
485- resolved . newIdentity ( raw . includes ( "--no-org" ) ? { org : false } : undefined ) ,
486- ) ;
487- const obs = await spinUp ( devDir , target , resolved . baseUrl , identity , raw . includes ( "--headed" ) ) ;
488- return printObservation ( obs ) ;
489- }
490- // a drive verb against the already-running browser
491- const obs = await drive (
492- devDir ,
493- target ,
494- verb ,
495- raw . slice ( 2 ) . filter ( ( a ) => ! a . startsWith ( "--" ) ) ,
496- ) ;
497- printObservation ( obs ) ;
498- } ;
499-
500446// --- lifecycle commands ----------------------------------------------------
501447
502448const status = ( ) => {
@@ -562,18 +508,9 @@ const HELP = `e2e dev CLI — the scenario primitives, interactive (see e2e/AGEN
562508 api <target> <group.endpoint> [json] typed API call as a fresh identity
563509 mcp <target> tools | call <tool> [json] MCP session call
564510 ledger <target> [workos|autumn] the emulator's request ledger (cloud)
565- browser <target> up [--headed] [--no-org] spin up a logged-in browser on the
566- running app and leave it running; prints a CDP
567- endpoint you can target with any browser tool
568- browser <target> <verb> drive it: goto <path> | click <text> | fill <field>
569- <value> | type <text> | press <key> | eval <js> |
570- look | down. Each prints the page's controls + a shot
571511 logs <target> dump the instance's dev-server log
572512 down <target> tear down (kills servers, removes tailscale serves)
573513
574- The browser is the same one the Browser test surface uses, so developing with it
575- and writing a scenario() are the same primitive (no recording, no codegen).
576-
577514Instances live in e2e/.dev/<target>.json — a state file marks a DELIBERATE
578515long-lived instance. Use the booted instance for e2e too:
579516 E2E_SELFHOST_URL=<app url> vitest run --project selfhost <file>` ;
@@ -597,8 +534,6 @@ const main = async () => {
597534 return mcpCall ( args [ 0 ] ?? "" , args [ 1 ] , args . slice ( 2 ) ) ;
598535 case "ledger" :
599536 return ledger ( args [ 0 ] ?? "" , args [ 1 ] ) ;
600- case "browser" :
601- return browser ( rest ) ;
602537 case "logs" :
603538 return logs ( args [ 0 ] ?? "" ) ;
604539 case "down" :
0 commit comments