Skip to content

Run the web app: package.json scripts beside the app's schemes (roadmap 5.3) - #3

Open
NathanBeddoeWebDev wants to merge 1 commit into
mainfrom
roadmap/27-web-run
Open

NathanBeddoeWebDev wants to merge 1 commit into
mainfrom
roadmap/27-web-run

Conversation

@NathanBeddoeWebDev

Copy link
Copy Markdown
Contributor

Summary

Roadmap 5.3, as one Run button: the toolbar's Run/Stop, the scheme menu and ⌘R now run an Xcode scheme, a Swift package product or a web app's package.json script.

  • Choosing a script: the scheme menu and Choose Scheme… (⌃0) get a section per web app, named for its folder (web), listing its scripts. Choose one and ⌘R runs it; the toolbar reads dev › web (pnpm), and the destination menu says a script has no run destination instead of listing simulators. A plain folder with a package.json becomes runnable instead of "No Scheme". Build, Test, Profile and Archive keep the project's scheme. The choice survives a relaunch.
  • Running it: with the package manager the packageManager field or lockfile implies (bun, pnpm, yarn, npm; npm by default), in the app's folder, with its node_modules/.bin ahead of the login shell's PATH, on a PTY in a debug-area terminal named web: dev (colors and the dev server's keys work).
  • Beside the app: a script runs alongside the scheme's build and app. Running the app doesn't touch the dev server and vice versa. ⌘. stops the chosen target's run (the script's, else the build/app/debugger, and with neither going, the scripts).
  • The URL: the first local URL it prints (Vite, Next, webpack-dev-server, Astro, any localhost) opens once per window in the browser (web.open_dev_server_url), and stays in the activity view as a chip that opens it again.
  • Errors as issues: TypeScript (both formats), esbuild, Vite, ESLint and path:line:col: error: lines become build issues in the Issue navigator and the editor, cleared when the script reruns or a watcher starts over; a failed run adds its exit code.
  • MCP: XcodeListSchemes lists scripts as web: dev with a run_targets kind; RunProject, StopProject and GetConsoleOutput work on them (no new Xcode-named tools).
  • Bug fix (found by the e2e): terminals were forked from GCD threads that block SIGHUP, so a non-shell program (a dev server) never got the hang-up and outlived zcode. They now fork with no signals blocked, and Stop also kills group members that outlive the leader.

Screenshots

The scheme menu with the web app's section:

Scheme menu

The dev server running beside the package's app: "Running HelloWeb on My Mac", the localhost:5173 chip, the web: dev terminal and the TypeScript error inline:

Dev server beside the app

The destination menu with a script chosen:

Destination menu

The error in the Issue navigator:

Issue navigator

Choose Scheme… (⌃0):

Choose Scheme

A plain folder with a package.json:

Plain folder

