feat(e2e): start a project from an example app with e2e init --example

Merged
KA
6d ago
+788-24

e2e init my-app --example with-expo copies one of the apps under examples/ into a new or empty directory. It then runs the usual skill, MCP, and install steps in the example's e2e project.

npx e2e init my-app --example with-flutter   # "flutter" works too
flowchart LR
  A[--example] --> B{dir empty?}
  B -- no --> X[exit 2, nothing downloaded]
  B -- yes --> C[codeload tarball at e2e@version]
  C -- 404 --> D[fall back to main, warn]
  C --> E[stream, extract examples/name, stop past it]
  D --> E
  E --> F[package.json: dir name + this CLI's e2e/@e2e-dev ranges]
  F --> G[wizard in root or e2e/: skill, MCP, .gitignore, install]
  G -- cancel / Ctrl-C --> R[remove the copy]
  • packages/e2e/src/cli/init/examples.ts: the example list, a streaming download from codeload.github.com/tester-army/e2e, and a small tar reader. The tar reader handles ustar prefixes, pax path, and GNU long names. It refuses .. paths, never writes links, and keeps the executable bit, so gradlew still runs.
  • The tag matches the running CLI, so the example code matches the runner. Example pins are bumped by hand and trail releases: with-vite at e2e@0.21.2 pins e2e ^0.15.2. The copy rewrites e2e and the recorded @e2e-dev/* ranges to what init writes for a new project.
  • The example's config, tests, and scripts stay as they are. No tests/example.e2e.ts and no test:e2e script get added. For native apps (SwiftUI, Compose, KMP, Flutter, MAUI) the wizard runs in e2e/, so the skill and MCP files land there. The docs say to open the agent in that folder.
  • The download has a 30 s idle limit, not a total one, because the tarball is the whole repo (about 28 MB gzipped before examples/). Ctrl-C during the download goes through the clack spinner's onCancel, removes the partial copy, and exits 130.
  • --example with --engine, --gateway, or --endpoint is a usage error (exit 2). with-limrun isn't offered, since it reuses the SwiftUI and Compose apps. tests/unit/init-examples.test.ts fails if the list and examples/ drift apart, or if a listed script is missing.
  • Telemetry: e2e_init_completed gets example (the folder name or null) and a new example-failed result. Both are documented in docs/telemetry.mdx.
  • Docs: a "Starting from an example" section and flag row in docs/reference/cli.mdx, plus skills/e2e/references/setup.md and examples/README.md.

Verified

Ran it locally: yes. Scratch directory, built CLI (packages/e2e/dist/cli/bin.js), real GitHub.

  • init vite-app --example vite --yes --install, then npm run test:e2e in the copy:
    ✓ target "web" command ready 659ms
    ↓ |web| tests/agentic.e2e.ts (2 tests | 2 skipped)
    ✓ |web| tests/deterministic.e2e.ts (3 tests) 940ms
    
    The agent tests skip without AI_GATEWAY_API_KEY. Before the range rewrite, the same run installed e2e@0.15.2 and failed with CONFIG_LOAD_FAILED.
  • init flutter-app --example flutter --yes: about 2.4 s end to end. The skill and MCP files land in flutter-app/e2e/, and the run ends with Next: cd flutter-app/e2e, then npm install, then build and install the app as ../README.md describes, then npm run test:e2e:android.
  • init compose --example with-compose, diffed against git archive e2e@0.21.2 examples/with-compose: identical except e2e/package.json name. gradlew is -rwxr-xr-x.
  • init expo-app --example expo: package.json diff against the tag is the name plus e2e ^0.16.0 → ^0.21.2, @e2e-dev/web ^0.11.1 → ^0.15.2, @e2e-dev/mobile ^0.9.0 → ^0.12.3.
  • kill -INT 0.6 s into a download: ■ Canceled, Cancelled; no changes were made, exit 130, and no directory left.
  • Each of these exits 2 before downloading anything:
    • --example svelte: the error lists the valid names.
    • --example expo --engine web: drop --engine.
    • A non-empty directory: is not empty; --example needs a new or empty directory.

Not verified: building and running a native example (Flutter, SwiftUI, and the others) on a device after copying. The copy is byte-identical to the tag apart from package.json, and the nightly examples workflow already covers those apps.