Skip to main content

launch

Launch Code OSS (VS Code from sources) into an isolated throwaway profile with unique debug ports so you can drive it with @playwright/cli AND attach a Node debugger via dap-cli in the same session. Use when working on VS Code itself and you want to interact with the running workbench, automate chat or UI flows, test UI features, take screenshots, set breakpoints in the renderer / extension host / main process, or combine UI driving with debugging.

Quellinformationen

Repository
devdotfast/whiteboard
Letzte Quellaktivität
23. September 2026 um 18:54
Erkannte Sprache von SKILL.md
Englisch
Sterne
2.054
Forks
91

Installationsoptionen

Standardmäßig ist der Prompt ausgewählt, der zuerst die Quelle prüft. Sie können zu einem direkten Befehl wechseln oder eine lokale Kopie herunterladen.

Quelldateien prüfen

Lesen Sie SKILL.md und alle von SkillsMP angezeigten Begleitdateien, bevor Sie sich für eine Installation entscheiden.

Datei-Explorer
3 Dateien

SKILL.md wird angezeigt

SKILL.md
Quellanweisungen · Schreibgeschützte Vorschau
name
launch
description
Launch Code OSS (VS Code from sources) into an isolated throwaway profile with unique debug ports so you can drive it with @playwright/cli AND attach a Node debugger via dap-cli in the same session. Use when working on VS Code itself and you want to interact with the running workbench, automate chat or UI flows, test UI features, take screenshots, set breakpoints in the renderer / extension host / main process, or combine UI driving with debugging.
# Code OSS Dev - Launch + Debug You're working on VS Code itself and you want to: 1. Launch a Code OSS build from sources that is **already signed in** (Copilot, GitHub, etc.) so chat / agent flows work end-to-end. 2. Drive it with `@playwright/cli` over CDP (UI automation). 3. Optionally attach a debugger via **dap-cli** to set breakpoints in the renderer, extension host, or main process. 4. Run multiple instances at once without port conflicts. This skill provides a launcher that clones an authenticated user-data-dir to a throwaway temp folder, picks free ports for every debug surface, and prints them as JSON so you can pick them up programmatically. The clone is **slim**: workspace storage, browser caches, file history, cached VSIX backups, and old logs are excluded by default. Auth tokens themselves live in the OS keychain (shared automatically) plus small files inside `User/globalStorage` - both of which *are* preserved. ## Prerequisites - macOS or Linux. The launcher is a bash script and depends on `rsync`, `curl`, `nohup`, and Node on `PATH`. The example caller snippets below also use `jq` (parse the JSON output) and `lsof` (kill-by-port fallback) — install those if you plan to use them, but the launcher itself does not require them. - A VS Code checkout with `node_modules/` installed (`npm install` if missing — do **not** symlink from a sibling worktree; that breaks builds in subtle ways). - A VS Code checkout with sources built. Run `npm run compile` once (one-shot) or `npm run watch` for incremental rebuilds. Both build the full client **and** all built-in extensions under `extensions/`. You must build the full product to run successfully, building just the client is not enough. - An **authenticated** Code OSS profile to seed from. By default the launcher uses `~/.vscode-oss-dev`, which is the user-data-dir the repo's `launch.json` configs use - if the user has ever signed in to Copilot in a dev build, this should work. Only pass `--source-user-data-dir <path>` (or set `$CODE_OSS_DEV_AUTHED_USER_DATA_DIR`) when you specifically want to seed from a different profile (e.g. your regular `~/Library/Application Support/Code` install). - If Code OSS launches and needs a sign-in, don't give up! Use the questions tool to ask the user to sign in. - `@playwright/cli` available (it's a devDependency in the vscode repo - `npm install` then use `npx @playwright/cli`). - For debugger work: `dap-cli` on `PATH`. If debugger support would be useful but the `dap-cli` skill is not present, prompt the user to install it from https://github.com/roblourens/dap-cli. - CSS selectors are internal implementation details. If a selector-based `eval` stops working, take a fresh `snapshot`, inspect the current DOM, and update the selector rather than assuming an old one still applies. > The launcher **copies** the source profile to a temp dir and never mutates the original. Each launch gets its own isolated `--user-data-dir` and `--extensions-dir`. > The launcher always sets `files.simpleDialog.enable: true` in the launched profile's `User/settings.json`. This is required for automation: VS Code's native OS file dialogs cannot be driven via `@playwright/cli` over CDP and are completely unreachable over SSH on headless macOS. The simple (quick-input) dialog can be navigated with `press` and clipboard paste. The override is per-launch and only affects throwaway profiles. ## Launch The launcher script lives next to this SKILL.md at `scripts/launch.sh`. Resolve it relative to wherever this skill file is installed - do not hardcode an absolute path. ```bash # LAUNCH=<dir-of-this-SKILL.md>/scripts/launch.sh "$LAUNCH" # default: workbench "$LAUNCH" -- <workspace-path> # forward extra args to code.sh "$LAUNCH" --source-user-data-dir <path> # pick a specific authed profile "$LAUNCH" --repo <vscode-repo-root> # if not run from the repo "$LAUNCH" --clone-extensions # start with a copy of the source extensions/ (~few seconds) "$LAUNCH" --full # skip slim excludes; copy everything ``` ### What gets copied (slim mode, the default) The exclude list mirrors the one used by VS Code's own perf-test skill (`.github/skills/auto-perf-optimize`), which is known to keep Copilot auth and language-model availability working. Specifically `WebStorage/`, `Service Worker/`, `Local Storage/`, `Cookies`, `Network Persistent State`, `TransportSecurity`, `Trust Tokens`, `Preferences`, `machineid`, and the entire `User/globalStorage/` (which holds `state.vscdb` - where extension `SecretStorage` blobs live, encrypted with the OS keychain key) are all preserved. Auth tokens themselves stay in the OS keychain, which is per-user, so they follow automatically. Excluded (transient, regenerable, or known-not-needed): - `User/workspaceStorage/` - per-workspace state, **including stored chat sessions** (often multi-GB) - `User/History/` - local file edit history - `CachedExtensionVSIXs` - backup VSIXs (hundreds of MB) - `logs` - Chromium caches: `Cache`, `Code Cache`, `CachedData`, `GPUCache`, `ShaderCache`, `Dawn*Cache`, `component_crx_cache` - `Backups`, `blob_storage`, `BrowserMetrics`, `Crashpad`, `Session Storage` - `Singleton*`, `*.lock`, `*.sock` (would conflict with the source instance) `extensions/` defaults to a **fresh empty directory** - fastest and conflict-free, but the launched instance starts with no third-party extensions installed. Pass `--clone-extensions` to copy the source extensions dir into the temp profile so the new instance is independent of the source. Pass `--full` to skip all excludes if you suspect the slim copy is missing something you need. > **Why never share the source `extensions/` dir directly?** The extension management service writes a shared `.obsolete` file; two concurrent writers crash each other's shared background process. The launcher always uses an isolated extensions dir for the same reason it uses `--shared-data-dir` (see below). > If the launched window says "language model unavailable" or otherwise looks unauthed, ask the user to sign in. The script runs pre-launch (electron download, compile-if-missing, built-in extensions) **in the foreground**, then starts Code OSS detached and **blocks until the renderer's CDP endpoint is responding** (up to ~90s) before printing the JSON line on stdout. If anything fails — preLaunch errors, code.sh exits early, CDP never opens — the script exits non-zero and dumps the relevant log tail to stderr. ```json {"pid":12345,"cdpPort":53111,"extHostPort":53112,"mainPort":53113,"agentHostPort":53114,"userDataDir":".../user-data","extensionsDir":".../extensions","sharedDataDir":".../shared-data","runDir":"...","logFile":".../code.log","repo":"..."} ``` Capture it with `jq` — no retry loop needed, CDP is already up when the JSON is printed: ```bash INFO=$("$LAUNCH" | tail -n1) CDP=$(jq -r .cdpPort <<<"$INFO") EXT=$(jq -r .extHostPort <<<"$INFO") MAIN=$(jq -r .mainPort <<<"$INFO") AGENT=$(jq -r .agentHostPort <<<"$INFO") LOG=$(jq -r .logFile <<<"$INFO") PID=$(jq -r .pid <<<"$INFO") ``` ### What each port is for | Port | Process | Use with | |------|---------|----------| | `cdpPort` (`--remote-debugging-port`) | Renderer (the workbench window) | `@playwright/cli` over CDP, also Chrome DevTools | | `extHostPort` (`--inspect-extensions`) | Extension host (Node) | `dap-cli` (Node inspector protocol) | | `mainPort` (`--inspect`) | Electron main process (Node) | `dap-cli` (Node inspector protocol) | | `agentHostPort` (`--inspect-agenthost`) | Agent host process (Node) | `dap-cli` (Node inspector protocol) | ## Drive the UI with @playwright/cli Use the dynamic `cdpPort` from the launch JSON. The normal loop is: attach, confirm the target, snapshot, interact, then re-snapshot after meaningful UI changes. > **Always pick a unique `PW_SESSION` name and pass it as `-s=$PW_SESSION`** on every `npx @playwright/cli ...` call. The CLI is backed by a persistent daemon (`cliDaemon.js`) keyed by session name; if two shells both omit `-s=`, they share the implicit `"default"` session and the most-recently-attached CDP "wins" for every subsequent command from either shell. The launch skill is built around isolation (per-instance UDD, ports, shared-data-dir), and this pattern keeps that isolation intact at the Playwright-driving layer too. **A note on the alternative `PLAYWRIGHT_CLI_SESSION` env var:** it's documented in the package README and works correctly for `open`-style workflows, but it interacts poorly with `attach --cdp=...` (the daemon ends up with both `--cdp=...` and `--endpoint=<env-value>`, and the latter wins, causing a `connect ENOENT` failure). Confirmed against `@playwright/cli@0.1.13`. Explicit `-s=NAME` works in all modes. ```bash # At the top of your script / subagent prompt: PW_SESSION="my-uniq-$$" # any unique string; $$ is fine for one shell per agent # launch.sh blocks until CDP is ready, so a single attach is enough. npx @playwright/cli -s=$PW_SESSION attach --cdp=http://127.0.0.1:$CDP npx @playwright/cli -s=$PW_SESSION tab-list npx @playwright/cli -s=$PW_SESSION snapshot ``` After `attach`, later `@playwright/cli` commands keep using the connected app until you close or reattach — as long as you keep passing the same `-s=$PW_SESSION`. ### Selecting the right Electron target Electron apps can expose multiple windows or webviews. If `tab-list` shows `about:blank`, a webview, or otherwise the wrong target, switch targets before interacting: ```bash npx @playwright/cli -s=$PW_SESSION tab-list npx @playwright/cli -s=$PW_SESSION tab-select 2 npx @playwright/cli -s=$PW_SESSION snapshot ``` If a target looks stale after relaunching, run `npx @playwright/cli -s=$PW_SESSION close`, attach again with `$CDP`, and re-check `tab-list`. ### Focusing the chat input ```bash # macOS npx @playwright/cli -s=$PW_SESSION press Control+Meta+i # Linux / Windows npx @playwright/cli -s=$PW_SESSION press Control+Alt+i ``` ### Typing into Monaco (chat input, editors) `fill` and `type` **silently fail** on Code OSS — Monaco's `native-edit-context` element doesn't react to Playwright's default input pipeline. Use one of these alternatives: - **`scripts/monaco-paste.sh` helper** (recommended — fast, no system clipboard, parallel-safe). Reads text from a positional arg or stdin and dispatches a `ClipboardEvent('paste')` with a `DataTransfer` payload into the focused chat-input Monaco editor. Honors `--session NAME` or `$PW_SESSION` env so it stays inside the same `-s=` session as everything else. ```bash LAUNCH_DIR=<dir-of-this-SKILL.md> # the same dir that holds scripts/launch.sh PASTE="$LAUNCH_DIR/scripts/monaco-paste.sh" export PW_SESSION # helper reads this env var # Send a prompt: npx @playwright/cli -s=$PW_SESSION press Control+Meta+i # focus chat input "$PASTE" 'Please run `pwd && ls` using your terminal tool.' npx @playwright/cli -s=$PW_SESSION press Enter # Long / arbitrary text via stdin (avoids any shell-quoting headaches): printf 'multi-line prompt\nwith backticks `x`\nand emoji 🎉' | "$PASTE" # Append without clearing: "$PASTE" --append " continued text" # Skip the read-back check (useful when intentionally pasting more than the # chat input's ~600-character soft cap): "$PASTE" --no-verify "...long text..." # Or pass the session explicitly per call (if you don't want to export PW_SESSION): "$PASTE" --session "$PW_SESSION" "..." ``` The helper prints a single JSON line on stdout: `{ok, actualLength, expectedLength, viewLineCount, firstViewLine, error?}`. Exit 0 on success, 1 on verify failure, 2 on argument errors. Tested reliable across 20+ sequential pastes including unicode (中文), emoji (🎉), backticks, ampersands, embedded quotes, and newlines. **Why a helper script and not just docs:** the inline recipe involves a multi-line `node -e` heredoc with embedded JS template literals, which is exactly the kind of code that gets miscopied. There are also three non-obvious correctness traps the helper handles internally: 1. Monaco's `native-edit-context` doesn't react to `fill` or `type`, only to actual paste events (or per-key `press`). 2. Monaco renders ASCII spaces as U+00A0 (NBSP) in the view-line DOM, so verification has to normalize before comparing. 3. Monaco updates its DOM **asynchronously** after a paste event — a synchronous read-back inside the same `eval` returns stale state. The helper waits two `requestAnimationFrame` ticks before reading. - **Per-key `press`** (universal but slow — each press is a separate CLI invocation with Node startup cost): ```bash npx @playwright/cli -s=$PW_SESSION press H npx @playwright/cli -s=$PW_SESSION press i npx @playwright/cli -s=$PW_SESSION press Enter ``` - **Clipboard paste via `pbcopy`** (fast on macOS, **but `NSPasteboard` is system-wide so any concurrent shell that touches the pasteboard will collide**). Only use when nothing else on the machine is using the clipboard for the duration of the paste. ```bash printf '%s' "Your prompt here" | pbcopy npx @playwright/cli -s=$PW_SESSION press Control+Meta+i npx @playwright/cli -s=$PW_SESSION press Meta+v npx @playwright/cli -s=$PW_SESSION press Enter ``` The focus shortcut should leave `document.activeElement` on VS Code's `native-edit-context` editing surface. That is a useful sanity check when key presses appear to do nothing. ### Parallel multi-instance pattern Because the launch skill is built around isolation, the natural workload is **many agents on one machine, each driving their own Code OSS**. The pattern boils down to giving each agent a unique `PW_SESSION` and passing it everywhere: ```bash # In agent A's shell: PW_SESSION="agent-A-$$" INFO=$("$LAUNCH" -- --use-mock-keychain | tail -n1) CDP=$(jq -r .cdpPort <<<"$INFO") npx @playwright/cli -s=$PW_SESSION attach --cdp=http://127.0.0.1:$CDP "$PASTE" "prompt for A" # helper picks up $PW_SESSION # In agent B's shell (running concurrently): PW_SESSION="agent-B-$$" INFO=$("$LAUNCH" -- --use-mock-keychain | tail -n1) CDP=$(jq -r .cdpPort <<<"$INFO") npx @playwright/cli -s=$PW_SESSION attach --cdp=http://127.0.0.1:$CDP "$PASTE" "prompt for B" ``` Each agent gets its own `cliDaemon` bound to its own CDP, so the pastes / clicks / snapshots don't cross-contaminate. Verified live with two concurrent instances. **macOS Mach-ports caveat:** on macOS, beyond ~2–3 concurrent Code OSS instances Crashpad's exception handler tends to die with `mach_port_request_notification: invalid capability`. That's a separate, OS-level limit; it's not affected by the session name. > **Cleanup for `cliDaemon` processes:** stop your session's daemon with `npx @playwright/cli -s=$PW_SESSION close`, or nuke all stale daemons (after killing all the Code OSS windows) with `npx @playwright/cli kill-all`. Session daemons live under `~/Library/Caches/ms-playwright/daemon/<hash>/`. ### Verifying and clearing chat text For the regular workbench sidebar, this confirms that text landed in the Monaco input: ```bash npx @playwright/cli -s=$PW_SESSION eval ' (() => { const sidebar = document.querySelector(".part.auxiliarybar");
Auf GitHub ansehen
Diese SKILL.md ist sehr gross, daher zeigt SkillsMP hier nur den ersten Abschnitt. Auf GitHub ansehen