From c31a29caf70632d6c7eae3168ca5b069f1b7c373 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Fern=C3=A1ndez?= Date: Fri, 29 May 2026 02:53:34 +0000 Subject: [PATCH 1/2] chore: publish under the @crunchloop scope Rename to @crunchloop/ghostty-web so the package publishes to the crunchloop-owned npm scope (the upstream `ghostty-web` name isn't ours). publishConfig already pins access: public, and the publish workflow's --provenance + OIDC trusted publishing works for scoped public packages. Co-Authored-By: Claude Opus 4.8 (1M context) --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 838c0e2..2c41259 100644 --- a/package.json +++ b/package.json @@ -1,5 +1,5 @@ { - "name": "ghostty-web", + "name": "@crunchloop/ghostty-web", "version": "0.4.1", "description": "Web-based terminal emulator using Ghostty's VT100 parser via WebAssembly", "type": "module", From 1ea8320b093982bb93a27acd68d4dd0585fa26f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Fern=C3=A1ndez?= Date: Fri, 29 May 2026 03:09:52 +0000 Subject: [PATCH 2/2] ci: fix pre-existing CI failures - test: use the lib-scoped `bun run test` instead of bare `bun test`. Bare `bun test` also collected the Playwright e2e specs (9 "Playwright Test did not expect test.describe()" errors); the 434 lib tests already pass. - build: raise the WASM size guard 512 KB -> 1 MB. The pinned ghostty now produces a ~625 KB ReleaseSmall wasm, which tripped the stale 512 KB check. - fmt: format docs/superpowers/plans/2026-05-24-e2e-playwright-coverage.md. Co-Authored-By: Claude Opus 4.8 (1M context) --- .github/workflows/ci.yml | 6 +- .github/workflows/publish.yml | 2 +- .../2026-05-24-e2e-playwright-coverage.md | 61 +++++++++++-------- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c86f429..d957e1d 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -78,7 +78,7 @@ jobs: run: bun install - name: Run tests - run: bun test + run: bun run test build: name: build @@ -103,8 +103,8 @@ jobs: run: | SIZE=$(stat -c%s ghostty-vt.wasm) echo "WASM size: $SIZE bytes" - if [ "$SIZE" -gt 524288 ]; then - echo "❌ Error: WASM exceeds 512 KB limit" + if [ "$SIZE" -gt 1048576 ]; then + echo "❌ Error: WASM exceeds 1 MB limit" exit 1 fi diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index 07a82d4..9e8aac4 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -55,7 +55,7 @@ jobs: run: bun run typecheck - name: Run tests - run: bun test + run: bun run test - name: Build library run: bun run build diff --git a/docs/superpowers/plans/2026-05-24-e2e-playwright-coverage.md b/docs/superpowers/plans/2026-05-24-e2e-playwright-coverage.md index 82f5099..851b6b8 100644 --- a/docs/superpowers/plans/2026-05-24-e2e-playwright-coverage.md +++ b/docs/superpowers/plans/2026-05-24-e2e-playwright-coverage.md @@ -18,18 +18,18 @@ All tasks below have been implemented. Test counts and pass status reflect the c ## Coverage Map -| Spec file | Tests | Status | -|-----------|-------|--------| -| `01-rendering.spec.ts` | 13 | ✅ all pass | -| `02-keyboard.spec.ts` | 5 | ✅ all pass | -| `03-scroll.spec.ts` | 8 | ✅ all pass | -| `04-selection.spec.ts` | 7 (2 skip) | ✅ 5 pass, 2 skip* | -| `05-resize.spec.ts` | 6 | ✅ all pass | -| `06-events.spec.ts` | 14 | ✅ all pass | -| `07-theme-options.spec.ts` | 9 | ✅ all pass | -| `08-addons.spec.ts` | 5 | ✅ all pass | -| `09-lifecycle.spec.ts` | 14 | ✅ all pass | -| **Total** | **81** | **✅ 81 pass, 2 skip** | +| Spec file | Tests | Status | +| -------------------------- | ---------- | ---------------------- | +| `01-rendering.spec.ts` | 13 | ✅ all pass | +| `02-keyboard.spec.ts` | 5 | ✅ all pass | +| `03-scroll.spec.ts` | 8 | ✅ all pass | +| `04-selection.spec.ts` | 7 (2 skip) | ✅ 5 pass, 2 skip\* | +| `05-resize.spec.ts` | 6 | ✅ all pass | +| `06-events.spec.ts` | 14 | ✅ all pass | +| `07-theme-options.spec.ts` | 9 | ✅ all pass | +| `08-addons.spec.ts` | 5 | ✅ all pass | +| `09-lifecycle.spec.ts` | 14 | ✅ all pass | +| **Total** | **81** | **✅ 81 pass, 2 skip** | \* `double-click selects a word` and `triple-click selects a line` are skipped: `getWordAtCell` calls `getLine()` which returns `invalid_value (-2)` from `ghostty_render_state_update` under @@ -41,13 +41,16 @@ Fix requires an explicit render-state warmup hook exposed to JS callers. ## Infrastructure Files ### `playwright.config.ts` + - Chromium only, serial (no parallelism), 1 retry, 15s timeout - `webServer`: `bun run dev` on `http://localhost:8000`, reuse existing - Trace on first retry, screenshot on failure, video on first retry - HTML + list reporters ### `tests/e2e/helpers/terminal.ts` + Helper functions available to all specs: + - `waitForTerminal(page)` — waits for `window.__ghosttyReady` - `termWrite(page, data)` — calls `__ghosttyTerm.write()` - `termReset(page)` — clears terminal to known state @@ -60,10 +63,11 @@ Helper functions available to all specs: - `hasRenderedContent(page)` — true if canvas has non-black pixels ### `demo/index.html` globals + ```javascript -window.__ghosttyTerm // Terminal instance -window.__ghosttyFitAddon // FitAddon instance -window.__ghosttyReady // true after open() +window.__ghosttyTerm; // Terminal instance +window.__ghosttyFitAddon; // FitAddon instance +window.__ghosttyReady; // true after open() ``` --- @@ -73,6 +77,7 @@ window.__ghosttyReady // true after open() **Covers:** Canvas mount, pixel content, buffer reads, ANSI SGR, cursor, wide chars, emoji, alternate screen. Tests: + - [ ] canvas is rendered on screen - [ ] canvas contains rendered pixels after write - [ ] plain text appears in buffer @@ -94,6 +99,7 @@ Tests: **Covers:** `input()`, `onData`, `disableStdin`, `attachCustomKeyEventHandler`, `onKey`. Tests: + - [ ] onData fires when input() is called with wasUserInput=true - [ ] onData does NOT fire when wasUserInput=false - [ ] disableStdin blocks input @@ -107,6 +113,7 @@ Tests: **Covers:** `scrollToTop`, `scrollToBottom`, `scrollLines`, `scrollPages`, `onScroll`, mouse wheel, `preserveScrollOnWrite`. Tests: + - [ ] scrollToTop moves viewport to start of scrollback - [ ] scrollToBottom returns to current output - [ ] scrollLines(N) moves viewport up by N @@ -123,6 +130,7 @@ Tests: **Covers:** `select`, `selectAll`, `clearSelection`, `hasSelection`, `getSelectionPosition`, `onSelectionChange`, mouse drag. Tests: + - [ ] hasSelection() is false initially - [ ] select() creates a selection - [ ] selectAll() selects all visible content @@ -140,6 +148,7 @@ Tests: **Covers:** `resize()`, `onResize`, `rows`, `cols`, `FitAddon.fit()`, container fill. Tests: + - [ ] terminal has valid initial dimensions - [ ] resize() updates cols and rows - [ ] onResize fires with new dimensions @@ -154,6 +163,7 @@ Tests: **Covers:** `onBell`, `onTitleChange`, `onLineFeed`, `onWriteParsed`, `onCursorMove`, `onRender`, OSC 133 (shell integration), OSC 22 (cursor shape), focus events (mode 1004). Tests: + - [ ] onBell fires on BEL character - [ ] onTitleChange fires on OSC 0 - [ ] onTitleChange fires on OSC 2 @@ -176,6 +186,7 @@ Tests: **Covers:** `options.theme`, `options.fontSize`, `options.cursorBlink`, `options.scrollback`, `options.convertEol`, `options.emitTerminalResponses`, `clear()`, `reset()`. Tests: + - [ ] theme background is applied to canvas container - [ ] options.fontSize can be read - [ ] options.cursorBlink can be set dynamically @@ -193,6 +204,7 @@ Tests: **Covers:** `loadAddon`, `FitAddon.fit()`, `FitAddon.proposeDimensions()`, addon lifecycle. Tests: + - [ ] FitAddon is loaded and fit() is callable - [ ] FitAddon proposeDimensions() returns valid size - [ ] loadAddon activates a custom addon @@ -206,6 +218,7 @@ Tests: **Covers:** `write`, `writeln`, write callbacks, `dispose`, `buffer.active/normal/alternate`, `getCell`, `markers`, `unicode`, mode queries. Tests: + - [ ] write() throws after dispose() - [ ] writeln() appends CRLF - [ ] write() with callback invokes callback @@ -227,15 +240,15 @@ Tests: The following features exist in the library but are not yet covered by E2E tests: -| Feature | API | Reason not covered | -|---------|-----|--------------------| -| IME input | textarea position | Requires OS-level IME simulation | -| Clipboard paste | Ctrl+V / right-click paste | Requires clipboard permissions in headless | -| Mouse tracking responses | mode 1000/1002/1003 | Requires PTY round-trip | -| Kitty keyboard protocol | CSI responses | Requires PTY round-trip | -| Synchronized output (mode 2026) | defer render | Timing-sensitive, needs dedicated test harness | -| Scrollback line access | `getScrollbackLine()` | Accessible via `SelectionManager` internals | -| `getSelection()` text | Returns rendered text | WASM render state unavailable outside render frame | +| Feature | API | Reason not covered | +| ------------------------------- | -------------------------- | -------------------------------------------------- | +| IME input | textarea position | Requires OS-level IME simulation | +| Clipboard paste | Ctrl+V / right-click paste | Requires clipboard permissions in headless | +| Mouse tracking responses | mode 1000/1002/1003 | Requires PTY round-trip | +| Kitty keyboard protocol | CSI responses | Requires PTY round-trip | +| Synchronized output (mode 2026) | defer render | Timing-sensitive, needs dedicated test harness | +| Scrollback line access | `getScrollbackLine()` | Accessible via `SelectionManager` internals | +| `getSelection()` text | Returns rendered text | WASM render state unavailable outside render frame | ---