(The screenshots use the e2e's fake pnpm and Vite, with language-server installs turned off, hence "vtsls isn't installed" in the status bar.)

Design notes

  • Debug-area terminal, not an editor tab: that's where Run's output already goes and what ⌘R shows; it keeps the editor panes' tabs alone and the dev server next to the app's console.
  • Stop with several things running is "the chosen target's run" rather than Xcode's which-one menu: choose the target and ⌘., or close the run's terminal tab.

Testing

  • cargo test passes; no new clippy warnings. New unit tests: script discovery, package-manager choice, URLs, every issue format, line splitting, the PTY output tap, signal mask and group kill.
  • New e2e section "Running web apps" (9/9) on a copy of HelloWeb with a fake pnpm/npm and a fake Vite: the menu, running beside the app, the URL opened (recorded via ZCODE_OPEN_URL_LOG), the error at counter.ts:3:11, Stop ending the dev server and its child, MCP, the choice after a relaunch and quitting, a plain folder and a failing script.
  • Full e2e run once: 274 passed, 16 failed. The MCP failure was this branch's (an error message) and is fixed. Organizer, macOS signing, multibuffer and prediction checks passed when rerun alone. The typing-latency and idle checks failed on frame cadence and window focus on this machine; main failed the same latency check in a back-to-back run.
  • Cold launch 243 ms (limit 250 ms).

Limitations are in docs/limitations.md; roadmap 5.3 is ✅, with a parity.md row and updated features/MCP/testing/architecture docs.

🤖 Generated with Claude Code

…age product or a web app's package.json script. The scheme menu (and Choose Scheme…, ⌃0; Next / Previous Scheme step through them too) has a section per web app, named for its folder ("web"), listing its scripts in package.json's order; choosing one makes ⌘R run it, the toolbar reads "dev › web (pnpm)" and the destination menu says a script has no run destination instead of listing simulators. A plain folder with a package.json is runnable this way (its first script chosen) instead of "No Scheme". Build, Test, Profile and Archive keep the project's scheme. The choice comes back with the session (ProjectSession::run_script); Edit Scheme… with a script chosen opens package.json at it. A script runs with the package manager its packageManager field or lockfile implies (bun.lock/bun.lockb, pnpm-lock.yaml, yarn.lock, package-lock.json, in its folder or a folder above it in the project; npm otherwise), as `exec <pm> run <script>` in its folder, with its node_modules/.bin (and a monorepo's above it) before the login shell's PATH, on a PTY in a terminal of the debug area's Terminal tab named "web: dev", shown without taking the keyboard; running it again ends the earlier run and takes its terminal's place, and run terminals aren't restored as shells. It runs beside the scheme's build and app: running the app doesn't touch a dev server and running a script doesn't stop the app. Stop (⌘.) ends the chosen target's run: a running chosen script's, otherwise the build, app and debugger, and only when none of those is going, the scripts; closing a run's terminal ends it too. The activity view says "Running web: dev" when a script is what's going on, and shows running scripts' URLs as chips that open them again. What a script prints is read as it comes: the PTY alacritty_terminal reads is wrapped (TapPty, through the polling crate's types it registers with, already built) so its output also goes, as plain lines (terminal/lines.rs: ANSI stripped, carriage returns and moves to column 1 resolved), to the workspace; build/web.rs takes the first local URL (Vite's Local:, Next, webpack-dev-server's Loopback:, astro dev, any http://localhost:NNNN or 127.0.0.1; 0.0.0.0 and [::] made localhost) and opens it in the browser once per window (web.open_dev_server_url, on by default; ZCODE_OPEN_URL_LOG records it instead), and reads errors and warnings as build issues: tsc's file(line,col) and pretty file:line:col - error TS…, esbuild's ✘ [ERROR] with its location on a later line, Vite's Internal server error with the path inline or a File: line below (or the importer of a failed import), ESLint's stylish and unix formats, and path:line:col: error:/ERROR:, relative paths against the web app's folder. They join the Issue navigator and the editors' inline diagnostics until the script runs again, clear when a watcher starts over (tsc's File change detected, Vite's hmr update and page reload), and a run that fails adds its exit code (127: the package manager isn't on the PATH). Terminals now fork with no signals blocked: GCD's threads block SIGHUP, a child inherits that, and a program that doesn't reset it (a dev server, unlike a shell) never got the hang-up, so quitting zcode left it running under launchd; Stop also SIGKILLs whatever of the group outlives the leader by a second. MCP: XcodeListSchemes lists the scripts after the schemes ("web: dev") with run_targets giving each one's kind (xcode_scheme, swift_package_product, web_script, with its folder, command and package manager); XcodeSwitchScheme and the tools' scheme argument take them; RunProject runs a chosen script and returns its first output, URL and errors after wait_seconds; StopProject takes an optional scheme; GetConsoleOutput lists running scripts and reads one's output with scheme. dump has web and scheme_menu; control commands scheme <name> and web-url <n>. Unit tests: discovery (order, node_modules and script-less files skipped), the package manager from lockfiles, packageManager and a monorepo's root, PATH folders, URLs, every issue format and a watcher starting over, line splitting, a tapped PTY with the asked-for PATH, a SIGHUP-ignoring child ended by Stop, no signals blocked in the child. e2e (Running web apps, a copy of HelloWeb with a fake pnpm and npm on PATH and a fake Vite in node_modules/.bin that prints its URL in Vite's colors and a TypeScript error, then serves with a child): the scheme menu's web section and pnpm from the lockfile; ⌘R running pnpm run dev in web/ with node_modules/.bin first on PATH in a terminal named web: dev while the package's app keeps running; the URL opened once and again from the activity view; the error at counter.ts:3:11 in the Issue navigator and the editor; the app run again and stopped with the dev server untouched; ⌘. ending the dev server and its child; MCP's run targets, RunProject, GetConsoleOutput and StopProject on the script; the choice after a relaunch and quitting ending its run; a plain folder with npm, a failing script's error and exit code, and ⌘. stopping what runs. Docs: roadmap 5.3 ✅, a parity row, features, MCP, limitations, testing, architecture, README.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant