Repository navigation
Conversation
sirmalloc#575 moved the TUI behind import('./tui'), but eleven widget modules (CustomText, CustomSymbol, CustomCommand, Link, Skills, CurrentWorkingDir and the shared symbol-override, max-width, speed-widget, locale-editor and timezone-editor helpers) still imported ink and React as values for their editor components. The widget registry builds every widget at load, so every render still evaluated ink, react, react-reconciler and yoga-layout (which instantiates its WASM at module load). Widget.renderEditor now returns a plain WidgetEditorDescriptor naming the editor ({ kind, props[, slots] }) instead of a React element. The editor components move unchanged to src/tui/components/widget-editors, and renderWidgetEditor() there maps a descriptor to its component; ItemsEditor is the only caller. The helper names and signatures used by the other widgets (renderSymbolSlotsEditor, renderMaxWidthEditor, ...) are kept, so those widgets are untouched. Built with `bun run build`, the chunk statically imported by the entry drops from 2.22 MB to 1.27 MB and no longer contains ink, react, react-reconciler or yoga-layout. Rendered output is byte-identical on the heavy, default, livelike, git17 and block configs. Interleaved bench (25 passes, node, host load 55-71 on 6 cores), CPU median: --version 1086 -> 806 ms (-26%), heavy config 2009 -> 1724 ms (-14%), default config 1531 -> 1260 ms (-18%). Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Port upstream editor changes (text cursor bar, symbol slots, link/cwd modes) onto the lazy widget-editor modules. BlinkingCursor and cursor-blink move from src/widgets/shared to src/tui/components so widget modules stay free of ink/React. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0171BeL2f3DYmsHicVsa2Tak
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
BLUF
Widget.renderEditornow returns a plain descriptor ({ kind, props }), and the editor components move unchanged intosrc/tui/components/widget-editors/. That folder is only reached through the lazyimport('./tui').--version. Rendered output is byte-identical.src/widgets/sharedthat only editors use: theuseTextCursorhook (text-cursor.ts, also used by the new label editor) andsearchable-option-editor.tsx(now behind the locale and timezone editors). The merge moves both, with their tests, intosrc/tui/components/widget-editors/so the no-ink/React guard still holds. It also ports main's later changes to the split widgets (custom-command display-width truncation, Link URL sanitizing, the cwd label and segment fixes,Number.parseInt) into the new files. Two new upstream glyph tests readslotsfrom the editor descriptor instead of a React element's props. The entry's static closure is still ink/React/yoga-free (1.28 MB shared chunk vs 2.23 MB on main).Details
src/types/Widget.ts: addsWidgetEditorDescriptor.renderEditor?(props)now returnsWidgetEditorDescriptor | nullinstead ofReact.ReactElement | null.SymbolSlotmoves here, andsymbol-overridere-exports it.CustomText,CustomSymbol,CustomCommand,Link,SkillsandCurrentWorkingDirgo from.tsxto.ts. So do the sharedsymbol-override,max-width,speed-widget,locale-editorandtimezone-editor. Each one keeps its render logic and returns a descriptor fromrenderEditor. Helper names and signatures are unchanged (renderSymbolSlotsEditor,renderMaxWidthEditor,renderSpeedWidgetEditor,renderUsageLocaleEditor,renderUsageTimezoneEditor), so the ~30 widgets that call them needed no edits. The only other changes are the return type annotation inBlockResetTimerandWeeklyResetTimer.src/tui/components/widget-editors/*Editor.tsx.renderWidgetEditor(descriptor)inindex.tsxmaps each kind to its component.ItemsEditoris the only caller: it rendersrenderWidgetEditor(editor), and still renders nothing when a widget returnsnull, as before. The few model helpers these editors use (Link'sbuildMetadataetc.,Skills' list-limit helpers, the speedWINDOW_EDITOR_ACTION) are now exported from their widget modules.renderEditordirectly (e.g.GitRootDir) pass unchanged.widget-editors/__tests__/index.test.tschecks two things. First, every editor a widget opens from its keybinds maps to a React element. Second, a guard fails if any module undersrc/widgetsimportsinkorreactas a value. The guard fails onmain, where 11 modules do.src/widgets/CustomCommand.tsx, which this PR splits intosrc/widgets/CustomCommand.tsandsrc/tui/components/widget-editors/CustomCommandEditor.tsx. Whichever PR merges second needs a small rebase. feat: Add RClone Queue widget + code-review fixes #523 adds a.tsxwidget; if it keeps an ink editor it would need the same descriptor pattern, and the new guard test would flag it.Measurements
Built with
bun run build(--splitting). The static import closure ofdist/ccstatusline.js:The runs alternated base and patched builds, each process fork/exec'd with CPU = user+sys including reaped children. 25 passes on node 24. Load1 during the run was 54.9 to 71.1 (median 62.2) on 6 cores. The host was heavily loaded, so compare the ratios rather than the absolute numbers.
node -e 0--version--versionOutput: stdout+stderr are byte-identical between the two builds on the heavy, heavy-ttl0, default, default-ttl0, livelike-ttl0, git17-ttl0 and block configs, each with 1 MB, 5 MB and no transcript (21/21).
--versionis identical too.Checks
bun run lint(tsc + eslint): clean.bun run build: OK (as above).bun test: 2289 pass / 69 fail on this loaded host. Every failure is a timing-sensitive test: ink input tests in the TUI menus and editors, the custom-command capture tests andfetchUsageData. The same TUI/editor/widget subset fails on unmodifiedmainunder the same load: 15 failures there vs 14 here, with the same test names. The usage and custom-command files fail too: 36 onmainvs 33 here. This full run was taken before the two new tests inwidget-editors/__tests__/index.test.tswere added. Those pass (2/2) when run on their own.🤖 Generated with Claude Code