Skip to content

chore: release 1.0.3 - #471

Merged
a1exk-dev merged 68 commits into
mainfrom
release/1.0.3
Oct 24, 2026
Merged

a1exk-dev merged 68 commits into
mainfrom
release/1.0.3

Conversation

@a1exk-dev

@a1exk-dev a1exk-dev commented Oct 24, 2026 •

Copy link
Copy Markdown
Owner

What changed

Refs: #431, #425

Summary

ctui 1.0.3 releases develop at 342f75b, the commit the portal last validated. The entry in ctui/CHANGELOG.md lists everything since v1.0.2, and prepare-release.ts wrote 1.0.3 into plugin.json's version.

develop @ 342f75b ──► release/1.0.3 ──► main  (you merge)
                          │                   │
                          ├ ctui/CHANGELOG.md   release.yml on the merge:
                          │ ## 1.0.3 (2026-10-24)  tag v1.0.3
                          ├ plugin.json          GitHub Release (body = top entry)
                          │ "version": "1.0.3"   npm publish @a1exk-dev/ctui 1.0.3
                          └ MEMORY.md, cspell    back-merge PR into develop

What 1.0.3 ships over v1.0.2:

Two commits on this branch besides the entry:

  • MEMORY.md: records the rule this release follows. A blocking finding that no documented shape clears and that waits on upstream is released with only on your word.
  • cspell.json: adds refusable, from a merged commit subject the generated entry quotes.

Evidence

Merge Danger

Door: one-way

Merging creates the v1.0.3 tag and a public GitHub Release, and publishes 1.0.3 to npm, and a published npm version can't be reused. The code is a two-way door: a hotfix can revert it.

Blast Radius: release

Every marketplace and npm user gets 1.0.3 on their next update. limits_cost now defaults to off, so a person who never set it loses the cost row that 1.0.2 showed off a plan (the old auto default). Anyone who set auto or on keeps it.

Reports

Live checks

ctui live checks — PASS (37/37)

plugin ctui v1.0.2-68-g62f5919
engine @anthropic-ai/claude-code 2.1.300
node scripts/check.ts PASS 397 tests, 9 s
run 2026-10-24T15:44Z Sonnet 5.5, medium effort
cost $2.10 wall 12 min 55 s
run dir /tmp/ctui-live-checks-JzRGAE

Sidebar docking

check expected measured
docking/width-42-at-150 body 42 columns wide at 150 #262626:107-149 on rows 0-40; col 107 is the │ rule, body 108-149, 42 columns PASS
docking/width-53-at-170 body 53 columns wide at 170 #262626:116-169; rule col 116, body 117-169, 53 columns PASS
docking/close-attempts-ignored footer row survives ✕ click, ctrl+x x, ctrl+x Tab + Esc ✕ at (0,148); claude cli: 2.1.300 still on row 37 after all three PASS
docking/fresh-110-prompt-docks no Sidebar before the prompt, footer after none on rows 0-44 at rest; after prompt rule col 67, ✕ row 0, footer row 37 (52 ms) PASS
docking/fresh-110-next-session-docks asked entry persisted; second launch docks before a prompt {"asked":[{"plugin":"ctui","id":"sidebar"}]}; footer row 37 at start, ✕ row 0, rule col 67 PASS
docking/dock-columns-override dock width follows pluginPanes.dockColumns, not 42 #262626:80-149, 70 columns on every body row; .claude.json held dockColumns = 70 PASS

Sidebar layout and scroll

check expected measured
layout/git-glyph-columns glyph at content col 0, text at col 2 row 4 U+F725 @110 #999999, "main" @112 #ffffff; row 5 U+F702, "↑0"; row 6 U+F728, "+2" #4eba65 PASS
layout/frame-and-footer one footer row at 53, two at 42, │ on every body row, no update icon 53: one row (38); 42: rows 37-38; │ col 107 on all 41 rows, default on #262626; no update icon in the dock PASS
layout/no-child-processes no claude -p / claude mcp list over 10 s: ctuistub node server and the prompt's bash -c only PASS

MCP

check expected measured
mcp/glyph-columns check_circle_outline at col 0, label at col 3 row 34 U+F05E1 @112 #4eba65, gaps 113-114, "c" of ctuistub @115 PASS
mcp/busy-animates ctuistub glyph differs across samples U+F0AA5 then U+F0AA0, 301 ms apart (94296/94597) PASS
mcp/fold-line-still folded MCP: term identical while row glyph differs folded ▶︎ MCP: 󰪣 1 󰗡 3 identical in both samples, same call as the differing glyphs above PASS

Render-site rewrites

check expected measured
rewrites/rule-gutter prompt, reply, $ Bash stop left of 105 prompt rightmost 102; reply token wraps at 104, 105-106 blank; $ Bash ends 104; control border rule reaches 106 PASS
rewrites/ctrl-o-transcript both views show the same rows, results in full under ctrl+o same rows both views; ctrl+o adds ⎿ one two … twentyfour in full; second ctrl+o restored identical PASS

Toasts

check expected measured
toasts/main-screen-prefix ctui: ◆ Explore started: … row 39 cols 153-198 ctui: ◆ Explore started: List docs/adr folder, directly under footer row 38; appeared 3010 ms after prompt PASS

Themes

check expected measured
themes/glass-flat one flat #363d41 at every step rows 1-39 #363d41:108-149 (117-169 at 170) after wheel, fold, resizes, fixture rewrite; no second run PASS
themes/glass-frame dock color on frame, then #363d41 dark: rule, ✕, row below all #262626; Everforest: all #363d41 PASS
themes/latte-body #e5e7ed body both times, frame differs then matches #e5e7ed:108-149, frame #262626; then #e5e7ed:107-149 PASS
themes/inherit-no-paint same color on body and frame #262626:107-149 rows 0-40 PASS
themes/omarchy-mix #373e42 body #373e42:108-149, frame #262626 PASS
themes/hover-colors suggestion on hover; inactive and bold text off it hovered ▼ and bold title #205ea6; off: ▼ #706e69, title #100f0f PASS
themes/focus-arrows grey focused, inverted after Tab, folded after Enter, #706e69 after Esc focused arrow #859289; after Tab fg default (harness shows no inverse attr, so only indirect evidence of inversion); Enter folded Limits; Esc arrows #706e69 PASS
themes/theme-list-from-ctui 22 ctui Themes A–Z, from ctui Catppuccin … White, 22, each from ctui; Live Check Fixture tagged custom PASS
themes/dock-tint transcript and dock recolored in one step Everforest dock #363d41:107-149, message rows #373e42; Latte dock #e5e7ed:107-149, rows #e5e7ed:0-149 PASS

The /ctui menu

check expected measured
menu/dock-pane-colors ctui text in Sidebar colors, engine text in /theme's ctui: bold #100f0f, ›/values #706e69, footer #100f0f/#706e69, · #b7b5ac; engine: › #859289, typed text default, ⏎ submit #859289; placeholder read default, not the fixture grey (judged PASS by the scenario) PASS
menu/frame-fits-content ─ and footer directly under last content row frame ╭ col 0 ╮ col 119; main last row 25, ─ 26, footer 27; Plugins 29/30/31; Themes 33/34/35 PASS

Skills

check expected measured
skills/glyph-columns U+F1A27 at col 0, name at col 3 row 24 U+F1A27 @112 #999999, gaps 113-114, "c" of ctuicheck @115 PASS

Todo

check expected measured
todo/own-list-hidden no list, ctrl+t to show tasks, list after ctrl+t rows 38-39 spinner only; footer ctrl+t to show tasks; after ctrl+t list shown, ctrl+t to hide tasks PASS
todo/spinner-animates glyph differs across samples U+F0AA1 → U+F0A9E over 302 ms PASS
todo/fold-line-still folded term identical, row glyph differs ▶︎ Todo: 󰪣 1 󰄰 2 identical at 78997/79299 ms; row glyph differed PASS
todo/spinner-focused glyph differs while focused U+F0AA3 → U+F0A9E at 82602/82904 ms PASS
todo/glyph-columns checkbox_marked_circle at col 0, text at col 3 row 25 U+F0133 @112 #4eba65, gaps 113-114, "R" @115 #999999 PASS
todo/no-dock-100-cols CC's list under spinner, ctrl+t to hide tasks 100 cols, no Sidebar, list rows 34-38, footer ctrl+t to hide tasks PASS

Agents & shells

check expected measured
agents/glyph-columns circle_slice at col 0, name at col 3 row 35 U+F0A9E @112 #ffc107, gaps 113-114, "L" @115 PASS
agents/fold-line-still folded term identical, shell glyph differs shell row U+F0AA3 → U+F0A9E; folded ▶︎ Agents & shells: 󰪣 1 identical in both samples PASS

Cost

check expected measured
cost/cold-cache-total row total equals generator's 1182.52$ of 100$; generator printed 1182.52$ PASS
cost/cold-cache-arrival under 3 s 1658 ms (baseline 1.5 s) PASS

No config dir kept: every row passed. Scenarios 1 and 6 re-drove one or two prompts after missing a window, so turns exceeded the 10-turn floor.

Evals

run 2026-10-24, release/1.0.3 @ 62f5919, claude-haiku-5-5, Claude Code 2.1.300
node scripts/evals.ts --ablation with-without --scaffold --trust-plugin --no-publish --allow-tools Edit Write 'Bash(node:*)'

Note: --scaffold runs each case's scaffold_script as you. Only use it on case files you (or your org) authored.
Plugin under test: "ctui" version "1.0.3" at "/tmp/ctui-stage-BLpeBb/ctui"
Ablation: 2 arms × 3 cases (18 runs)
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/01-medium/scaffold.sh
  medium run 1/3 [with]: score 1.00  $0.01
    ✓ list-before-first-edit (weight 1): TaskCreate@0 precedes Edit@8
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/01-medium/scaffold.sh
  medium run 2/3 [with]: score 1.00  $0.01
    ✓ list-before-first-edit (weight 1): TaskCreate@0 precedes Edit@11
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/01-medium/scaffold.sh
  medium run 3/3 [with]: score 1.00  $0.01
    ✓ list-before-first-edit (weight 1): TaskCreate@1 precedes Edit@11
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/01-medium/scaffold.sh
  medium run 1/3 [without]: score 0.00  $0.01
    ✗ list-before-first-edit (weight 1): "before" tool TaskCreate never called
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/01-medium/scaffold.sh
  medium run 2/3 [without]: score 0.00  $0.01
    ✗ list-before-first-edit (weight 1): "before" tool TaskCreate never called
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/01-medium/scaffold.sh
  medium run 3/3 [without]: score 0.00  $0.00
    ✗ list-before-first-edit (weight 1): "before" tool TaskCreate never called
✓ medium  with 1.00  without 0.00  Δ +1.00  (6 runs)  $0.04
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/02-big/scaffold.sh
  big run 1/3 [with]: score 1.00  $0.01
    ✓ list-before-first-write (weight 1): TaskCreate@0 precedes Write@7
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/02-big/scaffold.sh
  big run 2/3 [with]: score 1.00  $0.01
    ✓ list-before-first-write (weight 1): TaskCreate@0 precedes Write@8
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/02-big/scaffold.sh
  big run 3/3 [with]: score 1.00  $0.01
    ✓ list-before-first-write (weight 1): TaskCreate@0 precedes Write@7
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/02-big/scaffold.sh
  big run 1/3 [without]: score 0.00  $0.00
    ✗ list-before-first-write (weight 1): "before" tool TaskCreate never called
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/02-big/scaffold.sh
  big run 2/3 [without]: score 0.00  $0.00
    ✗ list-before-first-write (weight 1): "before" tool TaskCreate never called
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/02-big/scaffold.sh
  big run 3/3 [without]: score 0.00  $0.00
    ✗ list-before-first-write (weight 1): "before" tool TaskCreate never called
✓ big  with 1.00  without 0.00  Δ +1.00  (6 runs)  $0.03
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/03-one-line/scaffold.sh
  one-line run 1/3 [with]: score 1.00  $0.00
    ✓ no-task-list (weight 1): TaskCreate called 0x (expected 0..0)
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/03-one-line/scaffold.sh
  one-line run 2/3 [with]: score 1.00  $0.00
    ✓ no-task-list (weight 1): TaskCreate called 0x (expected 0..0)
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/03-one-line/scaffold.sh
  one-line run 3/3 [with]: score 1.00  $0.00
    ✓ no-task-list (weight 1): TaskCreate called 0x (expected 0..0)
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/03-one-line/scaffold.sh
  one-line run 1/3 [without]: score 1.00  $0.00
    ✓ no-task-list (weight 1): TaskCreate called 0x (expected 0..0)
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/03-one-line/scaffold.sh
  one-line run 2/3 [without]: score 1.00  $0.00
    ✓ no-task-list (weight 1): TaskCreate called 0x (expected 0..0)
  scaffold: /tmp/ctui-stage-BLpeBb/ctui/evals/03-one-line/scaffold.sh
  one-line run 3/3 [without]: score 1.00  $0.00
    ✓ no-task-list (weight 1): TaskCreate called 0x (expected 0..0)
✓ one-line  with 1.00  without 1.00  Δ 0.00  (6 runs)  $0.02

CASE      WITH  W/OUT Δ      RUNS COST    NOTES
medium    1.00  0.00  +1.00  6    $0.04   
big       1.00  0.00  +1.00  6    $0.03   
one-line  1.00  1.00  0.00   6    $0.02   

3 case(s) · mean Δ +0.67 · 239s · $0.09
Report: /home/a1exk/Projects/claude-tui/evals/results/2026-10-24T17-22-37-519Z/report.html

github-actions Bot and others added 30 commits October 20, 2026 11:11
chore: merge main v1.0.2 into develop
The directory reads `plugin-${id}` as a command assembled at run time,
which with the README's ~/.claude.json raised the cross-surface
MCP_FORWARDS_CREDENTIAL_ENV hold. Every key stays the same.

Refs: #429
Sidebar plugins now leave a mark carrying a Client's key, width and
props (ctui/plugins/clients.ts), and the Sidebar's render hook turns
each mark into a <Client> with a string-literal module, from elements
destructured by name off $.ui.resolve(e) with no rest pattern. This
clears the directory's MOD_IMPORT_DYNAMIC_COMPUTED finding; the press
targets, fold rows and sweeps draw as before. scripts/check.ts now
refuses a rest pattern on $.ui.resolve(e) and a <Client> outside
register.tsx or without a literal module.

Refs: #428
The directory portal refuses a settings write reached through a helper
or a timer that keeps $ (MOD_CONFIG_SET_UNREAD). Each /ctui write is now
a $.config.set with a fixed key and a plain value member, inside the
ui.press, ui.input, ui.focus, ui.close or session.end hook that handles
it. A moved order waits in the menu and is written by the next write,
the ring landing after Esc, the close or the session's end, replacing
#163's write about 1 s after the last move.

MEMORY.md: the menu entry drops the 1 s write, and a new entry says to
confirm a directory fix in the portal on develop before releasing it.

Refs: #427
/ctui started the menu over and dropped an order moved but not saved; it
now writes it first, on its own hook's `$`. session.end no longer writes
on clear or resume, where the write's reload would lose the work and
effort carried into the new session; the menu's next write, Esc or
close still saves it.

Also renames the press hook's local that shadowed the module's
`waiting`, says why each hook repeats its order write, bundles the test
helper's recorders into one object, matches the README to when the
order saves, and trims dated narration from MEMORY.md.

Refs: #427
"Mark" already names a Sidebar glyph (ADR 0003, marks.tsx). The pure
draws now return a Client placeholder, held in an empty Box, and the
render hook's `drawClients` walk draws each one, at any depth, as its
Client. A test checks a placeholder nested in a title row draws there
under the same key and props.

Refs: #428
The portal still blocked MOD_IMPORT_DYNAMIC_COMPUTED on the Sidebar render
hook, whose Clients were built inside a nested drawClients arrow and whose
spinner loaded from ../plugins/todo/spinner.tsx. A plain for loop in the hook
body now builds each Client from the placeholders a pure placeholdersIn
lists, and a pure withClients swaps them into the tree. The spinner moves to
hooks/spinner.tsx, so every module path reads ./<name>.tsx, which
scripts/check.ts now enforces. What ctui draws is unchanged.

Refs: #433
limits_cost now defaults to off in plugin.json and in readConfig's
fallback, so a fresh install neither shows the cost row nor lists or
greps a transcript. auto and on keep today's behaviour. The setting's
description, docs/configuration.md, the README's "What ctui watches"
and MEMORY.md say the row reads this month's transcripts and is off
until turned on.

Refs: #435
The Sidebar render hook now names the 'sweep' placeholder explicitly and
narrows anything else to never, so a new ClientPlaceholder variant fails
tsc. The MEMORY.md entry's Reason keeps each portal finding beside its
error code, without task narration, and the spinner tests name the
module's new home in hooks/spinner.tsx.

Refs: #433
…ok list

ctui/README.md gains Examples, Privacy and data, Troubleshooting and
Support, the last linking GitHub private vulnerability reporting for
security reports. "What ctui watches" replaces "every other hook passes
its event on unchanged" with two lists: the hooks that change what
Claude Code draws or does, and the hooks that read their event and pass
it on. The Task tools section now names every change the setting makes.

node scripts/check.ts fails when ctui/README.md drops one of the four
sections or the security link. MEMORY.md and CONTRIBUTING.md follow.

Refs: #436
showsCost defaulted its choice to auto, so a caller passing an
undefined limits_cost showed the row off a plan. Unset now means off,
as readConfig's fallback does.

Refs: #435
The comment explains readConfig's fallback, so it stays only there.

Refs: #435
The README checks read ctui/README.md three times; they now share one
read per file.

Refs: #436
… once

The Sidebar close is denied for every close by the person, not only
while docked. The list gains the Sidebar's ui.scroll, which takes the
scroll, and the menu's ui.press and ui.input. Only the main
conversation's TaskCreate and TaskUpdate calls run as ctui's; a
subagent's pass on. "What ctui watches" no longer repeats the reads that
"What ctui reads" lists, and "Privacy and data" links to the programs
list instead of restating it.

