| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat: rename sidebar/rail to workbar, bottom default, /workbar command | 8 天前 | |
tui: resume confirmation is a popup, and a wheel gesture is one frame **The confirmation is a popup now.** The arming line over the composer dock read as one more piece of chrome rather than as a question — "that's even more confusing tbh". `LaunchResumeConfirmView` is a small centered modal that names the session and its age, and asks. Enter or `y` confirms, Esc or `n` walks away, a click outside dismisses, and any other key does nothing — resuming replaces the whole session context, so it takes a deliberate act. The confirmed event routes into the same `pending_launch_action` path the card's own Enter uses, so there is still exactly one resume path. **Scrolling was never a rendering problem.** A timing probe put one frame with a 400-message transcript at ~2.2ms (445 fps), and flat against transcript length — the incremental transcript cache was doing its job. The cost was structural: a trackpad emits a burst of scroll events, the loop handled one per iteration and drew each time, and the 120 FPS limiter then spaced those draws out, so a flick arrived as a slow crawl long after the fingers stopped. Resize events have been coalesced exactly this way since #65; scroll never was. `coalesce_scroll_burst` folds the rest of the gesture in before drawing — the scroll handlers only accumulate into `viewport.pending_scroll_delta`, so each folded tick costs one cheap call and the whole gesture costs one draw. It is bounded at 64 so a stuck wheel cannot starve the frame, and a non-scroll event ends the burst and is pushed back unread rather than swallowed. It is a free function rather than another inline block in a 6,000-line loop so `a_scroll_burst_is_folded_into_one_frame` can drive it directly: ten ticks in, one delta out, and the key press that ended the burst still queued. Four new localized strings across all 15 locales (2031/2031, parity PASS). Gates: fmt PASS · clippy -p codewhale-tui PASS · nextest -p codewhale-tui 12006 passed / 0 failed / 13 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 7 天前 | |
tui: resume confirmation is a popup, and a wheel gesture is one frame **The confirmation is a popup now.** The arming line over the composer dock read as one more piece of chrome rather than as a question — "that's even more confusing tbh". `LaunchResumeConfirmView` is a small centered modal that names the session and its age, and asks. Enter or `y` confirms, Esc or `n` walks away, a click outside dismisses, and any other key does nothing — resuming replaces the whole session context, so it takes a deliberate act. The confirmed event routes into the same `pending_launch_action` path the card's own Enter uses, so there is still exactly one resume path. **Scrolling was never a rendering problem.** A timing probe put one frame with a 400-message transcript at ~2.2ms (445 fps), and flat against transcript length — the incremental transcript cache was doing its job. The cost was structural: a trackpad emits a burst of scroll events, the loop handled one per iteration and drew each time, and the 120 FPS limiter then spaced those draws out, so a flick arrived as a slow crawl long after the fingers stopped. Resize events have been coalesced exactly this way since #65; scroll never was. `coalesce_scroll_burst` folds the rest of the gesture in before drawing — the scroll handlers only accumulate into `viewport.pending_scroll_delta`, so each folded tick costs one cheap call and the whole gesture costs one draw. It is bounded at 64 so a stuck wheel cannot starve the frame, and a non-scroll event ends the burst and is pushed back unread rather than swallowed. It is a free function rather than another inline block in a 6,000-line loop so `a_scroll_burst_is_folded_into_one_frame` can drive it directly: ten ticks in, one delta out, and the key press that ended the burst still queued. Four new localized strings across all 15 locales (2031/2031, parity PASS). Gates: fmt PASS · clippy -p codewhale-tui PASS · nextest -p codewhale-tui 12006 passed / 0 failed / 13 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 7 天前 | |
tui: resume confirmation is a popup, and a wheel gesture is one frame **The confirmation is a popup now.** The arming line over the composer dock read as one more piece of chrome rather than as a question — "that's even more confusing tbh". `LaunchResumeConfirmView` is a small centered modal that names the session and its age, and asks. Enter or `y` confirms, Esc or `n` walks away, a click outside dismisses, and any other key does nothing — resuming replaces the whole session context, so it takes a deliberate act. The confirmed event routes into the same `pending_launch_action` path the card's own Enter uses, so there is still exactly one resume path. **Scrolling was never a rendering problem.** A timing probe put one frame with a 400-message transcript at ~2.2ms (445 fps), and flat against transcript length — the incremental transcript cache was doing its job. The cost was structural: a trackpad emits a burst of scroll events, the loop handled one per iteration and drew each time, and the 120 FPS limiter then spaced those draws out, so a flick arrived as a slow crawl long after the fingers stopped. Resize events have been coalesced exactly this way since #65; scroll never was. `coalesce_scroll_burst` folds the rest of the gesture in before drawing — the scroll handlers only accumulate into `viewport.pending_scroll_delta`, so each folded tick costs one cheap call and the whole gesture costs one draw. It is bounded at 64 so a stuck wheel cannot starve the frame, and a non-scroll event ends the burst and is pushed back unread rather than swallowed. It is a free function rather than another inline block in a 6,000-line loop so `a_scroll_burst_is_folded_into_one_frame` can drive it directly: ten ticks in, one delta out, and the key press that ended the burst still queued. Four new localized strings across all 15 locales (2031/2031, parity PASS). Gates: fmt PASS · clippy -p codewhale-tui PASS · nextest -p codewhale-tui 12006 passed / 0 failed / 13 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 7 天前 | |
tui: resume confirmation is a popup, and a wheel gesture is one frame **The confirmation is a popup now.** The arming line over the composer dock read as one more piece of chrome rather than as a question — "that's even more confusing tbh". `LaunchResumeConfirmView` is a small centered modal that names the session and its age, and asks. Enter or `y` confirms, Esc or `n` walks away, a click outside dismisses, and any other key does nothing — resuming replaces the whole session context, so it takes a deliberate act. The confirmed event routes into the same `pending_launch_action` path the card's own Enter uses, so there is still exactly one resume path. **Scrolling was never a rendering problem.** A timing probe put one frame with a 400-message transcript at ~2.2ms (445 fps), and flat against transcript length — the incremental transcript cache was doing its job. The cost was structural: a trackpad emits a burst of scroll events, the loop handled one per iteration and drew each time, and the 120 FPS limiter then spaced those draws out, so a flick arrived as a slow crawl long after the fingers stopped. Resize events have been coalesced exactly this way since #65; scroll never was. `coalesce_scroll_burst` folds the rest of the gesture in before drawing — the scroll handlers only accumulate into `viewport.pending_scroll_delta`, so each folded tick costs one cheap call and the whole gesture costs one draw. It is bounded at 64 so a stuck wheel cannot starve the frame, and a non-scroll event ends the burst and is pushed back unread rather than swallowed. It is a free function rather than another inline block in a 6,000-line loop so `a_scroll_burst_is_folded_into_one_frame` can drive it directly: ten ticks in, one delta out, and the key press that ended the burst still queued. Four new localized strings across all 15 locales (2031/2031, parity PASS). Gates: fmt PASS · clippy -p codewhale-tui PASS · nextest -p codewhale-tui 12006 passed / 0 failed / 13 skipped. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 7 天前 | |
refactor: extract localization into codewhale-localization First crate out of the TUI monolith. 7,087 lines and 16 locale packs leave `crates/tui`, which drops from 973,442 to 966,355 lines. The founder's read was right and worth recording, because it is the thing that kept this from happening: it looks far scarier than it is. `localization` appeared to depend on the rest of the crate, but the single `crate::` reference in all 6,797 lines was **inside a doc comment** — prose, not an edge. It was already a standalone crate wearing a module's clothes, consumed by 145 files and depending on none of them. The subsystem is cohesive and moves whole: the registry, its rust-i18n backend, the `generate_localization` half of `build.rs`, and `locales/`. `localization` is the only module in the workspace that touches `rust_i18n::t!`, so the entire i18n coupling left with it — `crates/tui` no longer depends on rust-i18n at all, and its `build.rs` loses a build-dependency and a code generator. 165 consumers were repointed from `crate::localization::` to `codewhale_localization::`. No re-export shim was left behind: per `docs/design/TUI_DECONSTRUCTION.md:176,185-186` a shim with deferred consumers is the state this work exists to remove, and there is no external contract to protect. Gate paths moved with the packs: `check-tui-locale-parity.py`, `check-tui-product-vocabulary.sh`, and the live docs. `docs/CHANGELOG_ARCHIVE.md` keeps its old paths deliberately — it is a historical record, not a pointer. Verified, not assumed: cargo check --workspace --all-targets 0 errors, 0 unused warnings cargo test -p codewhale-localization 51 passed; 0 failed cargo test -p codewhale-tui --lib -- tui::views tui::widgets commands:: 1610 passed; 0 failed scripts/check-tui-locale-parity.py PASS, 2203/2203 in 15 packs scripts/check-tui-product-vocabulary.sh exit 0 No new tests: 51 existing ones moved with the code and prove the extraction by passing unchanged, which is the only assertion that matters for a move. What this buys beyond the line count: the localization suite now runs in 3.56s against a small crate instead of waiting on the TUI crate's build, and TUI edits no longer recompile the string registry. C00 measured a warmed one-line locale edit at 30.22s / 8,728 MB RSS inside the monolith. Refs: Linear C03-C10 / SHA-6179, docs/design/TUI_DECONSTRUCTION.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL | 1 天前 | |
refactor: extract palette into its own crate and move command_safety to execpolicy Two more modules out of the TUI monolith, on the same evidence as the localization extraction: a dependency census that counted `crate::` mentions inside doc comments and `#[cfg(test)]` blocks made these look entangled. With comments and test code excluded, both had **zero** real production dependencies on the rest of the crate. `palette` -> `codewhale-palette` (5,850 lines). Theming and colour tokens, with a wide but shallow consumer rewrite. No contrast or colour value changed while moving; `scripts/export-design-tokens.py` and the `check:tokens` gate follow the new path, and the gate passes with 64 tokens unchanged. Two OSC probes (`osc11::query_terminal`, used by `tui::mark` for the kitty graphics query) had to widen from `pub(crate)` to `pub` to cross the new crate line — a terminal capability query, not a trust boundary, and stated here rather than left for a reader to notice. `command_safety` -> `crates/execpolicy` (2,951 lines). Deliberately **not** a new crate: execpolicy already owns `ApprovalMode` and approval policy, and a `codewhale-command-safety` beside it would be a second authority for one concern. This is security-relevant code that classifies whether a shell command is safe to run, so it moved unchanged — not one classification rule, allowlist entry or matcher was touched. `crates/tui` already depended on execpolicy, so this move *removes* a dependency edge rather than adding one, which is the ideal shape for this work. The CI step that ran its tests under `codewhale-tui` now picks them up from the `codewhale-execpolicy` run on the line below it. crates/tui: 973,442 -> 957,746 lines across this session's three extractions. Verified: cargo check --workspace --all-targets 0 errors, 0 unused warnings cargo test -p codewhale-palette 81 passed; 0 failed cargo test -p codewhale-execpolicy 188 + 1 + 5 passed; 0 failed cargo test -p codewhale-localization 51 passed; 0 failed scripts/check-tui-locale-parity.py PASS scripts/export-design-tokens.py --check up to date, 64 tokens No new tests: the moved suites passing unchanged is the proof a move is correct. Refs: Linear C03-C10 / SHA-6179, docs/design/TUI_DECONSTRUCTION.md. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01X57KRgwqYkmmtVQScczqiL | 1 天前 | |
chore: use the public name Codewhale in prose (identifiers untouched) (#5742) * chore: use the public name Codewhale in prose Replace the word CodeWhale with the ratified public name Codewhale in public prose only: docs/**, all 15 TUI locale packs, and user-facing Rust string literals in crates/tui/src (update/help/status/error copy plus the tests that assert on that copy). Compatibility identifiers are untouched: the Hmbown/CodeWhale GitHub slug and every URL containing it, Hmbown.CodeWhale (winget), Windows install paths (%LOCALAPPDATA%\Programs\CodeWhale\bin), clone directories (cd CodeWhale), user-agent and header strings, gherkin step names, test fixtures, doc comments, CHANGELOG history, README URLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore: bundled plan skill prose uses the public name Codewhale Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 10 天前 | |
chore: use the public name Codewhale in prose (identifiers untouched) (#5742) * chore: use the public name Codewhale in prose Replace the word CodeWhale with the ratified public name Codewhale in public prose only: docs/**, all 15 TUI locale packs, and user-facing Rust string literals in crates/tui/src (update/help/status/error copy plus the tests that assert on that copy). Compatibility identifiers are untouched: the Hmbown/CodeWhale GitHub slug and every URL containing it, Hmbown.CodeWhale (winget), Windows install paths (%LOCALAPPDATA%\Programs\CodeWhale\bin), clone directories (cd CodeWhale), user-agent and header strings, gherkin step names, test fixtures, doc comments, CHANGELOG history, README URLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore: bundled plan skill prose uses the public name Codewhale Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 10 天前 | |
chore: use the public name Codewhale in prose (identifiers untouched) (#5742) * chore: use the public name Codewhale in prose Replace the word CodeWhale with the ratified public name Codewhale in public prose only: docs/**, all 15 TUI locale packs, and user-facing Rust string literals in crates/tui/src (update/help/status/error copy plus the tests that assert on that copy). Compatibility identifiers are untouched: the Hmbown/CodeWhale GitHub slug and every URL containing it, Hmbown.CodeWhale (winget), Windows install paths (%LOCALAPPDATA%\Programs\CodeWhale\bin), clone directories (cd CodeWhale), user-agent and header strings, gherkin step names, test fixtures, doc comments, CHANGELOG history, README URLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore: bundled plan skill prose uses the public name Codewhale Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 10 天前 | |
chore: drop the co-author trailer gate, keep harvested credit (#5789) The Lint job ran scripts/check-coauthor-trailers.py on every commit range and rejected any Co-authored-by trailer that was not a human in .github/AUTHOR_MAP or one of two hardcoded agent identities. In practice it rejected ordinary agent commits -- the default trailer most tools append fails it -- so every contributor and every agent had to learn a rule that bought tidiness and nothing else. Removed: the 46-line "Check harvested contributor credit" step in ci.yml, the checker, its test, and its five fixtures. Also the stale mention in the light-change path filter. Kept, deliberately: harvested contributor credit. auto-close-harvested.yml is independent of the deleted script -- it reads "Harvested from PR #N by @handle" from the commit message -- so a contributor's PR still closes with credit when their work lands, and .github/AUTHOR_MAP remains the canonical human identity list. The rule that survives is "name the humans who did the work". The rule that goes is "no tool may appear in a trailer". The two skills that called the checker now read trailers with git log directly. CONTRIBUTING.md and AGENTS.md say what is true now instead of describing a gate that no longer exists. actionlint is clean on the edited workflow. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> | 10 天前 | |
chore: use the public name Codewhale in prose (identifiers untouched) (#5742) * chore: use the public name Codewhale in prose Replace the word CodeWhale with the ratified public name Codewhale in public prose only: docs/**, all 15 TUI locale packs, and user-facing Rust string literals in crates/tui/src (update/help/status/error copy plus the tests that assert on that copy). Compatibility identifiers are untouched: the Hmbown/CodeWhale GitHub slug and every URL containing it, Hmbown.CodeWhale (winget), Windows install paths (%LOCALAPPDATA%\Programs\CodeWhale\bin), clone directories (cd CodeWhale), user-agent and header strings, gherkin step names, test fixtures, doc comments, CHANGELOG history, README URLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore: bundled plan skill prose uses the public name Codewhale Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 10 天前 | |
chore: use the public name Codewhale in prose (identifiers untouched) (#5742) * chore: use the public name Codewhale in prose Replace the word CodeWhale with the ratified public name Codewhale in public prose only: docs/**, all 15 TUI locale packs, and user-facing Rust string literals in crates/tui/src (update/help/status/error copy plus the tests that assert on that copy). Compatibility identifiers are untouched: the Hmbown/CodeWhale GitHub slug and every URL containing it, Hmbown.CodeWhale (winget), Windows install paths (%LOCALAPPDATA%\Programs\CodeWhale\bin), clone directories (cd CodeWhale), user-agent and header strings, gherkin step names, test fixtures, doc comments, CHANGELOG history, README URLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore: bundled plan skill prose uses the public name Codewhale Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 10 天前 | |
chore: drop the co-author trailer gate, keep harvested credit (#5789) The Lint job ran scripts/check-coauthor-trailers.py on every commit range and rejected any Co-authored-by trailer that was not a human in .github/AUTHOR_MAP or one of two hardcoded agent identities. In practice it rejected ordinary agent commits -- the default trailer most tools append fails it -- so every contributor and every agent had to learn a rule that bought tidiness and nothing else. Removed: the 46-line "Check harvested contributor credit" step in ci.yml, the checker, its test, and its five fixtures. Also the stale mention in the light-change path filter. Kept, deliberately: harvested contributor credit. auto-close-harvested.yml is independent of the deleted script -- it reads "Harvested from PR #N by @handle" from the commit message -- so a contributor's PR still closes with credit when their work lands, and .github/AUTHOR_MAP remains the canonical human identity list. The rule that survives is "name the humans who did the work". The rule that goes is "no tool may appear in a trailer". The two skills that called the checker now read trailers with git log directly. CONTRIBUTING.md and AGENTS.md say what is true now instead of describing a gate that no longer exists. actionlint is clean on the edited workflow. Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> | 10 天前 | |
chore: use the public name Codewhale in prose (identifiers untouched) (#5742) * chore: use the public name Codewhale in prose Replace the word CodeWhale with the ratified public name Codewhale in public prose only: docs/**, all 15 TUI locale packs, and user-facing Rust string literals in crates/tui/src (update/help/status/error copy plus the tests that assert on that copy). Compatibility identifiers are untouched: the Hmbown/CodeWhale GitHub slug and every URL containing it, Hmbown.CodeWhale (winget), Windows install paths (%LOCALAPPDATA%\Programs\CodeWhale\bin), clone directories (cd CodeWhale), user-agent and header strings, gherkin step names, test fixtures, doc comments, CHANGELOG history, README URLs. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014aDEyM2a4pPZ9qqMDrP5YX Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore: bundled plan skill prose uses the public name Codewhale Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Claude Fable 5 <noreply@anthropic.com> | 10 天前 |
Maintainer / agent skills
GitHub-stewardship and release-QA workflows for maintaining Codewhale, codified as
SKILL.md skills (same format Claude Code and Codewhale both load). They encode the
issue-triage, PR-harvest, credit, and release-QA workflows the maintainers run each
release.
For end-user Skills Manager behavior (ownership, audit, import, trust), see ../SKILLS.md.
To activate:
- Claude Code: copy a skill dir into
.claude/skills/(project) or your user skills dir. - Codewhale: copy into a Codewhale-owned root (e.g.
~/.codewhale/skills/), import via/skills, or bundle intocrates/tui/assets/skills/+ register incrates/tui/src/skills/system.rsto ship it.
Skills: gh-file-issue, gh-compile-issues, gh-assign-issues, gh-find-prs, gh-treasure-hunt, gh-close-issues, gh-credit-harvest, codew-release-qa-sweep.