Repository navigation
feat: expose inverse, strikethrough, faint, invisible and cursorVisible in snapshots - #17
Conversation
…le in snapshots Read the remaining SGR flags from GhosttyStyle and DECTCEM from GHOSTTY_TERMINAL_DATA_CURSOR_VISIBLE. Cell flags are omitted when unset, matching bold/italic/underline. inverse is the raw attribute; colors are not swapped. Closes #15 Change-Id: I4e10cde9ffd9e8b79171b1945692e9560664ffb2 Signed-off-by: Thomas Kosiewski <tk@coder.com>
|
@codex review |
|
@codex security review |
Codex Review SummaryThis comment shows the latest Codex review activity on this pull request.
ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings. |
|
Codex Review: Didn't find any major issues. Another round soon, please! Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
|
@codex security review |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
Change-Id: Ie65e53e94e4f4aa09e80eef7db8146c9e6db4588 Signed-off-by: Thomas Kosiewski <tk@coder.com>
|
@codex review |
|
@codex security review |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 232796f289
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
The contract READMEs from #29 listed the snapshot and cell keys before this branch added cursorVisible, faint, inverse, invisible and strikethrough, and said no test covered the cell style fields. _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_ Change-Id: I9f66ac8d3bf878041531e1500c53416c92f92651 Signed-off-by: Thomas Kosiewski <tk@coder.com>
|
@codex review |
|
@codex security review |
|
Codex Review: Didn't find any major issues. You're on a roll. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
PASS+NOTES I verified the behavior at I packed each commit with the repo's
Journey exit codes: claims parent 1 / head 0, edges parent 1 / head 0, types-node parent 1 / head 0, observe parent 0 / head 0. Edge cases I triedAt the head 8/8 asserted edge checks pass. At the parent 0/8 pass.
NotesNeither note blocks the merge.
Docs at
|
Change-Id: I2a52cfff2d6055fc897033edd6c3f05166729371 Signed-off-by: Thomas Kosiewski <tk@coder.com>
|
@codex review |
|
@codex security review |
|
Codex Review: Didn't find any major issues. Chef's kiss. Reviewed commit: ℹ️ About Codex in GitHubYour team has set up Codex to review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. Codex can also answer questions or update the PR. Try commenting "@codex address that feedback". |
🛡️ Codex Security ReviewSecurity review completed. No security issues were found in this pull request. Reviewed commit: Only the user who started this review can view the report in Codex. ℹ️ About Codex security reviews in GitHubThis is an experimental Codex feature. Security reviews are triggered when:
Once complete, Codex will leave suggestions, or a comment if no findings are found. |
|
PASS+NOTES I re-verified after the merge of main. I tested PR head After my run,
At both commits, the stdout of claims, observe, edges, and types-node is byte-identical to my earlier run on The merged Both notes from my earlier verdict still hold. DECSTR ( Generated with |
…CSTR limit (#38) Closes #36 ## Why Snapshots from the native binding always carry `cursorVisible`, but the type marked it optional, so every reader had to handle `undefined`. Separately, a DECSTR soft reset (`ESC[!p`) leaves the cursor hidden, and nothing said so. ## What changed - `TerminalSnapshot.cursorVisible` is now required (`boolean`), in `src/types.ts` and the `src/README.md` contract. - The README says the pinned Ghostty ignores DECSTR and that RIS (`ESC c`) still resets. A test pins that behavior. ## Scope - Supporting DECSTR needs a Ghostty upgrade that requires Zig 0.16 and a new C API. That is tracked in #37, not done here. ## Tradeoffs - Keeping the field optional was the compatibility choice in #17. No published release has `cursorVisible` yet (`0.1.0-beta.1` predates it), so making it required now breaks no released consumer. ## Blast Radius Code that builds its own `TerminalSnapshot` must now set `cursorVisible`. coder/agent-tty does this in `assertNativeSnapshot` and will get TS2741 when it upgrades. That is the line where it currently drops the field. Readers are unaffected. ## Verification - `npm run build`, `typecheck`, `test` (68 passed) and `smoke` pass locally. - I packed `main` and this branch and compiled a strict consumer against each. `const v: boolean = snapshot().cursorVisible` fails with TS2322 on `main` and compiles here. A `TerminalSnapshot` literal without the field compiles on `main` and fails with TS2741 here. - Through the package, `ESC[?25l ESC[7m ESC[!p` leaves `cursorVisible: false` and `inverse: true`. A following `ESC c` gives `cursorVisible: true` and no attributes. --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
## Why Ship the changes merged since `0.1.0-beta.1` to npm. They include mode-aware mouse encoding (#12), the new snapshot attributes and `cursorVisible` (#17, #38), and Ghostty `v1.4.0` with DECSTR support (#43). ## What changed - `package.json` and `package-lock.json` go from `0.1.0-beta.1` to `0.1.0-beta.2`. The branch name matches the version, so `publish.yml` creates `v0.1.0-beta.2` after merge. - The `release-changelog` workflow adds the CHANGELOG entry to this branch. - `communique.toml` raises `max_tokens` to 16384. With Communique 1.0.3's default of 4096, generating these notes failed twice with "submit_release_notes was malformed 3 times". The next run succeeded. - `prepare-release-changelog.mjs` now detects Communique's `## [vX](url) - date` heading. Before, every push regenerated the entry over hand edits. - I corrected the generated entry. `cursorVisible` and `encodeMouse` first ship in this release, so they are listed as Added, not as changes or fixes. ## Blast Radius The merge publishes `0.1.0-beta.2` to npm under the `beta` dist-tag. `latest` stays on `0.1.0-beta.0`. Consumers that build a `TerminalSnapshot` themselves must now set `cursorVisible` (#38). ## Verification - `RELEASE_BRANCH_NAME=release/v0.1.0-beta.2 node .github/scripts/prepare-release-changelog.mjs origin/main` prints `should_generate=true` and `tag_name=v0.1.0-beta.2`. `resolve-npm-publish-tag.mjs` prints `beta`. - `npm run typecheck` and `npm test` (73 passed). - Three independent verifier passes, the last PASS+NOTES on the head. They check every CHANGELOG bullet against the `v0.1.0-beta.1` tag and confirm that the packed tarball loads its addon from `prebuilds/`. - The local linux-x64 prebuild steps from `mise run release-prebuilds` pass: `build:libghostty`, `build`, `build:prebuild`, `verify:prebuilds` and `npm pack --dry-run`. --- _Generated with [`xum`](https://github.com/coder/xum) • Model: `anthropic:claude-opus-5-5` • Thinking: `high`_
Closes #15
Summary
Snapshots now expose the remaining SGR cell attributes and DECTCEM cursor visibility, so coder/agent-tty (coder/agent-tty#171) can render reverse video, strikethrough, dim and hidden text, and hide the cursor.
SnapshotCellgains optionalfaint(SGR 2),inverse(SGR 7),invisible(SGR 8) andstrikethrough(SGR 9).bold/italic/underline: the key is present withtrueonly when set, and omitted otherwise.inverseis the raw attribute.foreground/backgroundare not swapped.TerminalSnapshotgainscursorVisible?: boolean. The native binding always sets it (true/false); the type is optional for compatibility.GhosttyStyle.{faint,inverse,invisible,strikethrough}via the existingghostty_grid_ref_stylecall, andghostty_terminal_get(GHOSTTY_TERMINAL_DATA_CURSOR_VISIBLE). No new libghostty entry points.CHANGELOG.mdis not hand-edited: therelease-changelogworkflow generates it with Communique onrelease/v*PRs.Existing fields are unchanged.
Tests (written first, red before the native change)
ESC[1;2;3;4;7;8;9m).ESC[31;42mcolors.cursorVisible: defaulttrue,ESC[?25lgivesfalse(with and withoutincludeCells),ESC[?25hgivestrue.Validation
npm run build:libghostty(pinned Ghostty 48ccec18, Zig 0.15.2)npm run build:nativenpm run buildnpm run typecheck(and an ad hoctscrun includingtest/)npm testnpm run smokeThe repo has no lint script.
Dogfood
A standalone Node ESM script imports
@coder/libghostty-vt-node(linked to this branch's build), feedsESC[?25l, thenESC[31;42;7mI ESC[27mi ESC[0m ESC[9mS ESC[29ms ESC[2mF ESC[22mf ESC[8mH ESC[28mh ESC[1;2;7;8;9mX ESC[0mx, thenESC[?25h, and printssnapshot({ includeCells: true }):Script
Output (one cell per line):
{"cursorSteps":[{"label":"initial","cursorVisible":true,"cursorRow":0,"cursorCol":0},{"label":"after ESC[?25l","cursorVisible":false,"cursorRow":0,"cursorCol":0},{"label":"after ESC[?25h","cursorVisible":true,"cursorRow":0,"cursorCol":14}],"line0":"Ii Ss Ff Hh Xx"} {"row":0,"col":0,"text":"I","width":1,"inverse":true,"foreground":"#cc6666","background":"#b5bd68"} {"row":0,"col":1,"text":"i","width":1,"foreground":"#cc6666","background":"#b5bd68"} {"row":0,"col":2,"text":" ","width":1} {"row":0,"col":3,"text":"S","width":1,"strikethrough":true} {"row":0,"col":4,"text":"s","width":1} {"row":0,"col":5,"text":" ","width":1} {"row":0,"col":6,"text":"F","width":1,"faint":true} {"row":0,"col":7,"text":"f","width":1} {"row":0,"col":8,"text":" ","width":1} {"row":0,"col":9,"text":"H","width":1,"invisible":true} {"row":0,"col":10,"text":"h","width":1} {"row":0,"col":11,"text":" ","width":1} {"row":0,"col":12,"text":"X","width":1,"bold":true,"faint":true,"inverse":true,"invisible":true,"strikethrough":true} {"row":0,"col":13,"text":"x","width":1}The uppercase cells carry the attribute, and the lowercase cells after each reset do not.
Ikeeps#cc6666on#b5bd68(palette 1 on palette 2), the same as unswappedi.Notes for agent-tty
foreground/backgroundyourself, substituting your default colors when either one is absent.invisiblecells still report their text, andvisibleLines/getVisibleText()still include hidden text (unchanged). Skip drawing glyphs forinvisiblecells.cellsonly contains cells with text. Erased cells that have only a background color (for example, anESC[Kstatus bar fill) are not emitted.Generated with
xum• Model:anthropic:claude-opus-5-5• Thinking:high