Skip to content

fix(tui): wrap diff and tool output at grapheme boundaries - #6829

Merged
Hmbown merged 2 commits into
codewhale-hq:mainfrom
Lstarsky0:fix/tui-wrap-graphemes
Oct 3, 2026
Merged

Hmbown merged 2 commits into
codewhale-hq:mainfrom
Lstarsky0:fix/tui-wrap-graphemes

Conversation

@Lstarsky0

Copy link
Copy Markdown
Contributor

What and why

9be600bf4 moved the markdown, ui_text and widget paths to grapheme clusters so keycaps, ZWJ emoji and combining sequences stay aligned with Ratatui's cell accounting (the #4479 class). Two wrap paths still go one char at a time:

  • diff_render's hard break for an overlong word in a diff line. At width 2 it turned ab👨‍👩‍👧👍🏽cd into ab, 👨\u{200d}, 👩\u{200d}, 👧, 👍, 🏽, cd: the family comes apart and the skin tone lands on its own line.
  • history::tool_output::wrap_text, which tool output, checklist items, commands and card detail lines go through. At width 3 it turned ab❤️cd into ab❤ and \u{fe0f}cd, so the heart loses its emoji form and the next line starts with a bare selector.

Both now step over graphemes, the same way markdown's push_word_breaking_graphemes does. diff_render no longer needs UnicodeWidthChar.

Issue

Refs #6561 (U04-m4)

How I tested it

  • cargo nextest run -p codewhale-tui --lib: 14533 passed, 2 failed. The two are mcp::http_client tests that fail here because of a local HTTP proxy; main fails them the same way and they pass with the proxy unset.
  • The two new tests fail without the change, with the splits shown above.
  • cargo clippy -p codewhale-tui --all-targets --all-features with CI's flags: nothing new compared to main.
  • cargo fmt --all -- --check only reports crates/tui/src/child_env.rs:1364, which main's Lint job fails on as well since 60ea7c2. This PR doesn't touch it.

Checklist

  • One focused change, rebased on current main
  • cargo fmt --all passes, and tests cover new or changed behavior
  • If this adds or changes a user-facing feature, I updated its docs and its row in docs/features.toml (cargo test -p codewhale-tui --test feature_registry checks it) — n/a

9be600b moved the markdown, ui_text and widget paths to grapheme
clusters. The diff renderer's overlong-word break and the tool-output
wrap still went one char at a time, so a line could end inside a ZWJ
emoji, before a skin-tone modifier, or right before U+FE0F. Step over
graphemes in both, as markdown's push_word_breaking_graphemes does.

Signed-off-by: Lstarsky0 <59827030+Lstarsky0@users.noreply.github.com>
@Lstarsky0
Lstarsky0 requested a review from Hmbown as a code owner October 3, 2026 04:51
@github-actions github-actions Bot added the contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm label Oct 3, 2026
…#6829

Preserve the original contributor commits; incoming source change is only
the reviewed child_env.rs formatting repair from ad43250.

Focused rustfmt check passed in the sealed source proposal.
Hosted test matrix remains separate and pending.

Signed-off-by: Hunter B <hmbown@gmail.com>
@Hmbown
Hmbown merged commit 239d003 into codewhale-hq:main Oct 3, 2026
26 checks passed
Hmbown pushed a commit that referenced this pull request Oct 3, 2026
Retain the real main parent 296c05d
and the original PR merge/commit ancestry for #6819 (@Guan0923), #6829 and
#6831 (@Lstarsky0), and #6830 (@SparkofSpike). Resolve the 19 reviewed
counterparts to the exact V22 product tree, including all 156 original
translated values and the original localization regression test.

Exact V22 local checks: Rust 1351/0/0; localization 54/0/0; CI-policy Clippy PASS.
CLI: 3 actual processes / 6 checks / 6 local fixture requests / 0 paid calls; approval, resume, cancellation and EOF effects passed.
npm test + check:web: 1180 passed / 0 failed / 7 explicit skips (wrapper101, SDK19, host378, website682); strict TypeScript and production web passed.
No contributor harvesting, runtime default flip, install or release claim.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
Hmbown pushed a commit that referenced this pull request Oct 4, 2026
Windows Native hosts: on 02fcc3e the LPAC token check and the data-directory
share conflict were fixed, and the isolation probe ran inside the LPAC for the
first time. Node then aborted at startup (WSAStartup 10107): an LPAC cannot
open any registry key without the registryRead capability, and Winsock reads
its catalog from the registry. Native hosts now receive exactly that one
capability (derived by name), and the token check requires exactly it; it
grants no file, network or COM access, and socket creation stays denied,
which the probe checks. Bun failed opening the NUL device (EPERM) for
--config=NUL: the plain Bun host now reads an empty config from the granted
runtime-copy directory, and the Windows compiled host relies on
--no-compile-autoload-bunfig instead of baking --config=NUL. Unprotected file
ACL edits now pass an explicit-only DACL to SetSecurityInfo with
UNPROTECTED_DACL_SECURITY_INFORMATION so Windows re-derives inherited entries
from the parent (a file has no children to propagate to); the kernel write had
turned a file's inherited entries explicit. ACL pointer reads use checked
NonNull access (CodeQL rust/access-invalid-pointer on 02fcc3e).

Windows atomic writes: Fleet's WorkspaceFile/WindowsDirectory pins, new in
0.10.1, keep every ancestor directory of a Fleet file open with read-only
sharing. MoveFileExW (tempfile::persist) reopens the destination directory
with FILE_ADD_FILE, so while a Fleet ledger is alive (a whole `codewhale
fleet` run, or a Runtime API request) Codewhale's own atomic writes into the
workspace root or its ancestors failed with os error 32. That includes
file-tool edits; hosted Windows showed it as a bare 500 writing mcp.json. On
Windows, write_atomic now creates its temp with DELETE access and renames
through that handle with a bare file name (the rename Fleet publication
already uses), so the parent is never reopened and no pin is relaxed. Names
Windows would rewrite (trailing dot or space, device names) are refused
before any temp exists, and every failure path closes the delete-denying
handle before removing the temp. MCP config write errors now name the file.
A Windows test writes and replaces a file beside live Fleet pins and checks
refused names leave no temp behind.

Wire JSON: the extension-host `isJson` guard used Array.every and
Object.values, so it accepted sparse arrays, extra array properties,
accessors and symbol keys that serialize differently from what was checked
(Copilot review on #6815). It now accepts only dense arrays and plain objects
whose own keys are enumerable string data properties, the rule storage.ts
already enforced; storage's duplicate check is removed. A new test fails on
the old guard and passes on the new one. Bundles that include the guard were
rebuilt with the pinned esbuild; the harness builtin digest pin in tier.rs
moves with it.

Release notes: credits and entries for #6820, #6829, #6830 and #6831, which
landed in 0.10.1 without CHANGELOG coverage, and for #6827 (Windows node.exe
kills are held by the built-in safety floor even in Full Access), crediting
@jayanthvee in the CHANGELOG, docs/CONTRIBUTORS.md, website credits and
public-surface facts.

Fixes #6827

Source15 verification (3,792 rows; owning HEAD cf03333 and index 5983aa54
unchanged):
- npm test and npm run check:web: 1,185 passed / 0 failed / 7 explicit skips
  (the website credit-parity test caught the first draft missing the new
  reporter credit);
  extension-host suite 390 tests, 383 passed, 0 failed, 7 skipped.
- macOS, compiled host rebuilt from the new bundle: extension_host 177/0,
  plugins::install::dsh 28/0, mcp 407/0, utils 38/0, tools::file 190/0,
  runtime_store_convergence 14/0, builtin digest table 2/0.
- Windows: cargo check --target x86_64-pc-windows-gnu of codewhale-tui lib
  and tests clean under deny(warnings); write_atomic change reviewed
  adversarially (FIX_FIRST findings applied: early-error temp cleanup, single
  retry layer, rewritten-name refusal). The LPAC capability, Bun config and
  file-ACL changes are type-checked only; their runtime proof is this head's
  hosted Windows run.

Hosted 02fcc3e: Safety, Lint, npm wrapper smoke and Test (ubuntu-latest)
passed. Windows 17,952 passed / 91 failed: LPAC runtime startup (Node
WSAStartup, Bun NUL config), one file-ACL hygiene test, the mcp.json write
conflict and one DSH HTTP case behind the probe, all addressed above. CodeQL
flagged five pointer reads, addressed above. Not proven here: Windows runtime
of these repairs.
This is source integration, not release, deploy, provider or install
approval.

Evidence: artifacts/gpt61-0101-takeover-20261002/parent-source15-application,
parent-source15-local, parent-source15-npm-web-actual, windows-gnu-check.

Signed-off-by: CodeWhale Bot <bot@codewhale.net>
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

contribution-gate Author not yet in .github/APPROVED_CONTRIBUTORS; a maintainer grants access with /lgtm

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants