Repository navigation
chore: release 1.0.3 - #471
Merged
Merged
Conversation
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
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
…fusal-policy-docs Refs: #463
…-authoring-review 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
…ery un-awaited call Refs: #462
…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
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.
What changed
Refs: #431, #425
Summary
ctui 1.0.3 releases
developat 342f75b, the commit the portal last validated. The entry inctui/CHANGELOG.mdlists everything sincev1.0.2, andprepare-release.tswrote1.0.3intoplugin.json'sversion.What 1.0.3 ships over
v1.0.2:/ctuiregistration or settings read shows a toast or a line instead of failing silently. A task tool runs once when itsactiveFormwrite is refused.ctui/README.mdgains Examples, Support, Privacy and data, Troubleshooting and a per-hook list.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: addsrefusable, from a merged commit subject the generated entry quotes.Evidence
node scripts/check.tsexits 0 on this branch's head (it failed first onrefusable, now incspell.json).claude plugin validate ctuisays✔ Validation passed. It runs none of the directory's rules.MOD_IMPORT_DYNAMIC_COMPUTEDon the Sidebar's$.ui.resolve(e)Client line. No documented shape clears it, and it waits on Plugin directory Validate blocks every mod Client with MOD_IMPORT_DYNAMIC_COMPUTED, even the documented form anthropics/claude-code#103757. You chose on 2026-10-24 to release with it open, so the directory submission waits on that answer (Validate the 1.0.3 fixes on develop in the portal #430 stays open).Merge Danger
Door: one-way
Merging creates the
v1.0.3tag 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_costnow defaults to off, so a person who never set it loses the cost row that 1.0.2 showed off a plan (the oldautodefault). Anyone who setautooronkeeps 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
│rule, body 108-149, 42 columnsclaude cli: 2.1.300still on row 37 after all three{"asked":[{"plugin":"ctui","id":"sidebar"}]}; footer row 37 at start, ✕ row 0, rule col 67.claude.jsonheld dockColumns = 70Sidebar layout and scroll
│on every body row, no update icon│col 107 on all 41 rows, default on #262626; no update icon in the dockclaude -p/claude mcp listctuistubnode server and the prompt'sbash -conlyMCP
▶︎ MCP: 1 3identical in both samples, same call as the differing glyphs aboveRender-site rewrites
$ Bashstop left of 105$ Bashends 104; control border rule reaches 106⎿ one two … twentyfourin full; second ctrl+o restored identicalToasts
ctui: ◆ Explore started: …ctui: ◆ Explore started: List docs/adr folder, directly under footer row 38; appeared 3010 ms after promptThemes
#363d41:108-149(117-169 at 170) after wheel, fold, resizes, fixture rewrite; no second run#e5e7ed:108-149, frame #262626; then#e5e7ed:107-149#262626:107-149rows 0-40#373e42:108-149, frame #262626default(harness shows no inverse attr, so only indirect evidence of inversion); Enter folded Limits; Esc arrows #706e69from ctuifrom ctui; Live Check Fixture taggedcustom#363d41:107-149, message rows #373e42; Latte dock#e5e7ed:107-149, rows#e5e7ed:0-149The
/ctuimenu/theme's›/values #706e69, footer #100f0f/#706e69,·#b7b5ac; engine:›#859289, typed textdefault,⏎ submit#859289; placeholder readdefault, not the fixture grey (judged PASS by the scenario)─and footer directly under last content rowSkills
Todo
ctrl+t to show tasks, list after ctrl+tctrl+t to show tasks; after ctrl+t list shown,ctrl+t to hide tasks▶︎ Todo: 1 2identical at 78997/79299 ms; row glyph differedctrl+t to hide tasksctrl+t to hide tasksAgents & shells
▶︎ Agents & shells: 1identical in both samplesCost
1182.52$ of 100$; generator printed1182.52$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:*)'