Refs: #436
…reads

The Limits cost entry's heading said the row hides on a plan; it is off
by default now, so it reads "is opt-in" and its reference follows, and
showsCost joins the places that default to off. The publish entry names
"What ctui reads" as the one list of reads and drops its restatement of
what scripts/check.ts enforces.

Refs: #435, #436
Adds `mod-policy-is-all-or-nothing` to the engine-pinned expectations:
the only managed levers that reach a mod's registered command are the
ones that stop the whole hooks module, and
`strictPluginOnlyCustomization` is not among them. Measured on 2.1.309,
above the 2.1.300 pin, so the member names the version it was read on
and the entry's intro flags it as the one member read off a newer
engine than the pin.

Widens the entry's `Applies when:` to cover a finding a read of the
engine produced, not only a live run, since this one came from the
binary rather than a live session.

`disableSideloadFlags` in the new text needs `Sideload` in cspell.json,
carried over from the research branch so `node scripts/check.ts`
passes.

Refs: #446
a1exk-dev and others added 27 commits October 24, 2026 13:37
Add a MEMORY.md entry with the three rules, the fixed handler, the
one-statement-one-line rule and the check that holds rule 1, and
ADR 0004 with why ctui guards the calls Claude Code leaves bare, why
the two named gates cannot fail, the deliberately bare after-answer
calls and the declined registration-level handler. Point the
rejection-is-a-log-line expectation at both and state its expiry.

Refs: #463
…ed handler

Nineteen of the twenty-one bare fire-and-forget calls in ctui's hooks
module now end in .catch(() => undefined), on the same line, like the
seventeen that already did. The two in the TaskCreate and TaskUpdate
hooks are left to the task-hook guard on this branch.

Refs: #462
A refused menu read at session start now reads as the menu's start
state, so the hook still registers the one-second tick, answers and
draws the Sidebar. A moved Plugins order never saved stays waiting.

Refs: #464
Esc in a menu submenu now guards its menu state read inline, with the
menu's start state as the substitute, so a refused read lands on the
close branch as ctui's stated choice rather than a skipped hook. Tests
hold that the Sidebar's close gate and the menu's hotkey gate still
refuse with the menu read refused. The direct-dispatch helper in the
menu tests now matches the Sidebar pane's id too.

Refs: #466
…hing repairs

Another mod's deny on the /ctui registration left the session without the
command and said nothing; it now toasts once, sending the person to /config.
The refused resize and the refused inline close gain a comment naming their
cost and a dock test each. The agents and floor test hosts answer
command.register, as a session's engine does.

Refs: #467
The close has already answered, so the save after it stays bare and uncommented, as the refused-call policy says.

Refs: #466
The rule passed a line that named .catch(() => undefined) anywhere. Now the handler must close the void call itself: only the closers of the expression around it may follow, and the call before it must be whole, so a handler inside its arguments fails.

Refs: #462
The toast now covers every refused /ctui registration, not just a taken name, so its state, key and toast id say so. The toast's text is unchanged.

Refs: #467
The refused-read stub rejected every menu read, so the Esc test's hook rejected after the close and its answer check passed on nothing. Now only the first menu read, the one the gate decides on, is refused, and the test holds the close's own answer.

Refs: #466
Docked with Todo on, ctui runs TaskCreate and TaskUpdate itself, then keeps the task's activeForm in $.state. A refused write failed the hook with no next result to stand on, so core ran the tool again and one TaskCreate made two tasks. Both hooks now discard that failure; the row shows the subject until the next TaskUpdate.

Refs: #449, #452
The settings reader's fallback, the Limits view's fallback and the reader
test read MONTHLY_DEFAULT from its own leaf module, and node scripts/check.ts
fails when the manifest's declared default and the constant differ.

Refs: #454
Given the render's viewport, the bar is the prompt's wrapped row count against a quarter of the panel's inner width, clamped to one row per character plus three. With no viewport it keeps the character-count length.

Refs: #453
…odule

Name the quarter-row factor in the prompt panel's bar as FILL beside
CHROME, make CHROME's comment add up to its 5 cells, and state the
one-row-per-character bound once. Rename ctui/hooks/monthly.ts to
monthly-default.ts so it no longer reads like month.ts, and drop the
clamp test's widths no terminal session sends.

Refs: #453
Refs: #454
@a1exk-dev
a1exk-dev merged commit 700e955 into main Oct 24, 2026
7 checks passed
@a1exk-dev
a1exk-dev deleted the release/1.0.3 branch October 24, 2026 22:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant