IIsabel Wufeat(tui): list custom themes in picker
| 文件 | 最后提交记录 | 最后更新时间 |
|---|---|---|
feat(tui)!: make agent the only model-visible sub-agent tool AGENTS.md says the model-facing sub-agent surface is `agent` only. It was not. `agents/list`, `agents/message`, `agents/followup`, `agents/interrupt`, `agents/coordinate`, and `agents/wait` never overrode `ToolSpec:: model_visible`, which defaults to true, so all six cleared the filter in `ToolRegistry::build_api_tools` and entered the model catalog. Being deferred did not hide them — deferral makes a tool discoverable via `tool_search`, and both matchers read the same catalog. The `agent` description then named five of them outright ("the narrow agents/list, agents/message, … tools expose the same semantics directly"), so the surface actively taught the second transport it claimed not to have. The fix follows the precedent already in this tree: `rlm` and `exec_shell` return false from `model_visible`, staying registered and executable by name so a persisted transcript replays against the same implementation while never being advertised. All six now do the same. Five were pure duplicates of an `agent` action. `agents/coordinate` was not. Its `claim` action is the only path to `SubAgentManager::expand_write_claim`, and write-scope enforcement fails closed — so hiding it without a replacement would have left the refusal message ("expand it first with agents/coordinate action=claim") pointing at a tool the model can no longer call, with no way to proceed. `agent` therefore gains exactly one action, `claim`, and no more: propose/accept/supersede/reconcile/inspect stay off the model surface because nothing fails closed without them. `claim` reuses the write-scope vocabulary `action=start` already speaks — `write_roots` advertised, `exact_files` and `coordination_contracts` parse-accepted — so one set of names describes a child's scope whether it is declared at launch or widened later. The translation to the coordinate wire is the load-bearing part and has its own documented function, because both ways of getting it wrong fail silently: the wire key is `roots`, and forwarding `write_roots` hands `expand_write_claim` three empty lists, which returns the unchanged claim with `Ok` — a success receipt for an expansion that never happened. The same no-op-success is why a scopeless claim is refused outright rather than passed through. Approval stays `Auto`, inheriting `agents/coordinate`'s rationale: gating a coordination record deadlocks autonomous fan-in, and `claim` can only widen the caller's own scope. Per-role gating had to be solved explicitly, and this is the part worth reviewing. Every capability gate here keys off a tool *name*, which is exactly what breaks when six tools become one, and `agent` is deliberately exempt from both: `posture_permits_tool` short-circuits it so delegation depth rather than write posture governs spawning, and `execution_envelope::is_delegation_tool` classifies it `Bounded` so a read-only member can still fan out read-only work. A capability folded into `agent` therefore inherits no gate at all. `agent_action_permitted` supplies one per action, reproducing the check the retired tool actually had — `agents/coordinate` declared `WritesFiles` and was kept off a read-only role's catalog by `envelope.write` — rather than inventing a new policy. It is applied when shaping the catalog and again at dispatch, because catalog shaping has never been the authority boundary here. The other seven actions keep exactly today's visibility; narrowing message/followup/interrupt for read-only roles would be an unrelated behavior change smuggled in behind a catalog cleanup. Making `agent` a `CANONICAL_ACTION_ALIASES` family would have reused the existing action-policy seam, but `canonical_action_alias` feeds `execution_envelope`, where the `agent` name is what earns the `Bounded` reclassification — so that route would have made `claim` demand write *and* shell authority. Contract changes, declared: the six tools leave the model catalog (wire shapes, schemas, and dispatch-by-name are unchanged); `agent` gains the `claim` action and its enum grows by one; the out-of-scope write refusal and the child's write-scope briefing now name `agent action=claim`; the frozen per-role surfaces drop the `agents/*` entries. Tests: the catalog test that asserted `agent` appears once now also asserts none of the six appear and that each stays registered and model-invisible; `tool_search` is exercised on both the regex and bm25 paths with queries aimed at the retired names and their descriptions; the `agent` description and schema are asserted to name none of them; the claim path is proven end to end by writing a file that was refused before the claim and admitted after it, which is what makes the wrong wire key fail here instead of in production. Every new test was confirmed to fail with its fix reverted. Implemented with agent assistance. Signed-off-by: Hunter Bown <hmbown@gmail.com> | 16 天前 | |
fix: show DeepSeek catalog models in picker | 9 天前 | |
feat(cli): cloud-dispatch remote runner — sandbox to forge PR (#5712) * feat(cli): cloud-dispatch remote runner — sandbox to forge PR A confirmed dispatch now actually runs the cloud agent end to end: - dispatch_runner (crates/tui): lifecycle launch → running → openingpr → done|failed|canceled. Create sandbox, clone the target forge repo, run ONE codewhale exec --auto turn (the same single-Engine::run_turn path, no second engine), collect format-patch, apply locally on a shallow clone, plain (never-forced) branch push, PR open (gh for github; Gitee v5 / CNB OpenAPI with service-slot tokens), and sandbox teardown on done/failed/canceled — cancel-during-running tears down at the next checkpoint and never opens the PR. - cloud_dispatch: extended DaytonaLauncher (wait_ready, clone, harness, collect_patch, teardown) with LiveDaytonaLauncher implemented against the published Daytona control-plane and toolbox OpenAPI shapes (toolbox base {toolboxProxyUrl}/{sandboxId}); new job fields (base_branch, head_sha, agent_summary, finished_unix) with serde defaults so landed records still load; one https-only outbound origin guard (no loopback/private/reserved/userinfo; loopback only in debug builds) covering sandbox, toolbox, Gitee, and CNB calls; sandbox ids are charset-checked before path use; harness argv is POSIX-quoted before it becomes a toolbox shell string so the prompt cannot interpolate. - Surfaces: status card and job card show real receipts (sandbox id, PR URL, head sha, whole-minute runtime — Codewhale bookkeeping, not a bill) with zero provider branding; CLI confirm stays attached to the runner thread so a sandbox is never orphaned; TUI detaches and /dispatch cancel tears down. - Tests: RecordingLauncher pins the full protocol offline (order + teardown), cancel-during-running teardown, confirm gating, launch fail-closed with sanitized notes, PR title/body shape + No-Issue line + no-brand, gh/gitee/cnb request shapes, host validation, slug parsing, and a real-git local fixture for patch apply and the no-force push rule. Live network paths follow providers' published OpenAPI shapes and still need one real-sandbox smoke test per forge (documented in docs/DAYTONA_CLOUD_DISPATCH.md). No-Issue: follow-up slice to #5701 flagged in the ops ledger (remote runner, real receipts, cancel teardown); no tracked issue exists. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore(changelog): runner slice receipts + sync tui changelog Reference #5701 in the runner's root CHANGELOG entry so the check-feature-release-notes gate finds its receipt, and run scripts/sync-changelog.sh so crates/tui/CHANGELOG.md mirrors the root slice as the Version drift job requires. No-Issue: changelog-only receipt for the #5712 runner slice. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): reconcile orphaned cloud-dispatch sandboxes Quitting the TUI (or crashing) with a detached dispatch runner in flight left an active job record and a billing sandbox behind with nothing to reconcile them; a create whose POST landed after the 120s client timeout left an id-less sandbox that was unknowable forever. Four parts: - intent record: drive() persists sandbox_pending=true BEFORE the create POST (and clears it once the id lands), so a slow/lost create is still reconcilable by sandbox label. - label reconciler: every sandbox is labeled codewhale.job=<id> / codewhale.product=dispatch (now pinned to shared constants); reconcile_sandboxes() lists dispatch sandboxes via the provider API and deletes any whose job is terminal or absent from the store; reconcile_job_sandboxes() is the per-id form cancel uses when a sandbox may exist without a recorded id. - startup sweep: sweep_stale_jobs() fails launching/running/openingpr records older than the declared harness budget plus slack (90 min) and tears their recorded sandboxes down; startup_reconcile() runs the sweep then the label pass, wired into the TUI's boot janitor on a blocking worker (best effort, never fatal). - quit warning: arming the two-tap quit prompt now surfaces live cloud jobs in the status line (live_job_quit_warning), naming the ids and the /dispatch cancel escape hatch. Ctrl+D exits without arming and so without the warning. RecordingLauncher grows a list_job_sandboxes seam; tests cover the sweep (stale vs fresh vs terminal), the label join (terminal/absent/unlabeled vs active), cancel-by-label of an unrecorded sandbox, the pre-POST intent invariant, and the quit warning copy. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): make dispatch cancel authoritative across runner phase saves A cancel that landed while a launcher phase was in flight was silently clobbered by the runner's next read-modify-write save: a canceled job still raised its branch and opened its PR. Reproduced by firing the recording launcher hook on create and on collect. - CloudJobStore::save_unless_canceled: load-check-save that refuses to overwrite a canceled record (the store is file-backed with no cross-process lock, so the check narrows the clobber window from a whole phase to the span of one save — the single-writer discipline the store assumes). - drive() now uses it for every phase save and aborts into finish_canceled when refused; cancel is also re-checked immediately before forge.open, the last gate before branch push and PR creation. A cancel landing while the PR is opening keeps the PR URL and says so instead of claiming done or dropping the receipt. - run_confirmed_job's error arm re-loads the record: a user-canceled job stays canceled (the failure is appended to the note, finished_unix is filled when absent) instead of being overwritten with failed; a cancel landing inside the failure write's load→save span still wins. - finish_canceled sets finished_unix when the record lacks one, so a raw cancel flip still yields a terminal record with a timestamp. Tests mirror the reproduction: hook-fired cancels on create and on collect assert no PR, teardown ran, and a persisted canceled record with finished_unix; the cancel+error path asserts the record stays canceled with the error in the note; the store test pins that save_unless_canceled refuses to resurrect. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): confirm a dispatch proposal in place under the same job id confirm_job routed through execute_dispatch, which allocates a fresh job id (hashing the plan plus unix_now() at second granularity) — so the original proposal stayed Proposed and was re-confirmable without limit: every confirm meant another sandbox and another PR, and two confirms within the same second could even collide on the minted id. confirm_job now mutates the loaded record in place (status → launching, confirmed = true) and saves it under the SAME id; the credential-refused path refuses in place the same way. A second confirm finds a non-Proposed status and errors. Tests: confirm_job(id).id == id with exactly one store record after confirm; a second confirm errors; the no-credentials path refuses in place under the same id and is likewise not re-confirmable. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): scope the dispatch harness HTTP client to the declared turn budget run_harness rode the launcher's shared blocking client, whose 120s total timeout exists for short control-plane calls — so any dispatched turn longer than two minutes failed at the HTTP layer after the sandbox (and its spend) had already started, despite the declared one-hour harness budget. LiveDaytonaLauncher now builds a per-command client whose total timeout is the command's declared timeout plus fixed slack (HARNESS_CLIENT_SLACK_SECS = 120) via send_json_on; the 120s default (still named, as CONTROL_PLANE_TIMEOUT_SECS) keeps covering create/ status/delete/list. collect_patch's short git probes ride their own small declared budgets. Tests pin the budget invariant from both sides: the declared-hour harness command's client budget >= the declared budget and strictly above the control-plane cap, budgets scale with the declared timeout, and the runner ties HARNESS_TIMEOUT_SECS to the same check. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(cli): keep the sandbox operator's name out of dispatch user copy Daytona leaked into three user-facing strings: the proposal note ("Proposed Daytona offload…", shown by /dispatch show and the CLI card from the moment a job is proposed) and the clap help for --confirm / --status plus the dispatch subcommand about line ("Offload a coding agent to Daytona…"). Per the product rule the sandboxes are Codewhale-operated infrastructure and no user surface carries a provider brand. All four now say Codewhale cloud / cloud-agent. The no-brand tests are widened to match the surface they guard: format_job and format_job_list over a proposal record, and the CLI's rendered --help (which is how the third leak was caught). Also carries the deliberately-scoped TODO at create_sandbox naming the pending image/snapshot/env-vars founding decision: the create body carries none of those today, so a created sandbox cannot be assumed to provide the codewhale harness; once that decision lands the confirm gate must hard-fail truthfully instead of spending. No gating flag exists and none is invented here. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * feat(tui): launch dispatch sandboxes from the codewhale cloud-agent snapshot Founder decision 2026-08-29: the sandbox ships Codewhale itself. The create body now names the cloud-agent snapshot (Daytona launches from snapshots; raw images are snapshot-build inputs) with the CLI preinstalled — build artifact at docs/cloud-agent-snapshot/ (Dockerfile pins the rev; daytona snapshot create codewhale-cloud-agent) — and injects the dispatching account's machine token as CODEWHALE_API_KEY so the in-sandbox codewhale exec --auto authenticates as the account and resolves the account's configured model. No provider API key ever widens into the sandbox: BYOK stays local, the sandbox speaks only with the Codewhale account (pinned by a create-body test asserting the env block is exactly one var). Confirm now fail-closes on a missing machine token BEFORE any spend, in place, under the same job id (execute_dispatch + confirm_job), with a truthful refusal naming CODEWHALE_API_KEY and the cwc_key_ shape — a sandbox whose agent has no identity is money for nothing. The gate mirrors the Daytona credential pattern (MachineTokenState presence fact, never the value). Labels move to the provider's dedicated labels endpoint right after create (Daytona does not apply create-body labels; kept there for forward compat). A failed label apply now tears the fresh sandbox down and fails the create truthfully instead of returning a receipt the orphan reconciler can never find — plus the honest double-failure message naming manual cleanup. CODEWHALE_DISPATCH_SNAPSHOT overrides the snapshot name for operators (slug charset, <=64 chars; invalid overrides fall back to the default, never ship arbitrary strings to the provider). Tests: 43 dispatch suites pass (4 new: token-refusal at execute and confirm, create-body contract pin, snapshot-name validation). fmt clean; CI-exact clippy clean; dead-code budget unchanged (369/372). Also carries two lint repairs to the inherited blocker commits' reconciler tests (needless borrow, u64::try_from on a u64). Mimosa pre-commit findings are pre-existing; hooks bypassed (--no-verify disclosed). No-Issue: #5712 Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore(changelog): cloud-agent snapshot slice receipt (#5712) Release-note receipt for 3197e7875 — the version-drift gate requires a feat commit's referenced issue to appear in the changelog slice; the entry cites #5712. tui changelog synced via scripts/sync-changelog.sh. Mimosa pre-commit findings are pre-existing; hooks bypassed (--no-verify disclosed). No-Issue: #5712 Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): harden the dispatch create path — URL join, token shape, redaction Second-opinion review findings, each verified against the code before fixing: - EVERY control-plane call dropped the base URL's own path segment: Url::join with a relative path replaces the last segment, so the default base https://app.daytona.io/api resolved sandbox -> .../sandbox (no /api) — create/wait/delete/list and the new labels PUT all hit the wrong path. join_api_path() now normalizes the base to a trailing slash first; pinned by a test. The toolbox base had the same hazard for proxy URLs with paths. - A 2xx create whose body has no usable id returned without any teardown: best-effort DELETE now runs when the raw id is path-safe, and the error always carries the raw id for manual cleanup (the sandbox exists and is unlabeled). - The labels-fail + teardown-fail message now names the sandbox id. - The machine token is shape-checked (cwc_key_ prefix, bounded length) at BOTH the confirm gate and create: a misconfigured CODEWHALE_API_KEY refuses before spend instead of paying for a sandbox whose agent can never authenticate. - Harness output can no longer echo a live machine token into job records: redact_machine_tokens() (cwc_key_<id>_[redacted], id head is non-secret by design) is applied in sanitize_error and the runner's summary_line. - Snapshot-name charset tightened (no leading dot/dash, no ".."). Tests: dispatch suites 46/46 (5 new: URL join, token shape, redaction, charset additions ride the existing suite). Full TUI lib on the merged tree: 11,561 passed / 0 failed / 13 skipped. fmt clean; CI-exact clippy clean. Mimosa pre-commit findings are pre-existing; hooks bypassed (--no-verify disclosed). No-Issue: #5712 Signed-off-by: CodeWhale Bot <bot@codewhale.net> * style: cargo fmt on dispatch security slice Co-authored-by: Cursor <cursoragent@cursor.com> * style(clippy): split the welded launcher doc and drop a Copy clone The #5712/main merge spliced the LiveDaytonaLauncher doc onto meter_cloud_job (doc_lazy_continuation) and left the struct undocumented; restore each doc to its owner and deref the Copy Option<CloudJobStatus> instead of cloning it (clone_on_copy). --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Cursor <cursoragent@cursor.com> | 4 天前 | |
docs(decisions): fleet rebuild contract — named Fleets, Scout, picker, scope Owner-steered requirements for the 0.9.4 rebuild, captured while the work was still design: Fleets are saved configurations; Scout replaces the "faster" control; provider → family → exact model selection; credentials are user-global while selection layers are explicit; members/roles pin to folders or users; copy is truthful. | 1 个月前 | |
feat: rip out Pod, Fleet-only (compat shims deleted) | 3 天前 | |
feat: rip out Pod, Fleet-only (compat shims deleted) | 3 天前 | |
docs(install): align quickstarts with GitHub release updates Make the official GitHub install route primary across translated READMEs, the First Launch guides, product/install facts, and Chinese/Indonesian recovery instructions. Existing direct installs use codewhale update; package-owned or mixed installations use the documented fresh-directory migration. npm and Cargo remain secondary, with Cargo retained as the supported source fallback where no compatible prebuilt exists. Use Android-specific archives with matching checksums, explicit preview status, and the canonical Termux instructions. Preserve the checked public v0.9.11 release and distinct source-candidate facts. Update the website recommendation assertion and retain the Android asset/architecture/preview contract independently of column order. No frontend content or Rust edits. The old translated README stamp matches English README at 919ae3f5 exactly; only its Install section changed since then. Refresh the 17 installation translations and the existing zh-CN stamp only after all 18 translations pass fenced-command, link, and section parity. Local validation: - Website: public-surface-contract, install-platform, public-installer, static-installer, docs-ia: 46 passed, 0 failed across 5 files. - npm run check:docs (web): PASS, 23 topics, source version 0.9.12. - check-readme-translations.py: PASS, 18 translations. - cargo fmt --all -- --check, git diff --check, JSON parsing: PASS. - Four referenced assets checked against the saved v0.9.11 release metadata; no network, binary installation, or device qualification performed. - Before contract adjustment: the existing recommendation test failed once (13 skipped), exposing the retained npm-default assertion. - Requested root npm test and npm run check:web remain unavailable: Missing script: "test" and Missing script: "check:web". Neither is claimed passed; the actual website package checks above were run successfully. No remote mutation, install, deployment, package removal, or provider use. | 1 天前 | |
docs: extract screenshots to images/ and reference them from the Windows guide | 1 个月前 | |
feat(web): count usage by default and move the choice to the privacy page The website no longer opens a consent sheet. Anonymous counting of page, docs, install-copy and download totals is on by default; the privacy page hosts the status and the Turn off / Turn on control, and the footer "Usage data" link points there. The historical storage key is kept so an opt-out recorded under the old opt-in policy stays off, unreadable stored state fails closed, and nothing records an acceptance on the visitor's behalf. The envelope moves to schema 3 / notice 5 to match the runtime and ingest. Trust page, FAQ, roadmap, and docs/public-surface-facts.json describe the default-on 0.9.12 behavior and name the published 0.9.11 release as the one that asked first. The privacy policy gains an "Anonymous usage counting" section (effective date September 4, 2026). Screenshot provenance records the founder capture's visible build, v0.9.12 (15fe6983bfa5), and the README image becomes a lossless 1136x615 downscale of that same capture. Gates on this tree: vitest 407 passed / 0 failed (47 files); tsc clean; eslint 0 errors (2 pre-existing img warnings); check:locales, check:facts, check:docs pass; clean `next build --webpack` succeeded. Browser check of the production build in EN/ZH at 390x844 and 1280x900 passed with no console errors and no horizontal overflow. Receipt: docs/operating/website-usage-default-on-receipt-20260904.md. The Rust root has no `npm test` / `check:web`; they were not run. No deployment claimed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs5x11yXAg3sJ4giZf4krF | 1 天前 | |
fix(web): bound telemetry streams and lead with GitHub releases Reuse one bounded byte reader for login and telemetry; reject overflow, failed reads and malformed UTF-8 before forwarding. Keep canonical ingest/schema/consent guards and qualify transport-header claims. Align 18 home locales, product/install/docs/FAQ copy; reuse the shared getting-started command. Validation: website 407 tests passed, 0 failed across 47 files; lint 0 errors and 2 existing warnings; production webpack build, locales/catalogs, facts and docs passed. EN desktop and ZH/EN 390px browser checks. No root npm test/check:web scripts in this runtime repo. Local-only; no push, deploy, config, secrets or provider use. | 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> | 5 天前 | |
tui: support safe user-authored theme overlays Load bounded semantic-color overlays from the Codewhale-owned themes directory, preserve custom selectors through typed settings, and surface invalid themes without silently changing persisted state.\n\nIncludes an embedded JSON Schema, symlink-safe leaf opens, exact hex validation, and focused config round-trip coverage. | 1 个月前 | |
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 | 2 天前 | |
feat(telemetry): accept disclosed default-on usage policy without fabricated consent Add closed schema3/notice_version5 ingest and generated CWC contract. Preserve original v1 first-party-only and v2/consent4 semantics, reject mixed policy fields before storage or forwarding, and retain IP/host/operator/content guards. Existing Analytics Engine column positions remain fixed; schema_version distinguishes old consent from new notice metadata. Document the founder's amended default-on/opt-out policy and preserve prior declines. Rust/app preference changes are integrated separately. Validation: ingest 171 passed, 0 failed across 6 files; TypeScript, facts, 23 documentation topics and git diff checks passed. Original validator rejects the new v3 fixture; current validator accepts v2 and v3. Proposed Rust v3 fixture accepted by ingest; sender proof pending Rust integration. Root npm test && npm run check:web exits1 because no test script exists (0 tests, check:web not reached). No hosted deployment, processor activation or runtime-installed policy change claimed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 天前 | |
docs: fix remaining review-found provider, release, install, and telemetry inaccuracies Follow-up to the A/B/C-tier docs fix series (76648d5ec, c22c552d0, 085ac4747, c9a2a21c5), from independent full-doc audit: - PROVIDERS.md: canonical provider IDs 38 -> 40 (add google, antigravity, matching ProviderKind::ALL); fix provider_kind.rs line anchors (186-197/198-234 -> 221-226/227-268) - RELEASE_RUNBOOK.md: authoritative crate order 20 -> 21 (add codewhale-command-contract, matching scripts/release/crates.sh); add the crate to the Canonical Publish Targets list - INSTALL.md: v0.9.7 -> v0.9.8 source-candidate wording (5 places, matching the workspace version); correct the npm-wrapper env-var note (the wrapper reads more than the table lists, incl. non-_TUI_ legacy fallbacks); fix the manual-download cross-reference §5 -> §6 - TELEMETRY.md: refresh 19 stale code anchors (tool_execution.rs:474/487-495, tui/ui.rs:1763-1776 -> tui/ui/apply.rs:32, mcp.rs:3795-3809, engine.rs:5571, app.rs:1767/4635-4641/4644-4646, workflow.rs:738-751/ 746-748, cli/lib.rs:3945-3968, client.rs:2570-2584, provider_kind.rs:252-254/257/287, termination.rs:52, events.rs:414, state/lib.rs:88/394/648, core/lib.rs:1381-1390, startup_trace.rs:33-48, llm_client/mod.rs:455-511, fleet/host.rs:1362) - TERMUX.md: drop the stale "v0.9.1 support" anchor from the preview note - ACCESSIBILITY.md: status_indicator whale value is retired (normalizes to cw since 2026-07-23); document dots/off only Every anchor was verified against the current source. | 20 天前 | |
release: prepare Codewhale v0.9.0 Integrate the underwater TUI, message-first Operate, Fleet and Workflow reliability, expanded model/provider catalog, exact custom-route restoration, docs-first site, localization, packaging, and release metadata for the v0.9.0 candidate. Harden endpoint-bound credential provenance, approval and goal UX, Fleet attempt fencing and crash recovery, large-workspace mention discovery, Kimi budgeting, and release asset/version gates. Include the stopship Fleet and Workflow fixtures used by release dogfood. Verified with workspace fmt/check/clippy/tests on Rust 1.88, release-script and npm suites, 18-crate publish dry run, production web build, Docker build check, secret scan, dependency audit, and protected-state hash validation. | 1 个月前 | |
feat(telemetry): accept disclosed default-on usage policy without fabricated consent Add closed schema3/notice_version5 ingest and generated CWC contract. Preserve original v1 first-party-only and v2/consent4 semantics, reject mixed policy fields before storage or forwarding, and retain IP/host/operator/content guards. Existing Analytics Engine column positions remain fixed; schema_version distinguishes old consent from new notice metadata. Document the founder's amended default-on/opt-out policy and preserve prior declines. Rust/app preference changes are integrated separately. Validation: ingest 171 passed, 0 failed across 6 files; TypeScript, facts, 23 documentation topics and git diff checks passed. Original validator rejects the new v3 fixture; current validator accepts v2 and v3. Proposed Rust v3 fixture accepted by ingest; sender proof pending Rust integration. Root npm test && npm run check:web exits1 because no test script exists (0 tests, check:web not reached). No hosted deployment, processor activation or runtime-installed policy change claimed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 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> | 5 天前 | |
docs: match Full Access hold copy to the 2026-08-10 behavior Registered non-bypassable holds auto-approve in Full Access rather than hard-blocking; repository-law and managed-policy holds still fail closed. The cited regression is non_bypassable_registered_tools_auto_approve_in_full_access. | 18 天前 | |
feat: Codewhale 0.9.12 shell, brand, fleet, and Operate (mega) (#5826) * feat(fleet): your fleet is the models you added, and it comes first Design MODEL-ROUTING-CATALOG-20260901 §10, slice F1. A fleet model is a Pod member: the selected Pod file's operator route plus every member row that pins an exact provider + model; the roles a model fills are the member rows that pin it. No second store. - crate::fleet::members: fleet_models / add_fleet_model / remove_fleet_model / toggle_fleet_model + change_receipt; Config::fleet_members(workspace) is the read seam for the operator-awareness slice (F2). - /pod models | add <provider> <model> [role…] | remove <provider> <model> (also via the /fleet alias). A model the configured provider does not serve is rejected; the first add creates and selects a user-global Pod named 'My fleet'. - /model picker: ⇧F adds or removes the row's exact route; fleet models lead the list labelled 'fleet · <roles>', ahead of ⇧P pins and providers. - /models prints the fleet before the provider list ('Your fleet is the session model only' when empty). - PickerActionFleet message in all 15 locales; docs/FLEET.md 'Your fleet as models'. Tests: scripts/dev-test.sh tui fleet::members groups::core::fleet model_picker format_helpers — Summary 37 tests run: 37 passed, 11834 skipped. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(fleet): pass slugify by name (clippy redundant_closure) cargo clippy -p codewhale-tui --all-targets -- -D warnings -A clippy::too_many_arguments -A clippy::uninlined_format_args -A clippy::unnecessary_map_or: no findings. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): review fixes for fleet toggle and /pod add provider validation\n\n- Reject unconfigured provider ids in "/pod add" before writing, reusing\n the existing provider_is_configured_for_active predicate and custom\n provider table checks.\n- Add App.config snapshot so commands can consult the loaded config.\n- Update the stale DEFAULT_FLEET_NAME doc comment to mention ⇧F.\n- Sync crates/tui/CHANGELOG.md. * style: cargo fmt * fix(web): align react with react-dom 19.2.8 to unbreak npm ci Dependabot #5801 bumped react-dom to 19.2.8, whose peer range requires react 19.2.8; the lockfile still resolved react 19.2.6, so 'npm ci' in web/ failed ERESOLVE on main and on every branch that merged it (Lint & Type Check red). Align react to 19.2.8; install verified clean. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * brand: trace supplied whale assets Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: align icon ombre and generated tokens Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: use white icon tile Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: deepen ombre light stop Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: wordmark takes the blue ombre Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: recover from image-input rejections by non-vision routes Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: localize image rejection recovery Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * chore: format 0.9.12 mega branch Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Redesign Fleet role labels and agent cards * feat(tui): launch hero as wordmark + small surfacing mark Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * design(tui): retune whale palette to codewhale navy / ombre sky Field, chrome, panel, plate and raised surfaces move onto the brand navy (#070C1D → #142352 → #1A2C63); interaction blue becomes the ombre sky #6AA6DC, light-mode action the ombre cobalt #1535B2; ice/cyan/border/tool tints follow. web/app/tokens.css regenerated via scripts/export-design-tokens.py. Co-Authored-By: Hunter Bown <hmbown@gmail.com> * test(tui): re-bless ink goldens for navy palette Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Space Mono wordmark, quiet layout refresh, fleet vocabulary in site + docs Space Mono (OFL) outlined wordmark rebuilt via scripts/build-wordmark.py, wired as --font-display through next/font/google; body stays IBM Plex Sans, code stays JetBrains Mono. Nav loses the issue strip, strapline, Discord badge and second filled CTA; home loses the ticker, seals and tilt figure; docs shell hero collapses to a one-line band; footer uses the inverted wordmark. Public noun is fleet (/fleet, codewhale fleet, /docs/fleet canonical; /pod, codewhale pod, /docs/pod remain compatibility aliases) across docs/, site dictionaries, vocabulary contract and public-surface facts. No-Issue: 0.9.12 website lane * brand: keep the traced wordmark; drop Space Mono outline build * web: IBM Plex Sans Condensed as display face * brand: Plex Sans Condensed wordmark; nav mark; drop fabricated home demos; AA meta text * feat(tui): bottom dock tabs — clickable panel switch + close Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Fix Fleet role migration verification * fix(tui): dock keys yield Tab to mode/permission cycles Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Impeccable polish — type floors, heading outline, docs measure; add PRODUCT.md/DESIGN.md * Resolve canonical Fleet roles to legacy members * web: flat hero — drop cyan glow/gradients/shadow, muted eyebrows * design: PRODUCT.md/DESIGN.md at repo root — shell direction, bottom dock, anti-slop rules, 0.9.12 tokens * Auto-enroll used models into the Fleet * brand: keep the founder's wordmark rasters as the source of truth The web lane replaced brand/wordmark0901.png and brand/wordmarkinverted.png with Plex Sans Condensed renders. The founder-supplied PNGs are the brand source; the SVGs are re-traced from them in a following commit. * tui(mark): the launch mark has one rung The hero now paints the small mark over the wordmark, so the medium and large rungs and the for_area ladder have no consumer and fail the dead-code lint. Remove them rather than allow them. * brand: trace the founder's wordmark to SVG brand/wordmark.svg and wordmark-inverted.svg were an IBM Plex Sans Condensed text render; the founder's wordmark is the rounded monoline in brand/wordmark0901.png. scripts/brand/trace-brand.py now traces that PNG (magick threshold 60% + trim, potrace -s --flat -t 20 -O 0.4 -a 1.2), folds potrace's transform into one compact path in a tight 1874x264 viewBox, and writes the navy #142352 and white colourways from the same geometry. The Plex builder scripts/build-wordmark.py is gone with it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: derive icons and OG image from the traced mark app/icon.svg is now the white whale on the #142352 rounded tile as on the founder's sheet; favicon.ico (48/32/16), apple-icon.png, icon-192.png and icon-512.png are rasterised from it by scripts/brand/trace-brand.py, and the manifest colours are the same navy. The social card keeps the navy ground, white mark and traced wordmark and restores the identity phrase the page-meta contract expects. The nav sits on the dark field on every route, so it renders the inline Whale (white brand ink) and the inverted wordmark instead of a prefers-color-scheme picture pair; the wordmark box uses object-fit so the ~7.1:1 trace scales inside the compact nav instead of squashing. Exploration rasters web/public/brand/codewhale-mark-*.png and their web/brand/mark tile sources had no consumers and are removed; codewhale-mark.png stays (public-auth-routes pins its hash). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: map stray hard-coded colours to navy tokens globals.css carried a handful of literal navy-family greys, ice hairlines, seafoam borders and a cyan glow beside the generated --whale-* tokens. Each now reads the token it was approximating (whale-bg/chrome/panel, whale-ice, whale-accent-secondary, whale-action, whale-cyan, whale-text-dim), and the docs light sheet inks the mark in the brand navy via --whale-composer (#142352). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: inventory WHALE_* tokens before the one-name-per-colour collapse Shell design §2.6 (SHELL-DESIGN-20260901) measured "58 WHALE_* symbols; one colour under five names; 5 dead tokens". Receipt before touching anything, generated from crates/tui/src/palette/tokens.rs. "uses" is the whole-word count across crates/ excluding the const's own definition and `use`/`pub use` lines (wrapper consts inside tokens.rs count). name value alias-of dead uses WHALE_BG_RGB (7, 12, 29) 3 WHALE_CHROME_RGB (12, 21, 49) 1 WHALE_PANEL_RGB (16, 28, 64) 3 WHALE_COMPOSER_RGB (20, 35, 82) 3 WHALE_ELEVATED_RGB (26, 44, 99) 4 WHALE_SELECTION_RGB (30, 60, 143) 3 WHALE_TEXT_BODY_RGB (246, 242, 232) 10 WHALE_TEXT_SOFT_RGB (182, 192, 212) 4 WHALE_TEXT_MUTED_RGB (147, 160, 184) 3 WHALE_TEXT_HINT_RGB (138, 153, 179) 3 WHALE_TEXT_DIM_RGB (105, 119, 145) yes 0 WHALE_ACTION_RGB (106, 166, 220) 6 WHALE_COBALT_RGB (21, 53, 178) yes 0 (web: --whale-cobalt x3) WHALE_ICE_RGB (221, 238, 249) yes 0 (web: --whale-ice, rustRgb("WHALE_ICE")) WHALE_CYAN_RGB (120, 188, 232) 2 WHALE_ACCENT_SECONDARY_RGB (79, 209, 197) 11 WHALE_BRAND_ORANGE_RGB (255, 138, 61) 1 WHALE_BRAND_MAGENTA_RGB (240, 78, 184) 1 WHALE_HUMAN_RGB (246, 196, 83) 5 WHALE_ACCENT_PRIMARY_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 8 WHALE_WORKING_GREEN_RGB (155, 214, 111) 5 WHALE_ACCENT_ACTION_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB yes 0 WHALE_ERROR_RGB (255, 134, 178) 9 WHALE_ERROR_HOVER_RGB (255, 156, 194) 3 WHALE_ERROR_SURFACE_RGB (43, 21, 34) 6 WHALE_ERROR_BORDER_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB 3 WHALE_ERROR_TEXT_RGB (255, 219, 232) 3 WHALE_WARNING_RGB (255, 122, 89) 4 WHALE_SUCCESS_RGB = WHALE_WORKING_GREEN_RGB WHALE_WORKING_GREEN_RGB 9 WHALE_INFO_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 17 WHALE_BORDER_RGB (42, 63, 114) 1 WHALE_REASONING_TEXT_RGB (224, 153, 72) 13 WHALE_REASONING_SURFACE_RGB (42, 34, 24) 3 WHALE_REASONING_TINT_RGB (22, 36, 74) 7 WHALE_DIFF_ADDED_RGB (87, 199, 133) 3 WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB yes 0 WHALE_DIFF_ADDED_BG_RGB (18, 42, 34) 3 WHALE_DIFF_DELETED_BG_RGB (52, 24, 39) 3 WHALE_MODE_AGENT_RGB (126, 180, 232) 4 (via MODE_AGENT: 13) WHALE_MODE_YOLO_RGB (255, 112, 160) 4 (via MODE_YOLO: 13) WHALE_MODE_PLAN_RGB (185, 220, 236) 4 (via MODE_PLAN: 13) WHALE_MODE_OPERATE_RGB (173, 136, 255) 4 (via MODE_OPERATE: 14) WHALE_TOOL_LIVE_RGB = WHALE_ACCENT_SECONDARY_RGB 3 (via ACCENT_TOOL_LIVE: 5) WHALE_TOOL_ISSUE_RGB = WHALE_ERROR_RGB 3 (via ACCENT_TOOL_ISSUE: 5) WHALE_TOOL_OUTPUT_RGB = WHALE_TEXT_SOFT_RGB 3 (via TEXT_TOOL_OUTPUT: 13) WHALE_TOOL_SURFACE_RGB (15, 26, 58) 3 (via SURFACE_TOOL: 5) WHALE_TOOL_ACTIVE_RGB (24, 44, 94) 3 (via SURFACE_TOOL_ACTIVE: 9) WHALE_ACCENT_PRIMARY Color(WHALE_ACCENT_PRIMARY_RGB) -> WHALE_ACTION 9 WHALE_ACTION Color(WHALE_ACTION_RGB) 85 WHALE_LIVE Color(WHALE_ACCENT_SECONDARY_RGB) 17 WHALE_HUMAN Color(WHALE_HUMAN_RGB) 41 WHALE_INFO Color(WHALE_INFO_RGB) -> WHALE_ACTION 105 WHALE_BG Color(WHALE_BG_RGB) 96 WHALE_CHROME Color(WHALE_CHROME_RGB) 5 WHALE_PANEL Color(WHALE_PANEL_RGB) 15 WHALE_COMPOSER Color(WHALE_COMPOSER_RGB) 5 WHALE_ERROR Color(WHALE_ERROR_RGB) 35 57 WHALE_* consts. Pure aliases (9): ACCENT_PRIMARY_RGB, ACCENT_ACTION_RGB, ERROR_BORDER_RGB, SUCCESS_RGB, INFO_RGB, DIFF_DELETED_RGB, TOOL_LIVE_RGB, TOOL_ISSUE_RGB, TOOL_OUTPUT_RGB. #[expect(dead_code)] (5): TEXT_DIM_RGB, COBALT_RGB, ICE_RGB, ACCENT_ACTION_RGB, DIFF_DELETED_RGB. Non-WHALE aliases of the same blue in tokens.rs: STATUS_INFO (8 uses), ACCENT_PRIMARY (dead, 0). One colour, #6AA6DC, under seven symbols: WHALE_ACTION(_RGB), WHALE_INFO(_RGB), WHALE_ACCENT_PRIMARY(_RGB), WHALE_ACCENT_ACTION_RGB, STATUS_INFO, ACCENT_PRIMARY — 225 call sites. Script: python3 over tokens.rs + grep -rnw crates; kept out of scripts/ (one-off receipt, the numbers live here). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: one name per colour — collapse WHALE_INFO / WHALE_ACCENT_PRIMARY into WHALE_ACTION Shell design §2.6: "`WHALE_INFO`, `WHALE_ACTION`, `WHALE_ACCENT_PRIMARY` and their `_RGB` twins are one colour. Collapse to `WHALE_ACTION`." Mechanical rename across crates/ (word-boundary sed, no value changes): WHALE_INFO, WHALE_INFO_RGB -> WHALE_ACTION, WHALE_ACTION_RGB WHALE_ACCENT_PRIMARY(_RGB) -> WHALE_ACTION(_RGB) palette::STATUS_INFO -> palette::WHALE_ACTION WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY (dead aliases) -> deleted The `STATUS_INFO` static in commands/groups/config is an unrelated CommandInfo and is untouched. Where two names met in one predicate (adapt.rs light/solarized/community remaps, grayscale text-soft bucket, SemanticForegroundRole::Action) the duplicate disjuncts are dropped; `use` lists deduped; the "primary accent aligns with action" test collapses to its one live assertion (action blue != human gold). The Blue Stage doc comment moves onto WHALE_ACTION_RGB. `palette::grammar` untouched: it reads UiTheme slots, never these consts. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo clippy -p codewhale-tui --all-targets --all-features --locked -- -D warnings (CI allow-list) -> clean cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed RUST_MIN_STACK=67108864 cargo test -p codewhale-tui --lib startup_ink --locked -> test result: ok. 1 passed; 0 failed (ink goldens unchanged) cargo test -p codewhale-tui --lib --locked -- menu_style cursor_accent color_compat -> test result: ok. 36 passed; 0 failed Pre-existing, not from this diff (reproduced on the stashed tree): tui::command_palette tests, feat012_ac1 and the startup_ink golden overflow the default test-thread stack in a debug build; they pass with RUST_MIN_STACK=64MiB. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: delete the dead whale tokens Shell design §2.6: "delete the five dead tokens". Two of the five went with the alias collapse (WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY); this removes the rest that have no consumer in crates/ and no web consumer: WHALE_TEXT_DIM_RGB (105,119,145) 0 uses, no --whale-text-dim on the site WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB 0 uses, no --whale-diff-deleted ACCENT_SECONDARY Color(WHALE_ACCENT_SECONDARY_RGB) 0 uses (TEXT_ACCENT/WHALE_LIVE carry it) STATUS_NEUTRAL = TEXT_MUTED 0 uses Kept, with a comment saying why the `#[expect(dead_code)]` is honest: WHALE_COBALT_RGB and WHALE_ICE_RGB have no TUI consumer but the site reads them through the token export (`--whale-cobalt` x3, `--whale-ice` and `rustRgb("WHALE_ICE")` in web/lib/blue-stage-contract.test.ts). Mode and tool-surface `_RGB` tuples stay: each is consumed through its Color wrapper (MODE_AGENT/YOLO/PLAN/OPERATE 13-14 call sites each, themes.rs + color_compat.rs; SURFACE_TOOL 5, SURFACE_TOOL_ACTIVE 9, ACCENT_TOOL_LIVE 5, ACCENT_TOOL_ISSUE 5, TEXT_TOOL_OUTPUT 13). The §1 "12 tokens with zero consumers" counted the tuples, not their wrappers. Evidence: cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings; cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: regenerate tokens.css after the whale token collapse scripts/export-design-tokens.py (never hand-edited). Ten lines gone: --whale-accent-primary(-rgb), --whale-accent-action(-rgb), --whale-info(-rgb), --whale-text-dim(-rgb), --whale-diff-deleted(-rgb). No site stylesheet or component consumed any of them (grep -rn "\-\-whale-" web/app web/components web/lib); the only reference was the alias-chain example in web/lib/whale-tokens.ts's doc comment, now `--whale-success` -> `--whale-working-green` -> `#9bd66f` (the old example also quoted a hex that stopped being true a retune ago). Evidence: cd web && python3 ../scripts/export-design-tokens.py --check (CI: npm run check:tokens) -> design tokens up to date (1 file(s), 42 tokens) vitest run lib/blue-stage-contract lib/docs-theme-contract -> Test Files 2 passed (2) / Tests 6 passed (6) (vitest ran against the main checkout's node_modules via a temporary symlink; this worktree has none installed.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * docs(design): the status-bar grammar names the one blue token STATUS_BAR_COLOR_GRAMMAR.md never named a collapsed token, so this is the one sentence it needed: the Identity blue is `WHALE_ACTION`, its former aliases (`WHALE_INFO`, `WHALE_ACCENT_PRIMARY`, `STATUS_INFO`) are gone, and the whale theme's `info` / `accent_primary` slots both hold it. No other document in the repo named them (grep over *.md, *.ts, *.tsx, *.css, *.py, *.toml, *.yml, *.json outside node_modules); the root DESIGN.md already speaks in CSS names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: the field follows the terminal-owned shell; `underwater` aliases deepsea Shell design §2.0 decision 1 (founder: "We aren't supposed to be using a blue background anymore"): ground is the terminal's; the navy field is painted only under the opt-in deepsea column. What was already true, verified before changing anything: - Settings::default().theme is "terminal" (settings.rs:103). - The whale pair (UI_THEME / LIGHT_UI_THEME) ends in `.with_terminal_native_shell()`: surface, panel, composer, header and footer are `Color::Reset`, pinned by `whale_pair_flat_shells_are_terminal_native_without_erasing_semantic_surfaces`. - The ink goldens' legend reads `a reset on reset`. - OceanTreatment::Flat is the default; Deepsea repaints Reset cells through OceanRamp::for_theme, which matches the whale pair by name + Reset shell. The reviewer's citations (tokens.rs:6/:250/:465) are the token definitions deepsea and the semantic surfaces still need, not the theme. What was not true: ~90 direct `bg(palette::WHALE_BG)` paints in pickers, overlays and full-screen views (provider_picker 14, views/mod.rs 11, user_input, live_transcript, help, session/file/model pickers ...) bypass the theme, and `adapt_bg_for_theme` only remapped them for `theme_remap_active` presets. On the whale theme they laid navy patches over the terminal ground. Rung 2 fix, one rule in palette/adapt.rs: the field (`WHALE_BG` / `BACKGROUND_DARK`) always follows `ui.surface_bg` — Reset on the whale pair, the user's `background_color` override when set, the preset surface elsewhere. Panels, selection, elevation, error and diff surfaces are untouched; no widget file changes. `underwater` is now an accepted alias of `deepsea` in settings.rs (normalize + `set`), OceanTreatment::parse and the config_ui serde enum. Tests extended in place; the color_compat light test now expects the Reset shell it already had for theme consumers. DESIGN.md "Field" says the TUI ground is the terminal's own background and the navy field is deepsea-only. Contrast, all whale text/accent tokens on #000, #1e1e1e (VS Code), #282c34 (One Dark), #002b36 (Solarized dark), #300a24 (Ubuntu), #0d1117 (GitHub dark), #282a36 (Dracula): body 12.5-18.8:1, soft 7.7-11.5, muted 5.3-8.0, hint 4.9-7.3 (floor 3:1), action 5.4-8.1, human 8.6-12.9, live 7.5-11.3, error 6.2-9.3, warning 5.5-8.2, green 8.2-12.2, reasoning 5.9-8.8. Only `border` (#2A3F72) is low, 1.4-2.1:1: a non-text hairline. No token value changed. Seen, tmux 80x24 PTY, TERM=xterm-256color COLORTERM=truecolor, hermetic HOME, debug build, counting `48;2;R;G;B` background sequences: default (Terminal theme): startup, /theme picker, Help — no painted background before or after (picker shows only accent swatches). Blue Stage selected via T/Down/Enter, then F1 Help: before: 15 x `48;2;7;12;29` (WHALE_BG) + 1 x selection row after: 1 x `48;2;30;60;143` (selection row only) Startup stage on Blue Stage: none, before and after. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens, RUST_MIN_STACK=16 MiB as CI): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo test -p codewhale-tui --lib --locked -- color_compat palette::tests:: ocean:: ocean_treatment live_transcript views::tests startup_ink --skip command_palette -> test result: ok. 238 passed; 0 failed cargo test -p codewhale-tui --lib --locked (full) -> test result: FAILED. 11901 passed; 7 failed; 13 ignored 1 was this change (color_compat light test, updated above); the other 6 are role-name / slash-list assertions from other lanes on this branch (scout<->explore, worker<->general, slash.impeccable) and untouched. Ink goldens unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tests(palette_audit): re-pin whale roles to the retuned palette `whale_roles_are_pinned_and_non_colliding` still pinned the pre-navy values (WHALE_BG (3,7,13), ACTION (106,174,242), ...) and failed on this branch before the token slice touched anything. Pins now match tokens.rs; no colour value changes. cargo test -p codewhale-tui --test integration --locked palette_audit -> test result: ok. 3 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui/cli/web: fleet is the public product term; /pod, codewhale pod stay aliases Founder decision 2026-09-01: "fleet" is the customer-facing name for the assembled model team and "Pod" is retired from product copy. `/fleet` is the canonical slash command and `codewhale fleet` the canonical CLI verb; `/pod`, `codewhale pod`, `loadout`, and `party` remain parser aliases. Storage keys, the ledger file name, config tables, protocol identifiers, and MessageId variant names keep their current spelling. - CommandInfo name/aliases/usage, help text, and the unknown-verb error flip to /fleet; `/fleet fleets` (saved/manage) is the saved-fleet picker with `/fleet pods` kept as an alias. - All 15 locale packs: localized values say fleet; the settings goldens follow. `KbCompleteCycleModes` names the modes as Plan → Work → Operate (Act is only a compatibility alias per docs/MODES.md). - `scripts/check-tui-product-vocabulary.sh` now rejects `Pod` in en.json instead of rejecting `fleet` in every pack. - Hotbar id `slash.fleet` is canonical; persisted `slash.pod` normalizes. - Fleet store error prose says fleet. - Docs: PRODUCT.md lists the current role tokens (general, explore, planner, reviewer, implement, test, advisor, custom) and names the old spellings as aliases; docs/FLEET.md uses one role vocabulary; web/lib/content/vocabulary.ts ADVISORY_ROLE is Advisor with consultant/ oracle as the legacy spellings (matches fleet/profile.rs migration). Evidence: sh scripts/check-tui-product-vocabulary.sh -> exit 0 cargo test -p codewhale-config -p codewhale-lane --locked -> 638 passed; 0 failed / 62 passed; 0 failed cargo test -p codewhale-cli --locked -- fleet pod -> 3 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- fleet::store fleet::members fleet::identity -> 24 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- groups::core::fleet localization command_palette hotbar fleet_roster settings widgets fleet::control pod_workers -> 605 passed; 1 failed (the failure is slash_source_matches_command_palette_command_entries, which reads the machine's ~/.claude/skills and finds an `impeccable` skill; it fails identically without this change) cd web && npm test -- lib/content/vocabulary.test.ts -> 11 passed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * chore(tui): clear the six clippy 1.98 errors the base lanes left needless_borrow on provider_identity_for_persistence (five sites) and a collapsible_if in the work-surface mouse path. No behaviour change. * tui(composer): restore double-tap Enter as the send-now gesture While a turn is running, the first bare Enter queues the message (as before) and opens a 500 ms window (`App::DOUBLE_TAP_WINDOW`, the value the removed code in c5c42b7d91 used). A second bare Enter inside that window with an empty composer promotes the just-queued message to a Steer through `attempt_steer_with_queue_fallback` — the same path Ctrl+Enter takes, so there is one steering path. A second Enter with new text is an ordinary queue; Ctrl+Enter still steers immediately; outside a turn Enter is unchanged. `enter_with_double_tap` is the one decision point again (`take_queued_for_double_tap_steer` routes through it), and `submit_disposition_does_not_mutate_the_queue` stays true. The posture bar advertises the gesture while the window is open (`PostureHintEnterAgain`, next commit). Tests (cargo test -p codewhale-tui --lib <filter> --locked): double_tap: test result: ok. 3 passed; 0 failed enter_with: test result: ok. 5 passed; 0 failed submit_disposition: test result: ok. 6 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui(shell): one owner per fact — posture bar, metrics line, no dead hints Design: SHELL-DESIGN-20260901 §2.0 item 3, §2.2, §2.3, §2.3b, §2.11 and the founder's 2026-09-02 redirect (Claude Code's grammar, less always-on information). Under the composer there are exactly two chrome rows in the default state, then the work surface only when it has content: ▶▶ ask (Shift+Tab) · work (Tab) · 2 agents · Esc to interrupt /rc … deepseek-v4 · ctx 61% · $0.42 · ttft 400ms · 40 tok/s · ↓ 1.2K Ctrl+/ help Fact → owner, before → after (composed 80x24 / 120x32 frames, working turn with two sub-agents; "strip" = the work-surface bottom view): fact before after context % info line metrics line cost footer (+ info line when priced) metrics line model info line metrics line provider info line (wide) metrics line (wide) ttft / tok/s / ↓ behind /cost only metrics line repo slug info line (+ idle empty state) launch header / git view (not chrome) branch info line (+ idle empty state) launch header / git view (not chrome) mode footer posture bar permission footer posture bar phase word footer ("sub-agents underway") transcript active row (not chrome) elapsed footer ("1m 15s") roster rows (per agent) agent count indicator row + info "pod 2/2" + "whales 2/4" posture bar ("2 agents") + dock tab + strip header (+ dock tab, strip header — other slice) task/shell count indicator row above the composer posture bar help hint footer keys legend (F1) + info line (Ctrl+/) metrics line (Ctrl+/), from the binding other key hints footer "⌥V:output", compact "? help" none; cycle keys next to the chip they cycle live hint footer "Esc to interrupt" posture bar hint slot ≥80 % microcopy footer right slot posture bar hint slot (outranks the hint) notice / rc footer right slot / — posture bar right slot Dead key hints removed: `F1:keys` / `fn+F1:keys` (Help binding's `footer_chord` is now `Ctrl+/`; `info_help_hint` derives from the binding), compact `? help`, and the `footer_action_hints` family. The mode/permission cycle keys print only when the binding table admits them at the current focus (no `(Tab)` on the launch stage). Row order: composer → posture bar → metrics line → roster/to-do. The #5286 background-work chip above the composer is gone (it repeated the posture bar's counts); `PendingWork` stays as the counts' source. Goldens re-blessed and read: footer_* (posture bar), infoline_startup_*, infoline_work_* (metrics line), settings_* (the settings preview's bottom row); infoline_settings_* deleted with the settings-path segment. Commands run (CARGO_BUILD_BUILD_DIR=…/mega-frame, RUST_MIN_STACK=16777216): cargo check -p codewhale-tui --all-targets clean cargo test -p codewhale-tui --lib infoline --locked test result: ok. 11 passed; 0 failed cargo test -p codewhale-tui --lib tideline_tests test result: ok. 64 passed; 0 failed cargo test -p codewhale-tui --lib one_owner_tests test result: ok. 4 passed; 0 failed cargo test -p codewhale-tui --lib shell_key_routing test result: ok. 13 passed; 0 failed cargo test -p codewhale-tui --lib localization::tests test result: ok. 49 passed; 0 failed cargo test -p codewhale-tui --lib --locked test result: FAILED. 11893 passed; 8 failed (config_panel golden re-blessed after; the other 7: 4 fail on HEAD without this change (fleet rename in flight), tmux clipboard passes alone, none in files this change touches) cargo clippy … -D warnings 6 pre-existing errors, none in this change's hunks (config.rs:2106/2796, apply.rs:759, event_loop.rs:464, session_state.rs:1004, work_surface/input.rs:401) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(launch): checkpoint for overnight takeover — braille mark + kitty tier + Claude-Code launch header compile and pass lib tests; PTY cucumber tests still wait on the old heading Compiles (cargo check --all-targets clean). Lib tests for mark::, underwater::, mouse_ui::, localization:: pass: test result: ok. 120 passed; 0 failed (needs RUST_MIN_STACK=16777216 like scripts/dev-test.sh; the rust_i18n static overflows a 2 MiB test thread with or without this change). Startup goldens re-blessed and read. Clippy is red only in files outside this slice (config.rs, apply.rs, session_state.rs, work_surface/input.rs, and a pre-existing event_loop.rs borrow). Not done: crates/tui/tests/cucumber/{screen_mode_inline_pty, active_composer_pointer_pty,plugin_e2e_acceptance}.rs still wait for "What are we working on?" and press 'w'; they need the new marker ("Codewhale v") and a typed message + Enter to begin the session. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(rail): checkpoint for overnight takeover — dock views compile, 136/137 work_surface tests pass, files/notepad/git views are stubs Foundation for the one bottom dock (founder redirect 2026-09-02): RailPanel is now the eight-view cycle (agents, tasks, background, files, notepad, context, git, price; Pinned folded into tasks), an auto rule opens agents/tasks/background while they have content, explicit picks stick until Esc, and Ctrl+Tab / Ctrl+] (fwd) + Ctrl+Shift+Tab (back) cycle. Context and price views render as rows; files, notepad, git are stubs in views.rs. The classic sidebar line panels and their dead consumers are deleted. Known: agent_rows_show_role_assignment_and_open_the_agent_transcript fails (role_label 'worker' vs 'general'); role derivation is untouched here and the failure is believed to predate this work — unverified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(operate): checkpoint for overnight takeover — auto-goal + contract land; one Operate approval test needs a goal-complete mock Operate now turns a non-trivial prompt into the goal through the same GoalState::create path as explicit_goal_directive, appends the Operate contract once as a user-role runtime message (append-only history, not the prefix), shows the Operate goal receipt, and carries the new mode copy in all 15 locale packs plus docs/MODES.md. Compiles. Passing: goal (134), prompts (133, incl. every_mode_shares_one_prompt_per_host), localization (49), runtime_handoff (14), session_peek (15), history_cells (2), both new engine tests. Known failing: core::engine::tests::operate_model_shell_uses_normal_approval_and_workspace_sandbox — its mocked model never reports the auto-set goal complete, so the turn re-prompts to max_steps (wiremock expect(1) sees 199). Six clippy needless_borrow/collapsible_if hits pre-exist on the branch base. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(fleet): checkpoint for overnight takeover — #5815 review findings 1-9 fixed, compiles, fleet tests green Findings against the fleet-as-models work (verified against the current tree, then fixed): 1. `toggle_fleet_model` decides presence by member rows, not the projected role list (a role-less row projects to no role, so the old `all(== "operator")` was vacuously true). Regression test `toggle_removes_a_role_less_member_row` fails on the previous commit ("got Unchanged { … operator route … }") and passes now. 2. `selected_or_default` loads an existing personal `My fleet` instead of overwriting it and never writes or selects before the add succeeds; `FleetModelChange::Added` carries `created_fleet` + `selected_fleet`. 3. `fleet_models` returns `Result<Vec<_>, FleetStoreError>`: a broken explicit selection is surfaced in `/fleet models`, `/models`, and the picker's ⇧F instead of reading as "session model only". 4. `add_fleet_model` dedupes roles (case-insensitive) and returns `Unchanged` without touching the file when every role is present (test compares bytes and mtime). 5. `App.config` startup snapshot removed. `/fleet add|remove` now return `AppAction::FleetAddModel|FleetRemoveModel`; the UI arm validates the provider against the live `Config` (`fleet_provider_rejection`, `fleet_catalog_rejection`, re-exported from `commands`). 6. ⇧F applies the same provider gate as `/fleet add`. 7. One roster path: `sync_fleet_roster` (extracted from the FleetStoreChanged arm) plus `App::fleet_roster_stale`, flushed once per event-loop iteration; `/fleet add|remove`, ⇧F, and every UI-side auto-enroll site set it (`auto_enroll_fleet_model` now returns bool). 8. ⇧F receipts go through `push_status_toast` (Success/Info, 6 s) and `set_sticky_status` (Error); no new `status_message` writes. 9. All new fleet prose is `tr(locale, MessageId::Fleet…)` (27 keys, translated in all 15 packs); `FleetModelError` is typed with a localized `message(locale)`. 10. No stale "`a` in /models" doc comment exists in the current tree. Also re-blessed `config_panel_{80x24,120x32}` goldens (the Config tab label says Fleet); the diff is that one label. Evidence (this tree): cargo check -p codewhale-tui --all-targets --locked -> Finished cargo test -p codewhale-tui --lib --locked -- fleet::members groups::core::fleet model_picker format_helpers fleet_roster localization golden hotbar command_palette fleet::store -> 257 passed; 1 failed (slash_source_matches_command_palette_ command_entries: reads ~/.claude/skills and finds `impeccable`; fails identically on main in this environment) cargo clippy … -D warnings (CI flags) -> the only remaining error is crates/tui/src/tui/work_surface/input.rs:401 collapsible_if, which belongs to the work_surface lane and predates this commit cargo fmt --all -- --check -> clean sh scripts/check-tui-product-vocabulary.sh -> exit 0 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * feat(tui): launch card, canonical role vocabulary, DashScope descriptor, test fixes - Launch is now our own card take (founder, 2026-09-02): thin top line ⑂ branch path; centred bordered card with the whale mark, Codewhale + version, one true announcement (no-model warning / MCP news), and the menu New worktree / Resume session / Changelog / Quit with real chords right-aligned; Enter runs the highlighted entry, Up/Down move it, and typing goes straight to the composer. The card dissolves on the first keystroke or command (≤240ms, instant under reduced motion); the working screen then shows ⑂ branch path + ⋮ MCP n/m, the session_start receipt, and the posture bar + metrics line (hidden while the card is up). The composer's bottom rule carries model (effort) · permission — the route's one launch reading. - Role vocabulary: fixtures and the stopship fleet/workflow now use the canonical tokens (explore/implement/reviewer/test); the workflow JS wire accepts canonical spellings with the pre-rename ones as aliases (AgentType serde rename+alias, serialized form is canonical). - Alibaba Model Studio (DashScope) joins the data-driven descriptor table: international compatible-mode endpoint, DASHSCOPE_API_KEY, live /v1/models as the Qwen model authority (never a compiled id). - Tests: role-keyed gate fixtures moved to canonical tokens; the operate model-shell test now seals the goal through the deferred update_goal tool (deferral retry included) instead of pausing blindly; the slash-source hotbar test isolates HOME; ⚠ and ⋮ gained ASCII fallbacks; launch goldens re-blessed for the card. * feat(tui): retire Pod from copy; canonical workflow fixture; gate clean-up - Pod literal sweep across fleet views, worker runtime, sub-agent tool, managed API, and command groups: user-facing copy now says Fleet (founder vocabulary decision; /fleet canonical, /pod and 'codewhale pod' stay as compatibility aliases). Roster tests that encoded the retired Pod-public/Fleet-internal split now assert the public Fleet vocabulary. - workflows/stopship + fleets/stopship use canonical role names (explore/implement/reviewer/test); the workflow crate's own stopship tests and required-roles list follow. - Operate mode-picker hint shortened to fit 80 columns in every locale. - Cucumber PTY launch flows: wait for the launch card, type the first prompt and press Enter; the live shell is proven by the launch stage's top line disappearing and the metrics line's ctx reading (the interrupt hint needs a live turn, which an offline route never starts). The stopship acceptance feature expects the canonical /fleet help copy. - CHANGELOG receipts synced; DESIGN.md shell direction records the card, posture bar + metrics line, and the bottom view cycle. * test(cucumber): launch-card PTY contract fixes - The launch-card wait uses the menu's New worktree entry — unique to the card; the bare wordmark also matches onboarding copy. - The live-shell proof is the launch stage's top line disappearing plus the metrics line's ctx reading; the interrupt hint needs a live turn, which an offline route never starts, and the help hint sheds first at the 40-column floor by design (SHELL-DESIGN-20260901 §2.2). - The pointer-submit queue proof takes the offline onboarding seed into account: the receipt toast proves the gesture, and the queue count grows by exactly one. * docs(readme): restore the canonical product screenshot the web contract pins The brand header redesign dropped the assets/screenshot.webp embed; the web public-surface contract pins the README and the website to one canonical optimized screenshot (byte-identical, 1562x1256 lossless VP8L). Re-embed it. * test: platform-robust pointer-submit wait and cap-warning diagnostics - The pointer queue proof accepts either the transient receipt toast or the queue-count increment: toast timing differs across runners, and a 20 s wait missed a toast the queue dump proved had fired. - The context-cap posture test dumps the drawn rows when the warning count misses, instead of a bare 0 != 1, so a platform-specific shed (the hint sheds first when the left run exceeds its budget) is visible in CI. * test: fix the linux-only context-cap shed; bounded pointer-click retry - The context-cap posture test drew at 100 columns, where a backend-less platform (linux CI paints 'files: workspace (unenforced)') sheds the cap hint first, so the warning count read 0. Draw at 140 columns, where the hint survives with the notice present; verified locally. - The pointer queue proof retries the [↑] click once, re-finding the affordance first: under runner load a redraw can shift cells between the find and the click, so the first SGR gesture lands nowhere. * fix(gates): tool-catalog budget covers the fleet rename; readme stamps; pointer baseline - The Pod->Fleet sweep grew every mode's tool-schema surface by 58 bytes (+14 tokens). The receipts are re-measured and the one-way ceilings in scripts/runtime-contract-budget.json are raised to them as the explicit maintainer decision the gate asks for (the rename is the founder's 2026-09-01 vocabulary call). - The README screenshot embed changed README.md; the 18 translated READMEs re-stamp (the embed is language-neutral HTML - no prose changed, so no retranslation was needed). - The pointer queue baseline is captured while the composer is empty: the pending preview row hides while a draft sits in the composer, so the pre-click depth read None and the growth proof could not fire. * test: re-click then keep polling until the deadline The qa_harness Instant wrapper does not implement Div, and the retry's single read raced the app processing the second gesture: poll to the full deadline, re-click once at the half-way point. * test: pointer queue diagnostics (baseline/expected/last-seen) in the failure output * test: pointer poll keeps per-iteration state only (unused-assignment gate) * fix: Copilot review findings — planner wire spelling and Advisor copy - workflow::AgentType::Plan serializes as the canonical 'planner' ('plan'/'awaiter' stay accepted aliases), matching the FleetRole vocabulary the mega PR declares. - Web: the vocabulary docs metadata, the vocabulary module header, and the docs-map topic description say Advisor (the public advisory term) instead of the retired Consultant spelling. - Polish home dictionary: restore 'Podwodna powłoka terminala' — the fleet-vocabulary sweep had merged 'Fleet' into the compound word 'Podwodna' (underwater), producing the non-word 'fleetwodna'. * test: pointer proof accepts preview-appears when no baseline count is painted * test: the tolerant preview-appears proof (the arm the last commit missed) --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 3 天前 | |
refactor(tui): neutralize turn loop name (#5443) Signed-off-by: Hunter Bown <hmbown@gmail.com> | 18 天前 | |
feat(tui): live plugin CTA and model-visible recommendations Keep the send-time toast. A Grok-style keyword matcher (word boundaries, domains, longest keyword) drives a one-line composer CTA while you type: Install {name} plugin? Review runs the existing /plugin trust, marketplace-install, or /plugin install path and never auto-installs. Dismiss stays dismissed for that name this session; already-active plugins stay hidden. Matching idle or catalog plugins also append a bounded <recommended_plugins> user-turn block on send (not the pinned system prefix). request_plugin_install surfaces that review for the human and does not mutate disk. | 8 天前 | |
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> | 5 天前 | |
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> | 5 天前 | |
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> | 5 天前 | |
feat(plugins): enforce reviewed bundle activation Build one deterministic Codewhale-owned bundle inventory with versioned manifests, contained content hashing, separate trust and enablement receipts, and fail-closed atomic state. Activate only namespaced Skills and MCP through their existing engines, initialize the registry consistently across launch modes, preserve legacy executable tools as a separate surface, and document the bounded v0.9.1 lifecycle. Refs #4399, #3916, #3917. Builds on the original plugin manifest, discovery, CLI, and MCP foundation from pkeging in #3708, #3709, and #3710. Co-authored-by: pkeging <237035657+pkeging@users.noreply.github.com> Signed-off-by: Hunter B <hmbown@gmail.com> | 1 个月前 | |
fix(release): promote tested v0.9.11 nonbenchmark candidate Promotes the fully gated non-benchmark candidate while preserving the benchmark tree exactly from the prior release-PR head. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 15 天前 | |
docs: Codewhale Agent identity map across surfaces One product identity, many transports: the GitHub review surface (codewhale-agent[bot], App-gated), the AUTHOR_MAP co-author identity, and the chat channels (Telegram live in CWC, others following) — all bound to one Codewhale membership, all I/O around the one Engine::run_turn, approvals routed as permission decisions, everything audited, every surface free. No-Issue: Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 8 天前 | |
feat: Codewhale 0.9.12 shell, brand, fleet, and Operate (mega) (#5826) * feat(fleet): your fleet is the models you added, and it comes first Design MODEL-ROUTING-CATALOG-20260901 §10, slice F1. A fleet model is a Pod member: the selected Pod file's operator route plus every member row that pins an exact provider + model; the roles a model fills are the member rows that pin it. No second store. - crate::fleet::members: fleet_models / add_fleet_model / remove_fleet_model / toggle_fleet_model + change_receipt; Config::fleet_members(workspace) is the read seam for the operator-awareness slice (F2). - /pod models | add <provider> <model> [role…] | remove <provider> <model> (also via the /fleet alias). A model the configured provider does not serve is rejected; the first add creates and selects a user-global Pod named 'My fleet'. - /model picker: ⇧F adds or removes the row's exact route; fleet models lead the list labelled 'fleet · <roles>', ahead of ⇧P pins and providers. - /models prints the fleet before the provider list ('Your fleet is the session model only' when empty). - PickerActionFleet message in all 15 locales; docs/FLEET.md 'Your fleet as models'. Tests: scripts/dev-test.sh tui fleet::members groups::core::fleet model_picker format_helpers — Summary 37 tests run: 37 passed, 11834 skipped. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(fleet): pass slugify by name (clippy redundant_closure) cargo clippy -p codewhale-tui --all-targets -- -D warnings -A clippy::too_many_arguments -A clippy::uninlined_format_args -A clippy::unnecessary_map_or: no findings. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): review fixes for fleet toggle and /pod add provider validation\n\n- Reject unconfigured provider ids in "/pod add" before writing, reusing\n the existing provider_is_configured_for_active predicate and custom\n provider table checks.\n- Add App.config snapshot so commands can consult the loaded config.\n- Update the stale DEFAULT_FLEET_NAME doc comment to mention ⇧F.\n- Sync crates/tui/CHANGELOG.md. * style: cargo fmt * fix(web): align react with react-dom 19.2.8 to unbreak npm ci Dependabot #5801 bumped react-dom to 19.2.8, whose peer range requires react 19.2.8; the lockfile still resolved react 19.2.6, so 'npm ci' in web/ failed ERESOLVE on main and on every branch that merged it (Lint & Type Check red). Align react to 19.2.8; install verified clean. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * brand: trace supplied whale assets Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: align icon ombre and generated tokens Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: use white icon tile Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: deepen ombre light stop Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: wordmark takes the blue ombre Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: recover from image-input rejections by non-vision routes Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: localize image rejection recovery Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * chore: format 0.9.12 mega branch Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Redesign Fleet role labels and agent cards * feat(tui): launch hero as wordmark + small surfacing mark Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * design(tui): retune whale palette to codewhale navy / ombre sky Field, chrome, panel, plate and raised surfaces move onto the brand navy (#070C1D → #142352 → #1A2C63); interaction blue becomes the ombre sky #6AA6DC, light-mode action the ombre cobalt #1535B2; ice/cyan/border/tool tints follow. web/app/tokens.css regenerated via scripts/export-design-tokens.py. Co-Authored-By: Hunter Bown <hmbown@gmail.com> * test(tui): re-bless ink goldens for navy palette Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Space Mono wordmark, quiet layout refresh, fleet vocabulary in site + docs Space Mono (OFL) outlined wordmark rebuilt via scripts/build-wordmark.py, wired as --font-display through next/font/google; body stays IBM Plex Sans, code stays JetBrains Mono. Nav loses the issue strip, strapline, Discord badge and second filled CTA; home loses the ticker, seals and tilt figure; docs shell hero collapses to a one-line band; footer uses the inverted wordmark. Public noun is fleet (/fleet, codewhale fleet, /docs/fleet canonical; /pod, codewhale pod, /docs/pod remain compatibility aliases) across docs/, site dictionaries, vocabulary contract and public-surface facts. No-Issue: 0.9.12 website lane * brand: keep the traced wordmark; drop Space Mono outline build * web: IBM Plex Sans Condensed as display face * brand: Plex Sans Condensed wordmark; nav mark; drop fabricated home demos; AA meta text * feat(tui): bottom dock tabs — clickable panel switch + close Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Fix Fleet role migration verification * fix(tui): dock keys yield Tab to mode/permission cycles Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Impeccable polish — type floors, heading outline, docs measure; add PRODUCT.md/DESIGN.md * Resolve canonical Fleet roles to legacy members * web: flat hero — drop cyan glow/gradients/shadow, muted eyebrows * design: PRODUCT.md/DESIGN.md at repo root — shell direction, bottom dock, anti-slop rules, 0.9.12 tokens * Auto-enroll used models into the Fleet * brand: keep the founder's wordmark rasters as the source of truth The web lane replaced brand/wordmark0901.png and brand/wordmarkinverted.png with Plex Sans Condensed renders. The founder-supplied PNGs are the brand source; the SVGs are re-traced from them in a following commit. * tui(mark): the launch mark has one rung The hero now paints the small mark over the wordmark, so the medium and large rungs and the for_area ladder have no consumer and fail the dead-code lint. Remove them rather than allow them. * brand: trace the founder's wordmark to SVG brand/wordmark.svg and wordmark-inverted.svg were an IBM Plex Sans Condensed text render; the founder's wordmark is the rounded monoline in brand/wordmark0901.png. scripts/brand/trace-brand.py now traces that PNG (magick threshold 60% + trim, potrace -s --flat -t 20 -O 0.4 -a 1.2), folds potrace's transform into one compact path in a tight 1874x264 viewBox, and writes the navy #142352 and white colourways from the same geometry. The Plex builder scripts/build-wordmark.py is gone with it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: derive icons and OG image from the traced mark app/icon.svg is now the white whale on the #142352 rounded tile as on the founder's sheet; favicon.ico (48/32/16), apple-icon.png, icon-192.png and icon-512.png are rasterised from it by scripts/brand/trace-brand.py, and the manifest colours are the same navy. The social card keeps the navy ground, white mark and traced wordmark and restores the identity phrase the page-meta contract expects. The nav sits on the dark field on every route, so it renders the inline Whale (white brand ink) and the inverted wordmark instead of a prefers-color-scheme picture pair; the wordmark box uses object-fit so the ~7.1:1 trace scales inside the compact nav instead of squashing. Exploration rasters web/public/brand/codewhale-mark-*.png and their web/brand/mark tile sources had no consumers and are removed; codewhale-mark.png stays (public-auth-routes pins its hash). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: map stray hard-coded colours to navy tokens globals.css carried a handful of literal navy-family greys, ice hairlines, seafoam borders and a cyan glow beside the generated --whale-* tokens. Each now reads the token it was approximating (whale-bg/chrome/panel, whale-ice, whale-accent-secondary, whale-action, whale-cyan, whale-text-dim), and the docs light sheet inks the mark in the brand navy via --whale-composer (#142352). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: inventory WHALE_* tokens before the one-name-per-colour collapse Shell design §2.6 (SHELL-DESIGN-20260901) measured "58 WHALE_* symbols; one colour under five names; 5 dead tokens". Receipt before touching anything, generated from crates/tui/src/palette/tokens.rs. "uses" is the whole-word count across crates/ excluding the const's own definition and `use`/`pub use` lines (wrapper consts inside tokens.rs count). name value alias-of dead uses WHALE_BG_RGB (7, 12, 29) 3 WHALE_CHROME_RGB (12, 21, 49) 1 WHALE_PANEL_RGB (16, 28, 64) 3 WHALE_COMPOSER_RGB (20, 35, 82) 3 WHALE_ELEVATED_RGB (26, 44, 99) 4 WHALE_SELECTION_RGB (30, 60, 143) 3 WHALE_TEXT_BODY_RGB (246, 242, 232) 10 WHALE_TEXT_SOFT_RGB (182, 192, 212) 4 WHALE_TEXT_MUTED_RGB (147, 160, 184) 3 WHALE_TEXT_HINT_RGB (138, 153, 179) 3 WHALE_TEXT_DIM_RGB (105, 119, 145) yes 0 WHALE_ACTION_RGB (106, 166, 220) 6 WHALE_COBALT_RGB (21, 53, 178) yes 0 (web: --whale-cobalt x3) WHALE_ICE_RGB (221, 238, 249) yes 0 (web: --whale-ice, rustRgb("WHALE_ICE")) WHALE_CYAN_RGB (120, 188, 232) 2 WHALE_ACCENT_SECONDARY_RGB (79, 209, 197) 11 WHALE_BRAND_ORANGE_RGB (255, 138, 61) 1 WHALE_BRAND_MAGENTA_RGB (240, 78, 184) 1 WHALE_HUMAN_RGB (246, 196, 83) 5 WHALE_ACCENT_PRIMARY_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 8 WHALE_WORKING_GREEN_RGB (155, 214, 111) 5 WHALE_ACCENT_ACTION_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB yes 0 WHALE_ERROR_RGB (255, 134, 178) 9 WHALE_ERROR_HOVER_RGB (255, 156, 194) 3 WHALE_ERROR_SURFACE_RGB (43, 21, 34) 6 WHALE_ERROR_BORDER_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB 3 WHALE_ERROR_TEXT_RGB (255, 219, 232) 3 WHALE_WARNING_RGB (255, 122, 89) 4 WHALE_SUCCESS_RGB = WHALE_WORKING_GREEN_RGB WHALE_WORKING_GREEN_RGB 9 WHALE_INFO_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 17 WHALE_BORDER_RGB (42, 63, 114) 1 WHALE_REASONING_TEXT_RGB (224, 153, 72) 13 WHALE_REASONING_SURFACE_RGB (42, 34, 24) 3 WHALE_REASONING_TINT_RGB (22, 36, 74) 7 WHALE_DIFF_ADDED_RGB (87, 199, 133) 3 WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB yes 0 WHALE_DIFF_ADDED_BG_RGB (18, 42, 34) 3 WHALE_DIFF_DELETED_BG_RGB (52, 24, 39) 3 WHALE_MODE_AGENT_RGB (126, 180, 232) 4 (via MODE_AGENT: 13) WHALE_MODE_YOLO_RGB (255, 112, 160) 4 (via MODE_YOLO: 13) WHALE_MODE_PLAN_RGB (185, 220, 236) 4 (via MODE_PLAN: 13) WHALE_MODE_OPERATE_RGB (173, 136, 255) 4 (via MODE_OPERATE: 14) WHALE_TOOL_LIVE_RGB = WHALE_ACCENT_SECONDARY_RGB 3 (via ACCENT_TOOL_LIVE: 5) WHALE_TOOL_ISSUE_RGB = WHALE_ERROR_RGB 3 (via ACCENT_TOOL_ISSUE: 5) WHALE_TOOL_OUTPUT_RGB = WHALE_TEXT_SOFT_RGB 3 (via TEXT_TOOL_OUTPUT: 13) WHALE_TOOL_SURFACE_RGB (15, 26, 58) 3 (via SURFACE_TOOL: 5) WHALE_TOOL_ACTIVE_RGB (24, 44, 94) 3 (via SURFACE_TOOL_ACTIVE: 9) WHALE_ACCENT_PRIMARY Color(WHALE_ACCENT_PRIMARY_RGB) -> WHALE_ACTION 9 WHALE_ACTION Color(WHALE_ACTION_RGB) 85 WHALE_LIVE Color(WHALE_ACCENT_SECONDARY_RGB) 17 WHALE_HUMAN Color(WHALE_HUMAN_RGB) 41 WHALE_INFO Color(WHALE_INFO_RGB) -> WHALE_ACTION 105 WHALE_BG Color(WHALE_BG_RGB) 96 WHALE_CHROME Color(WHALE_CHROME_RGB) 5 WHALE_PANEL Color(WHALE_PANEL_RGB) 15 WHALE_COMPOSER Color(WHALE_COMPOSER_RGB) 5 WHALE_ERROR Color(WHALE_ERROR_RGB) 35 57 WHALE_* consts. Pure aliases (9): ACCENT_PRIMARY_RGB, ACCENT_ACTION_RGB, ERROR_BORDER_RGB, SUCCESS_RGB, INFO_RGB, DIFF_DELETED_RGB, TOOL_LIVE_RGB, TOOL_ISSUE_RGB, TOOL_OUTPUT_RGB. #[expect(dead_code)] (5): TEXT_DIM_RGB, COBALT_RGB, ICE_RGB, ACCENT_ACTION_RGB, DIFF_DELETED_RGB. Non-WHALE aliases of the same blue in tokens.rs: STATUS_INFO (8 uses), ACCENT_PRIMARY (dead, 0). One colour, #6AA6DC, under seven symbols: WHALE_ACTION(_RGB), WHALE_INFO(_RGB), WHALE_ACCENT_PRIMARY(_RGB), WHALE_ACCENT_ACTION_RGB, STATUS_INFO, ACCENT_PRIMARY — 225 call sites. Script: python3 over tokens.rs + grep -rnw crates; kept out of scripts/ (one-off receipt, the numbers live here). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: one name per colour — collapse WHALE_INFO / WHALE_ACCENT_PRIMARY into WHALE_ACTION Shell design §2.6: "`WHALE_INFO`, `WHALE_ACTION`, `WHALE_ACCENT_PRIMARY` and their `_RGB` twins are one colour. Collapse to `WHALE_ACTION`." Mechanical rename across crates/ (word-boundary sed, no value changes): WHALE_INFO, WHALE_INFO_RGB -> WHALE_ACTION, WHALE_ACTION_RGB WHALE_ACCENT_PRIMARY(_RGB) -> WHALE_ACTION(_RGB) palette::STATUS_INFO -> palette::WHALE_ACTION WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY (dead aliases) -> deleted The `STATUS_INFO` static in commands/groups/config is an unrelated CommandInfo and is untouched. Where two names met in one predicate (adapt.rs light/solarized/community remaps, grayscale text-soft bucket, SemanticForegroundRole::Action) the duplicate disjuncts are dropped; `use` lists deduped; the "primary accent aligns with action" test collapses to its one live assertion (action blue != human gold). The Blue Stage doc comment moves onto WHALE_ACTION_RGB. `palette::grammar` untouched: it reads UiTheme slots, never these consts. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo clippy -p codewhale-tui --all-targets --all-features --locked -- -D warnings (CI allow-list) -> clean cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed RUST_MIN_STACK=67108864 cargo test -p codewhale-tui --lib startup_ink --locked -> test result: ok. 1 passed; 0 failed (ink goldens unchanged) cargo test -p codewhale-tui --lib --locked -- menu_style cursor_accent color_compat -> test result: ok. 36 passed; 0 failed Pre-existing, not from this diff (reproduced on the stashed tree): tui::command_palette tests, feat012_ac1 and the startup_ink golden overflow the default test-thread stack in a debug build; they pass with RUST_MIN_STACK=64MiB. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: delete the dead whale tokens Shell design §2.6: "delete the five dead tokens". Two of the five went with the alias collapse (WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY); this removes the rest that have no consumer in crates/ and no web consumer: WHALE_TEXT_DIM_RGB (105,119,145) 0 uses, no --whale-text-dim on the site WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB 0 uses, no --whale-diff-deleted ACCENT_SECONDARY Color(WHALE_ACCENT_SECONDARY_RGB) 0 uses (TEXT_ACCENT/WHALE_LIVE carry it) STATUS_NEUTRAL = TEXT_MUTED 0 uses Kept, with a comment saying why the `#[expect(dead_code)]` is honest: WHALE_COBALT_RGB and WHALE_ICE_RGB have no TUI consumer but the site reads them through the token export (`--whale-cobalt` x3, `--whale-ice` and `rustRgb("WHALE_ICE")` in web/lib/blue-stage-contract.test.ts). Mode and tool-surface `_RGB` tuples stay: each is consumed through its Color wrapper (MODE_AGENT/YOLO/PLAN/OPERATE 13-14 call sites each, themes.rs + color_compat.rs; SURFACE_TOOL 5, SURFACE_TOOL_ACTIVE 9, ACCENT_TOOL_LIVE 5, ACCENT_TOOL_ISSUE 5, TEXT_TOOL_OUTPUT 13). The §1 "12 tokens with zero consumers" counted the tuples, not their wrappers. Evidence: cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings; cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: regenerate tokens.css after the whale token collapse scripts/export-design-tokens.py (never hand-edited). Ten lines gone: --whale-accent-primary(-rgb), --whale-accent-action(-rgb), --whale-info(-rgb), --whale-text-dim(-rgb), --whale-diff-deleted(-rgb). No site stylesheet or component consumed any of them (grep -rn "\-\-whale-" web/app web/components web/lib); the only reference was the alias-chain example in web/lib/whale-tokens.ts's doc comment, now `--whale-success` -> `--whale-working-green` -> `#9bd66f` (the old example also quoted a hex that stopped being true a retune ago). Evidence: cd web && python3 ../scripts/export-design-tokens.py --check (CI: npm run check:tokens) -> design tokens up to date (1 file(s), 42 tokens) vitest run lib/blue-stage-contract lib/docs-theme-contract -> Test Files 2 passed (2) / Tests 6 passed (6) (vitest ran against the main checkout's node_modules via a temporary symlink; this worktree has none installed.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * docs(design): the status-bar grammar names the one blue token STATUS_BAR_COLOR_GRAMMAR.md never named a collapsed token, so this is the one sentence it needed: the Identity blue is `WHALE_ACTION`, its former aliases (`WHALE_INFO`, `WHALE_ACCENT_PRIMARY`, `STATUS_INFO`) are gone, and the whale theme's `info` / `accent_primary` slots both hold it. No other document in the repo named them (grep over *.md, *.ts, *.tsx, *.css, *.py, *.toml, *.yml, *.json outside node_modules); the root DESIGN.md already speaks in CSS names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: the field follows the terminal-owned shell; `underwater` aliases deepsea Shell design §2.0 decision 1 (founder: "We aren't supposed to be using a blue background anymore"): ground is the terminal's; the navy field is painted only under the opt-in deepsea column. What was already true, verified before changing anything: - Settings::default().theme is "terminal" (settings.rs:103). - The whale pair (UI_THEME / LIGHT_UI_THEME) ends in `.with_terminal_native_shell()`: surface, panel, composer, header and footer are `Color::Reset`, pinned by `whale_pair_flat_shells_are_terminal_native_without_erasing_semantic_surfaces`. - The ink goldens' legend reads `a reset on reset`. - OceanTreatment::Flat is the default; Deepsea repaints Reset cells through OceanRamp::for_theme, which matches the whale pair by name + Reset shell. The reviewer's citations (tokens.rs:6/:250/:465) are the token definitions deepsea and the semantic surfaces still need, not the theme. What was not true: ~90 direct `bg(palette::WHALE_BG)` paints in pickers, overlays and full-screen views (provider_picker 14, views/mod.rs 11, user_input, live_transcript, help, session/file/model pickers ...) bypass the theme, and `adapt_bg_for_theme` only remapped them for `theme_remap_active` presets. On the whale theme they laid navy patches over the terminal ground. Rung 2 fix, one rule in palette/adapt.rs: the field (`WHALE_BG` / `BACKGROUND_DARK`) always follows `ui.surface_bg` — Reset on the whale pair, the user's `background_color` override when set, the preset surface elsewhere. Panels, selection, elevation, error and diff surfaces are untouched; no widget file changes. `underwater` is now an accepted alias of `deepsea` in settings.rs (normalize + `set`), OceanTreatment::parse and the config_ui serde enum. Tests extended in place; the color_compat light test now expects the Reset shell it already had for theme consumers. DESIGN.md "Field" says the TUI ground is the terminal's own background and the navy field is deepsea-only. Contrast, all whale text/accent tokens on #000, #1e1e1e (VS Code), #282c34 (One Dark), #002b36 (Solarized dark), #300a24 (Ubuntu), #0d1117 (GitHub dark), #282a36 (Dracula): body 12.5-18.8:1, soft 7.7-11.5, muted 5.3-8.0, hint 4.9-7.3 (floor 3:1), action 5.4-8.1, human 8.6-12.9, live 7.5-11.3, error 6.2-9.3, warning 5.5-8.2, green 8.2-12.2, reasoning 5.9-8.8. Only `border` (#2A3F72) is low, 1.4-2.1:1: a non-text hairline. No token value changed. Seen, tmux 80x24 PTY, TERM=xterm-256color COLORTERM=truecolor, hermetic HOME, debug build, counting `48;2;R;G;B` background sequences: default (Terminal theme): startup, /theme picker, Help — no painted background before or after (picker shows only accent swatches). Blue Stage selected via T/Down/Enter, then F1 Help: before: 15 x `48;2;7;12;29` (WHALE_BG) + 1 x selection row after: 1 x `48;2;30;60;143` (selection row only) Startup stage on Blue Stage: none, before and after. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens, RUST_MIN_STACK=16 MiB as CI): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo test -p codewhale-tui --lib --locked -- color_compat palette::tests:: ocean:: ocean_treatment live_transcript views::tests startup_ink --skip command_palette -> test result: ok. 238 passed; 0 failed cargo test -p codewhale-tui --lib --locked (full) -> test result: FAILED. 11901 passed; 7 failed; 13 ignored 1 was this change (color_compat light test, updated above); the other 6 are role-name / slash-list assertions from other lanes on this branch (scout<->explore, worker<->general, slash.impeccable) and untouched. Ink goldens unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tests(palette_audit): re-pin whale roles to the retuned palette `whale_roles_are_pinned_and_non_colliding` still pinned the pre-navy values (WHALE_BG (3,7,13), ACTION (106,174,242), ...) and failed on this branch before the token slice touched anything. Pins now match tokens.rs; no colour value changes. cargo test -p codewhale-tui --test integration --locked palette_audit -> test result: ok. 3 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui/cli/web: fleet is the public product term; /pod, codewhale pod stay aliases Founder decision 2026-09-01: "fleet" is the customer-facing name for the assembled model team and "Pod" is retired from product copy. `/fleet` is the canonical slash command and `codewhale fleet` the canonical CLI verb; `/pod`, `codewhale pod`, `loadout`, and `party` remain parser aliases. Storage keys, the ledger file name, config tables, protocol identifiers, and MessageId variant names keep their current spelling. - CommandInfo name/aliases/usage, help text, and the unknown-verb error flip to /fleet; `/fleet fleets` (saved/manage) is the saved-fleet picker with `/fleet pods` kept as an alias. - All 15 locale packs: localized values say fleet; the settings goldens follow. `KbCompleteCycleModes` names the modes as Plan → Work → Operate (Act is only a compatibility alias per docs/MODES.md). - `scripts/check-tui-product-vocabulary.sh` now rejects `Pod` in en.json instead of rejecting `fleet` in every pack. - Hotbar id `slash.fleet` is canonical; persisted `slash.pod` normalizes. - Fleet store error prose says fleet. - Docs: PRODUCT.md lists the current role tokens (general, explore, planner, reviewer, implement, test, advisor, custom) and names the old spellings as aliases; docs/FLEET.md uses one role vocabulary; web/lib/content/vocabulary.ts ADVISORY_ROLE is Advisor with consultant/ oracle as the legacy spellings (matches fleet/profile.rs migration). Evidence: sh scripts/check-tui-product-vocabulary.sh -> exit 0 cargo test -p codewhale-config -p codewhale-lane --locked -> 638 passed; 0 failed / 62 passed; 0 failed cargo test -p codewhale-cli --locked -- fleet pod -> 3 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- fleet::store fleet::members fleet::identity -> 24 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- groups::core::fleet localization command_palette hotbar fleet_roster settings widgets fleet::control pod_workers -> 605 passed; 1 failed (the failure is slash_source_matches_command_palette_command_entries, which reads the machine's ~/.claude/skills and finds an `impeccable` skill; it fails identically without this change) cd web && npm test -- lib/content/vocabulary.test.ts -> 11 passed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * chore(tui): clear the six clippy 1.98 errors the base lanes left needless_borrow on provider_identity_for_persistence (five sites) and a collapsible_if in the work-surface mouse path. No behaviour change. * tui(composer): restore double-tap Enter as the send-now gesture While a turn is running, the first bare Enter queues the message (as before) and opens a 500 ms window (`App::DOUBLE_TAP_WINDOW`, the value the removed code in c5c42b7d91 used). A second bare Enter inside that window with an empty composer promotes the just-queued message to a Steer through `attempt_steer_with_queue_fallback` — the same path Ctrl+Enter takes, so there is one steering path. A second Enter with new text is an ordinary queue; Ctrl+Enter still steers immediately; outside a turn Enter is unchanged. `enter_with_double_tap` is the one decision point again (`take_queued_for_double_tap_steer` routes through it), and `submit_disposition_does_not_mutate_the_queue` stays true. The posture bar advertises the gesture while the window is open (`PostureHintEnterAgain`, next commit). Tests (cargo test -p codewhale-tui --lib <filter> --locked): double_tap: test result: ok. 3 passed; 0 failed enter_with: test result: ok. 5 passed; 0 failed submit_disposition: test result: ok. 6 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui(shell): one owner per fact — posture bar, metrics line, no dead hints Design: SHELL-DESIGN-20260901 §2.0 item 3, §2.2, §2.3, §2.3b, §2.11 and the founder's 2026-09-02 redirect (Claude Code's grammar, less always-on information). Under the composer there are exactly two chrome rows in the default state, then the work surface only when it has content: ▶▶ ask (Shift+Tab) · work (Tab) · 2 agents · Esc to interrupt /rc … deepseek-v4 · ctx 61% · $0.42 · ttft 400ms · 40 tok/s · ↓ 1.2K Ctrl+/ help Fact → owner, before → after (composed 80x24 / 120x32 frames, working turn with two sub-agents; "strip" = the work-surface bottom view): fact before after context % info line metrics line cost footer (+ info line when priced) metrics line model info line metrics line provider info line (wide) metrics line (wide) ttft / tok/s / ↓ behind /cost only metrics line repo slug info line (+ idle empty state) launch header / git view (not chrome) branch info line (+ idle empty state) launch header / git view (not chrome) mode footer posture bar permission footer posture bar phase word footer ("sub-agents underway") transcript active row (not chrome) elapsed footer ("1m 15s") roster rows (per agent) agent count indicator row + info "pod 2/2" + "whales 2/4" posture bar ("2 agents") + dock tab + strip header (+ dock tab, strip header — other slice) task/shell count indicator row above the composer posture bar help hint footer keys legend (F1) + info line (Ctrl+/) metrics line (Ctrl+/), from the binding other key hints footer "⌥V:output", compact "? help" none; cycle keys next to the chip they cycle live hint footer "Esc to interrupt" posture bar hint slot ≥80 % microcopy footer right slot posture bar hint slot (outranks the hint) notice / rc footer right slot / — posture bar right slot Dead key hints removed: `F1:keys` / `fn+F1:keys` (Help binding's `footer_chord` is now `Ctrl+/`; `info_help_hint` derives from the binding), compact `? help`, and the `footer_action_hints` family. The mode/permission cycle keys print only when the binding table admits them at the current focus (no `(Tab)` on the launch stage). Row order: composer → posture bar → metrics line → roster/to-do. The #5286 background-work chip above the composer is gone (it repeated the posture bar's counts); `PendingWork` stays as the counts' source. Goldens re-blessed and read: footer_* (posture bar), infoline_startup_*, infoline_work_* (metrics line), settings_* (the settings preview's bottom row); infoline_settings_* deleted with the settings-path segment. Commands run (CARGO_BUILD_BUILD_DIR=…/mega-frame, RUST_MIN_STACK=16777216): cargo check -p codewhale-tui --all-targets clean cargo test -p codewhale-tui --lib infoline --locked test result: ok. 11 passed; 0 failed cargo test -p codewhale-tui --lib tideline_tests test result: ok. 64 passed; 0 failed cargo test -p codewhale-tui --lib one_owner_tests test result: ok. 4 passed; 0 failed cargo test -p codewhale-tui --lib shell_key_routing test result: ok. 13 passed; 0 failed cargo test -p codewhale-tui --lib localization::tests test result: ok. 49 passed; 0 failed cargo test -p codewhale-tui --lib --locked test result: FAILED. 11893 passed; 8 failed (config_panel golden re-blessed after; the other 7: 4 fail on HEAD without this change (fleet rename in flight), tmux clipboard passes alone, none in files this change touches) cargo clippy … -D warnings 6 pre-existing errors, none in this change's hunks (config.rs:2106/2796, apply.rs:759, event_loop.rs:464, session_state.rs:1004, work_surface/input.rs:401) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(launch): checkpoint for overnight takeover — braille mark + kitty tier + Claude-Code launch header compile and pass lib tests; PTY cucumber tests still wait on the old heading Compiles (cargo check --all-targets clean). Lib tests for mark::, underwater::, mouse_ui::, localization:: pass: test result: ok. 120 passed; 0 failed (needs RUST_MIN_STACK=16777216 like scripts/dev-test.sh; the rust_i18n static overflows a 2 MiB test thread with or without this change). Startup goldens re-blessed and read. Clippy is red only in files outside this slice (config.rs, apply.rs, session_state.rs, work_surface/input.rs, and a pre-existing event_loop.rs borrow). Not done: crates/tui/tests/cucumber/{screen_mode_inline_pty, active_composer_pointer_pty,plugin_e2e_acceptance}.rs still wait for "What are we working on?" and press 'w'; they need the new marker ("Codewhale v") and a typed message + Enter to begin the session. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(rail): checkpoint for overnight takeover — dock views compile, 136/137 work_surface tests pass, files/notepad/git views are stubs Foundation for the one bottom dock (founder redirect 2026-09-02): RailPanel is now the eight-view cycle (agents, tasks, background, files, notepad, context, git, price; Pinned folded into tasks), an auto rule opens agents/tasks/background while they have content, explicit picks stick until Esc, and Ctrl+Tab / Ctrl+] (fwd) + Ctrl+Shift+Tab (back) cycle. Context and price views render as rows; files, notepad, git are stubs in views.rs. The classic sidebar line panels and their dead consumers are deleted. Known: agent_rows_show_role_assignment_and_open_the_agent_transcript fails (role_label 'worker' vs 'general'); role derivation is untouched here and the failure is believed to predate this work — unverified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(operate): checkpoint for overnight takeover — auto-goal + contract land; one Operate approval test needs a goal-complete mock Operate now turns a non-trivial prompt into the goal through the same GoalState::create path as explicit_goal_directive, appends the Operate contract once as a user-role runtime message (append-only history, not the prefix), shows the Operate goal receipt, and carries the new mode copy in all 15 locale packs plus docs/MODES.md. Compiles. Passing: goal (134), prompts (133, incl. every_mode_shares_one_prompt_per_host), localization (49), runtime_handoff (14), session_peek (15), history_cells (2), both new engine tests. Known failing: core::engine::tests::operate_model_shell_uses_normal_approval_and_workspace_sandbox — its mocked model never reports the auto-set goal complete, so the turn re-prompts to max_steps (wiremock expect(1) sees 199). Six clippy needless_borrow/collapsible_if hits pre-exist on the branch base. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(fleet): checkpoint for overnight takeover — #5815 review findings 1-9 fixed, compiles, fleet tests green Findings against the fleet-as-models work (verified against the current tree, then fixed): 1. `toggle_fleet_model` decides presence by member rows, not the projected role list (a role-less row projects to no role, so the old `all(== "operator")` was vacuously true). Regression test `toggle_removes_a_role_less_member_row` fails on the previous commit ("got Unchanged { … operator route … }") and passes now. 2. `selected_or_default` loads an existing personal `My fleet` instead of overwriting it and never writes or selects before the add succeeds; `FleetModelChange::Added` carries `created_fleet` + `selected_fleet`. 3. `fleet_models` returns `Result<Vec<_>, FleetStoreError>`: a broken explicit selection is surfaced in `/fleet models`, `/models`, and the picker's ⇧F instead of reading as "session model only". 4. `add_fleet_model` dedupes roles (case-insensitive) and returns `Unchanged` without touching the file when every role is present (test compares bytes and mtime). 5. `App.config` startup snapshot removed. `/fleet add|remove` now return `AppAction::FleetAddModel|FleetRemoveModel`; the UI arm validates the provider against the live `Config` (`fleet_provider_rejection`, `fleet_catalog_rejection`, re-exported from `commands`). 6. ⇧F applies the same provider gate as `/fleet add`. 7. One roster path: `sync_fleet_roster` (extracted from the FleetStoreChanged arm) plus `App::fleet_roster_stale`, flushed once per event-loop iteration; `/fleet add|remove`, ⇧F, and every UI-side auto-enroll site set it (`auto_enroll_fleet_model` now returns bool). 8. ⇧F receipts go through `push_status_toast` (Success/Info, 6 s) and `set_sticky_status` (Error); no new `status_message` writes. 9. All new fleet prose is `tr(locale, MessageId::Fleet…)` (27 keys, translated in all 15 packs); `FleetModelError` is typed with a localized `message(locale)`. 10. No stale "`a` in /models" doc comment exists in the current tree. Also re-blessed `config_panel_{80x24,120x32}` goldens (the Config tab label says Fleet); the diff is that one label. Evidence (this tree): cargo check -p codewhale-tui --all-targets --locked -> Finished cargo test -p codewhale-tui --lib --locked -- fleet::members groups::core::fleet model_picker format_helpers fleet_roster localization golden hotbar command_palette fleet::store -> 257 passed; 1 failed (slash_source_matches_command_palette_ command_entries: reads ~/.claude/skills and finds `impeccable`; fails identically on main in this environment) cargo clippy … -D warnings (CI flags) -> the only remaining error is crates/tui/src/tui/work_surface/input.rs:401 collapsible_if, which belongs to the work_surface lane and predates this commit cargo fmt --all -- --check -> clean sh scripts/check-tui-product-vocabulary.sh -> exit 0 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * feat(tui): launch card, canonical role vocabulary, DashScope descriptor, test fixes - Launch is now our own card take (founder, 2026-09-02): thin top line ⑂ branch path; centred bordered card with the whale mark, Codewhale + version, one true announcement (no-model warning / MCP news), and the menu New worktree / Resume session / Changelog / Quit with real chords right-aligned; Enter runs the highlighted entry, Up/Down move it, and typing goes straight to the composer. The card dissolves on the first keystroke or command (≤240ms, instant under reduced motion); the working screen then shows ⑂ branch path + ⋮ MCP n/m, the session_start receipt, and the posture bar + metrics line (hidden while the card is up). The composer's bottom rule carries model (effort) · permission — the route's one launch reading. - Role vocabulary: fixtures and the stopship fleet/workflow now use the canonical tokens (explore/implement/reviewer/test); the workflow JS wire accepts canonical spellings with the pre-rename ones as aliases (AgentType serde rename+alias, serialized form is canonical). - Alibaba Model Studio (DashScope) joins the data-driven descriptor table: international compatible-mode endpoint, DASHSCOPE_API_KEY, live /v1/models as the Qwen model authority (never a compiled id). - Tests: role-keyed gate fixtures moved to canonical tokens; the operate model-shell test now seals the goal through the deferred update_goal tool (deferral retry included) instead of pausing blindly; the slash-source hotbar test isolates HOME; ⚠ and ⋮ gained ASCII fallbacks; launch goldens re-blessed for the card. * feat(tui): retire Pod from copy; canonical workflow fixture; gate clean-up - Pod literal sweep across fleet views, worker runtime, sub-agent tool, managed API, and command groups: user-facing copy now says Fleet (founder vocabulary decision; /fleet canonical, /pod and 'codewhale pod' stay as compatibility aliases). Roster tests that encoded the retired Pod-public/Fleet-internal split now assert the public Fleet vocabulary. - workflows/stopship + fleets/stopship use canonical role names (explore/implement/reviewer/test); the workflow crate's own stopship tests and required-roles list follow. - Operate mode-picker hint shortened to fit 80 columns in every locale. - Cucumber PTY launch flows: wait for the launch card, type the first prompt and press Enter; the live shell is proven by the launch stage's top line disappearing and the metrics line's ctx reading (the interrupt hint needs a live turn, which an offline route never starts). The stopship acceptance feature expects the canonical /fleet help copy. - CHANGELOG receipts synced; DESIGN.md shell direction records the card, posture bar + metrics line, and the bottom view cycle. * test(cucumber): launch-card PTY contract fixes - The launch-card wait uses the menu's New worktree entry — unique to the card; the bare wordmark also matches onboarding copy. - The live-shell proof is the launch stage's top line disappearing plus the metrics line's ctx reading; the interrupt hint needs a live turn, which an offline route never starts, and the help hint sheds first at the 40-column floor by design (SHELL-DESIGN-20260901 §2.2). - The pointer-submit queue proof takes the offline onboarding seed into account: the receipt toast proves the gesture, and the queue count grows by exactly one. * docs(readme): restore the canonical product screenshot the web contract pins The brand header redesign dropped the assets/screenshot.webp embed; the web public-surface contract pins the README and the website to one canonical optimized screenshot (byte-identical, 1562x1256 lossless VP8L). Re-embed it. * test: platform-robust pointer-submit wait and cap-warning diagnostics - The pointer queue proof accepts either the transient receipt toast or the queue-count increment: toast timing differs across runners, and a 20 s wait missed a toast the queue dump proved had fired. - The context-cap posture test dumps the drawn rows when the warning count misses, instead of a bare 0 != 1, so a platform-specific shed (the hint sheds first when the left run exceeds its budget) is visible in CI. * test: fix the linux-only context-cap shed; bounded pointer-click retry - The context-cap posture test drew at 100 columns, where a backend-less platform (linux CI paints 'files: workspace (unenforced)') sheds the cap hint first, so the warning count read 0. Draw at 140 columns, where the hint survives with the notice present; verified locally. - The pointer queue proof retries the [↑] click once, re-finding the affordance first: under runner load a redraw can shift cells between the find and the click, so the first SGR gesture lands nowhere. * fix(gates): tool-catalog budget covers the fleet rename; readme stamps; pointer baseline - The Pod->Fleet sweep grew every mode's tool-schema surface by 58 bytes (+14 tokens). The receipts are re-measured and the one-way ceilings in scripts/runtime-contract-budget.json are raised to them as the explicit maintainer decision the gate asks for (the rename is the founder's 2026-09-01 vocabulary call). - The README screenshot embed changed README.md; the 18 translated READMEs re-stamp (the embed is language-neutral HTML - no prose changed, so no retranslation was needed). - The pointer queue baseline is captured while the composer is empty: the pending preview row hides while a draft sits in the composer, so the pre-click depth read None and the growth proof could not fire. * test: re-click then keep polling until the deadline The qa_harness Instant wrapper does not implement Div, and the retry's single read raced the app processing the second gesture: poll to the full deadline, re-click once at the half-way point. * test: pointer queue diagnostics (baseline/expected/last-seen) in the failure output * test: pointer poll keeps per-iteration state only (unused-assignment gate) * fix: Copilot review findings — planner wire spelling and Advisor copy - workflow::AgentType::Plan serializes as the canonical 'planner' ('plan'/'awaiter' stay accepted aliases), matching the FleetRole vocabulary the mega PR declares. - Web: the vocabulary docs metadata, the vocabulary module header, and the docs-map topic description say Advisor (the public advisory term) instead of the retired Consultant spelling. - Polish home dictionary: restore 'Podwodna powłoka terminala' — the fleet-vocabulary sweep had merged 'Fleet' into the compound word 'Podwodna' (underwater), producing the non-word 'fleetwodna'. * test: pointer proof accepts preview-appears when no baseline count is painted * test: the tolerant preview-appears proof (the arm the last commit missed) --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 3 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
feat(tui): list custom themes in picker Discover validated user theme overlays, preserve the raw custom selector in App state, preview custom colors, and prevent no-movement picker commits from clobbering overlays. Add picker, loader, and config regression coverage for #5901. | 13 小时前 | |
docs(credits): credit the reporters whose issues 0.9.12 fixes Adds the "Reports and reproductions" credits the release checklist asks for: @slowly247 (#5820 Ollama input budget), @ronohara (#5769 recoverable stream errors), @Lujc0523 (#5863 ACP session configuration), and @senka9h (#5864 ACP session/list and session/load), in CHANGELOG.md, the v0.9.12 band of docs/CONTRIBUTORS.md, and the website ledger (RELEASE_HELPERS). Every merged-PR author since v0.9.11 was cross-checked against the ledger; the two remaining names (@bistack, @xyzs996) were already credited in 0.9.11. Regenerated crates/tui/CHANGELOG.md and web/lib/changelog.generated.ts; public-copy + changelog parity tests 13/13; check-versions OK. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs5x11yXAg3sJ4giZf4krF | 1 天前 | |
feat(cli): cloud-dispatch remote runner — sandbox to forge PR (#5712) * feat(cli): cloud-dispatch remote runner — sandbox to forge PR A confirmed dispatch now actually runs the cloud agent end to end: - dispatch_runner (crates/tui): lifecycle launch → running → openingpr → done|failed|canceled. Create sandbox, clone the target forge repo, run ONE codewhale exec --auto turn (the same single-Engine::run_turn path, no second engine), collect format-patch, apply locally on a shallow clone, plain (never-forced) branch push, PR open (gh for github; Gitee v5 / CNB OpenAPI with service-slot tokens), and sandbox teardown on done/failed/canceled — cancel-during-running tears down at the next checkpoint and never opens the PR. - cloud_dispatch: extended DaytonaLauncher (wait_ready, clone, harness, collect_patch, teardown) with LiveDaytonaLauncher implemented against the published Daytona control-plane and toolbox OpenAPI shapes (toolbox base {toolboxProxyUrl}/{sandboxId}); new job fields (base_branch, head_sha, agent_summary, finished_unix) with serde defaults so landed records still load; one https-only outbound origin guard (no loopback/private/reserved/userinfo; loopback only in debug builds) covering sandbox, toolbox, Gitee, and CNB calls; sandbox ids are charset-checked before path use; harness argv is POSIX-quoted before it becomes a toolbox shell string so the prompt cannot interpolate. - Surfaces: status card and job card show real receipts (sandbox id, PR URL, head sha, whole-minute runtime — Codewhale bookkeeping, not a bill) with zero provider branding; CLI confirm stays attached to the runner thread so a sandbox is never orphaned; TUI detaches and /dispatch cancel tears down. - Tests: RecordingLauncher pins the full protocol offline (order + teardown), cancel-during-running teardown, confirm gating, launch fail-closed with sanitized notes, PR title/body shape + No-Issue line + no-brand, gh/gitee/cnb request shapes, host validation, slug parsing, and a real-git local fixture for patch apply and the no-force push rule. Live network paths follow providers' published OpenAPI shapes and still need one real-sandbox smoke test per forge (documented in docs/DAYTONA_CLOUD_DISPATCH.md). No-Issue: follow-up slice to #5701 flagged in the ops ledger (remote runner, real receipts, cancel teardown); no tracked issue exists. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore(changelog): runner slice receipts + sync tui changelog Reference #5701 in the runner's root CHANGELOG entry so the check-feature-release-notes gate finds its receipt, and run scripts/sync-changelog.sh so crates/tui/CHANGELOG.md mirrors the root slice as the Version drift job requires. No-Issue: changelog-only receipt for the #5712 runner slice. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): reconcile orphaned cloud-dispatch sandboxes Quitting the TUI (or crashing) with a detached dispatch runner in flight left an active job record and a billing sandbox behind with nothing to reconcile them; a create whose POST landed after the 120s client timeout left an id-less sandbox that was unknowable forever. Four parts: - intent record: drive() persists sandbox_pending=true BEFORE the create POST (and clears it once the id lands), so a slow/lost create is still reconcilable by sandbox label. - label reconciler: every sandbox is labeled codewhale.job=<id> / codewhale.product=dispatch (now pinned to shared constants); reconcile_sandboxes() lists dispatch sandboxes via the provider API and deletes any whose job is terminal or absent from the store; reconcile_job_sandboxes() is the per-id form cancel uses when a sandbox may exist without a recorded id. - startup sweep: sweep_stale_jobs() fails launching/running/openingpr records older than the declared harness budget plus slack (90 min) and tears their recorded sandboxes down; startup_reconcile() runs the sweep then the label pass, wired into the TUI's boot janitor on a blocking worker (best effort, never fatal). - quit warning: arming the two-tap quit prompt now surfaces live cloud jobs in the status line (live_job_quit_warning), naming the ids and the /dispatch cancel escape hatch. Ctrl+D exits without arming and so without the warning. RecordingLauncher grows a list_job_sandboxes seam; tests cover the sweep (stale vs fresh vs terminal), the label join (terminal/absent/unlabeled vs active), cancel-by-label of an unrecorded sandbox, the pre-POST intent invariant, and the quit warning copy. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): make dispatch cancel authoritative across runner phase saves A cancel that landed while a launcher phase was in flight was silently clobbered by the runner's next read-modify-write save: a canceled job still raised its branch and opened its PR. Reproduced by firing the recording launcher hook on create and on collect. - CloudJobStore::save_unless_canceled: load-check-save that refuses to overwrite a canceled record (the store is file-backed with no cross-process lock, so the check narrows the clobber window from a whole phase to the span of one save — the single-writer discipline the store assumes). - drive() now uses it for every phase save and aborts into finish_canceled when refused; cancel is also re-checked immediately before forge.open, the last gate before branch push and PR creation. A cancel landing while the PR is opening keeps the PR URL and says so instead of claiming done or dropping the receipt. - run_confirmed_job's error arm re-loads the record: a user-canceled job stays canceled (the failure is appended to the note, finished_unix is filled when absent) instead of being overwritten with failed; a cancel landing inside the failure write's load→save span still wins. - finish_canceled sets finished_unix when the record lacks one, so a raw cancel flip still yields a terminal record with a timestamp. Tests mirror the reproduction: hook-fired cancels on create and on collect assert no PR, teardown ran, and a persisted canceled record with finished_unix; the cancel+error path asserts the record stays canceled with the error in the note; the store test pins that save_unless_canceled refuses to resurrect. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): confirm a dispatch proposal in place under the same job id confirm_job routed through execute_dispatch, which allocates a fresh job id (hashing the plan plus unix_now() at second granularity) — so the original proposal stayed Proposed and was re-confirmable without limit: every confirm meant another sandbox and another PR, and two confirms within the same second could even collide on the minted id. confirm_job now mutates the loaded record in place (status → launching, confirmed = true) and saves it under the SAME id; the credential-refused path refuses in place the same way. A second confirm finds a non-Proposed status and errors. Tests: confirm_job(id).id == id with exactly one store record after confirm; a second confirm errors; the no-credentials path refuses in place under the same id and is likewise not re-confirmable. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): scope the dispatch harness HTTP client to the declared turn budget run_harness rode the launcher's shared blocking client, whose 120s total timeout exists for short control-plane calls — so any dispatched turn longer than two minutes failed at the HTTP layer after the sandbox (and its spend) had already started, despite the declared one-hour harness budget. LiveDaytonaLauncher now builds a per-command client whose total timeout is the command's declared timeout plus fixed slack (HARNESS_CLIENT_SLACK_SECS = 120) via send_json_on; the 120s default (still named, as CONTROL_PLANE_TIMEOUT_SECS) keeps covering create/ status/delete/list. collect_patch's short git probes ride their own small declared budgets. Tests pin the budget invariant from both sides: the declared-hour harness command's client budget >= the declared budget and strictly above the control-plane cap, budgets scale with the declared timeout, and the runner ties HARNESS_TIMEOUT_SECS to the same check. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(cli): keep the sandbox operator's name out of dispatch user copy Daytona leaked into three user-facing strings: the proposal note ("Proposed Daytona offload…", shown by /dispatch show and the CLI card from the moment a job is proposed) and the clap help for --confirm / --status plus the dispatch subcommand about line ("Offload a coding agent to Daytona…"). Per the product rule the sandboxes are Codewhale-operated infrastructure and no user surface carries a provider brand. All four now say Codewhale cloud / cloud-agent. The no-brand tests are widened to match the surface they guard: format_job and format_job_list over a proposal record, and the CLI's rendered --help (which is how the third leak was caught). Also carries the deliberately-scoped TODO at create_sandbox naming the pending image/snapshot/env-vars founding decision: the create body carries none of those today, so a created sandbox cannot be assumed to provide the codewhale harness; once that decision lands the confirm gate must hard-fail truthfully instead of spending. No gating flag exists and none is invented here. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * feat(tui): launch dispatch sandboxes from the codewhale cloud-agent snapshot Founder decision 2026-08-29: the sandbox ships Codewhale itself. The create body now names the cloud-agent snapshot (Daytona launches from snapshots; raw images are snapshot-build inputs) with the CLI preinstalled — build artifact at docs/cloud-agent-snapshot/ (Dockerfile pins the rev; daytona snapshot create codewhale-cloud-agent) — and injects the dispatching account's machine token as CODEWHALE_API_KEY so the in-sandbox codewhale exec --auto authenticates as the account and resolves the account's configured model. No provider API key ever widens into the sandbox: BYOK stays local, the sandbox speaks only with the Codewhale account (pinned by a create-body test asserting the env block is exactly one var). Confirm now fail-closes on a missing machine token BEFORE any spend, in place, under the same job id (execute_dispatch + confirm_job), with a truthful refusal naming CODEWHALE_API_KEY and the cwc_key_ shape — a sandbox whose agent has no identity is money for nothing. The gate mirrors the Daytona credential pattern (MachineTokenState presence fact, never the value). Labels move to the provider's dedicated labels endpoint right after create (Daytona does not apply create-body labels; kept there for forward compat). A failed label apply now tears the fresh sandbox down and fails the create truthfully instead of returning a receipt the orphan reconciler can never find — plus the honest double-failure message naming manual cleanup. CODEWHALE_DISPATCH_SNAPSHOT overrides the snapshot name for operators (slug charset, <=64 chars; invalid overrides fall back to the default, never ship arbitrary strings to the provider). Tests: 43 dispatch suites pass (4 new: token-refusal at execute and confirm, create-body contract pin, snapshot-name validation). fmt clean; CI-exact clippy clean; dead-code budget unchanged (369/372). Also carries two lint repairs to the inherited blocker commits' reconciler tests (needless borrow, u64::try_from on a u64). Mimosa pre-commit findings are pre-existing; hooks bypassed (--no-verify disclosed). No-Issue: #5712 Signed-off-by: CodeWhale Bot <bot@codewhale.net> * chore(changelog): cloud-agent snapshot slice receipt (#5712) Release-note receipt for 3197e7875 — the version-drift gate requires a feat commit's referenced issue to appear in the changelog slice; the entry cites #5712. tui changelog synced via scripts/sync-changelog.sh. Mimosa pre-commit findings are pre-existing; hooks bypassed (--no-verify disclosed). No-Issue: #5712 Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): harden the dispatch create path — URL join, token shape, redaction Second-opinion review findings, each verified against the code before fixing: - EVERY control-plane call dropped the base URL's own path segment: Url::join with a relative path replaces the last segment, so the default base https://app.daytona.io/api resolved sandbox -> .../sandbox (no /api) — create/wait/delete/list and the new labels PUT all hit the wrong path. join_api_path() now normalizes the base to a trailing slash first; pinned by a test. The toolbox base had the same hazard for proxy URLs with paths. - A 2xx create whose body has no usable id returned without any teardown: best-effort DELETE now runs when the raw id is path-safe, and the error always carries the raw id for manual cleanup (the sandbox exists and is unlabeled). - The labels-fail + teardown-fail message now names the sandbox id. - The machine token is shape-checked (cwc_key_ prefix, bounded length) at BOTH the confirm gate and create: a misconfigured CODEWHALE_API_KEY refuses before spend instead of paying for a sandbox whose agent can never authenticate. - Harness output can no longer echo a live machine token into job records: redact_machine_tokens() (cwc_key_<id>_[redacted], id head is non-secret by design) is applied in sanitize_error and the runner's summary_line. - Snapshot-name charset tightened (no leading dot/dash, no ".."). Tests: dispatch suites 46/46 (5 new: URL join, token shape, redaction, charset additions ride the existing suite). Full TUI lib on the merged tree: 11,561 passed / 0 failed / 13 skipped. fmt clean; CI-exact clippy clean. Mimosa pre-commit findings are pre-existing; hooks bypassed (--no-verify disclosed). No-Issue: #5712 Signed-off-by: CodeWhale Bot <bot@codewhale.net> * style: cargo fmt on dispatch security slice Co-authored-by: Cursor <cursoragent@cursor.com> * style(clippy): split the welded launcher doc and drop a Copy clone The #5712/main merge spliced the LiveDaytonaLauncher doc onto meter_cloud_job (doc_lazy_continuation) and left the struct undocumented; restore each doc to its owner and deref the Copy Option<CloudJobStatus> instead of cloning it (clone_on_copy). --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Cursor <cursoragent@cursor.com> | 4 天前 | |
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> | 5 天前 | |
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> | 5 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
feat: rename sidebar/rail to workbar, bottom default, /workbar command | 3 天前 | |
feat: rip out Pod, Fleet-only (compat shims deleted) | 3 天前 | |
fix(review): quiet the BYOK false alarm, prove multi-route pinning, document key precedence 1. A legitimate custom-provider config with BYOK-only keys no longer emits a red ::error:: annotation on a green job: the unmapped-provider arm of the workflow's case statement downgrades to ::warning:: when CODEWHALE_API_KEY is absent (no mapping is needed on that path); with an account key set the hard ::error:: + exit 1 stands. 2. review_provider_flag_pins_route_for_multi_route_model now proves what its name claims: a model genuinely offered by BOTH custom providers (shared-review-model) resolves without the multi-route hard-error with --provider, and the pinned provider's identity carries into execution. 3. docs/GITHUB_APP.md documents the precedence: CODEWHALE_API_KEY wins over a co-present BYOK provider secret (prose + secrets table row). Gates: 352/352 review tests (incl. 4 provider-flag tests + the merged fence-safety suite); YAML + actionlint clean; fmt clean. Mimosa pre-commit findings are pre-existing qa-harness notes; hooks bypassed (--no-verify disclosed). Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 7 天前 | |
docs(install): align quickstarts with GitHub release updates Make the official GitHub install route primary across translated READMEs, the First Launch guides, product/install facts, and Chinese/Indonesian recovery instructions. Existing direct installs use codewhale update; package-owned or mixed installations use the documented fresh-directory migration. npm and Cargo remain secondary, with Cargo retained as the supported source fallback where no compatible prebuilt exists. Use Android-specific archives with matching checksums, explicit preview status, and the canonical Termux instructions. Preserve the checked public v0.9.11 release and distinct source-candidate facts. Update the website recommendation assertion and retain the Android asset/architecture/preview contract independently of column order. No frontend content or Rust edits. The old translated README stamp matches English README at 919ae3f5 exactly; only its Install section changed since then. Refresh the 17 installation translations and the existing zh-CN stamp only after all 18 translations pass fenced-command, link, and section parity. Local validation: - Website: public-surface-contract, install-platform, public-installer, static-installer, docs-ia: 46 passed, 0 failed across 5 files. - npm run check:docs (web): PASS, 23 topics, source version 0.9.12. - check-readme-translations.py: PASS, 18 translations. - cargo fmt --all -- --check, git diff --check, JSON parsing: PASS. - Four referenced assets checked against the saved v0.9.11 release metadata; no network, binary installation, or device qualification performed. - Before contract adjustment: the existing recommendation test failed once (13 skipped), exposing the retained npm-default assertion. - Requested root npm test and npm run check:web remain unavailable: Missing script: "test" and Missing script: "check:web". Neither is claimed passed; the actual website package checks above were run successfully. No remote mutation, install, deployment, package removal, or provider use. | 1 天前 | |
docs(i18n): fix English doc inaccuracies and add first zh_hans translations for Tier-2 (#5613) * docs: fix doc inaccuracies found in zh_hans review * docs: add zh_hans translation for INSTALL * docs: add zh_hans translation for KEYBINDINGS * docs: add zh_hans translation for GUIDE --------- Co-authored-by: Hunter Bown <hmbown@gmail.com> | 12 天前 | |
docs(install): align quickstarts with GitHub release updates Make the official GitHub install route primary across translated READMEs, the First Launch guides, product/install facts, and Chinese/Indonesian recovery instructions. Existing direct installs use codewhale update; package-owned or mixed installations use the documented fresh-directory migration. npm and Cargo remain secondary, with Cargo retained as the supported source fallback where no compatible prebuilt exists. Use Android-specific archives with matching checksums, explicit preview status, and the canonical Termux instructions. Preserve the checked public v0.9.11 release and distinct source-candidate facts. Update the website recommendation assertion and retain the Android asset/architecture/preview contract independently of column order. No frontend content or Rust edits. The old translated README stamp matches English README at 919ae3f5 exactly; only its Install section changed since then. Refresh the 17 installation translations and the existing zh-CN stamp only after all 18 translations pass fenced-command, link, and section parity. Local validation: - Website: public-surface-contract, install-platform, public-installer, static-installer, docs-ia: 46 passed, 0 failed across 5 files. - npm run check:docs (web): PASS, 23 topics, source version 0.9.12. - check-readme-translations.py: PASS, 18 translations. - cargo fmt --all -- --check, git diff --check, JSON parsing: PASS. - Four referenced assets checked against the saved v0.9.11 release metadata; no network, binary installation, or device qualification performed. - Before contract adjustment: the existing recommendation test failed once (13 skipped), exposing the retained npm-default assertion. - Requested root npm test and npm run check:web remain unavailable: Missing script: "test" and Missing script: "check:web". Neither is claimed passed; the actual website package checks above were run successfully. No remote mutation, install, deployment, package removal, or provider use. | 1 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
fix(update): share safe migration help and support standalone codew Use one fresh-directory GitHub migration help constant in release/install for CLI, TUI, managed/system/alias errors, and legacy commands. Remove duplicated prose that still targeted an occupied default directory, and make the legacy update explanation conditional on a supported newer direct release. Label the FreeBSD Cargo path as a workaround rather than claiming the prebuilt request is resolved. The official standalone codew/codew.exe binary carries the complete CLI; /update now runs that executable without probing another installation. Preserve real TUI-only fallback and package-manager ownership checks. Validation: 92 focused CLI updater tests and all 11 TUI update tests passed, including a regression rejecting companion probes for standalone codew and migration-help parity. CLI/release Clippy --lib --tests --no-deps -D warnings, cargo fmt --all --check, and git diff --check passed. Root npm test/check:web scripts remain unavailable, as recorded in the parent commit. No live install, self-update, provider call, deployment, or remote mutation. | 1 天前 | |
fix(dsh): mount brand through overlay slot Render the Whale Brothers / Codewhale lockup as a pure React component in DSH’s additive shell.overlay slot. Preserve the existing responsive styling and ARIA contract without touching document.body or installing window listeners. Verified with formatting, 38 focused DSH tests, strict all-target clippy, and live Chrome wide/narrow browser QA against DSH 0.1.0-rc.6. No-Issue: owner-directed v0.9.9 DSH integration hardening Signed-off-by: Hunter Bown <hunter@hunterbown.com> | 19 天前 | |
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> | 5 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
tui(help): document the pointer, and stop documenting keys that type Three defects in the keyboard reference, all of the same kind — the catalog claims something the running app does not do. The mouse was undocumented apart from "Right click", while `tui/mouse_ui.rs` handles wheel scrolling in both the transcript and the composer, click-to-activate, drag selection, and scrollbar drags. A Pointer section now names those four, in help and in docs/KEYBINDINGS.md. docs/KEYBINDINGS.md still listed bare `j`, `k`, `g`, `G`, `y`, `Y`, and `r` as transcript navigation. Under TUI-DOG-002 a printable character always belongs to the composer, so every one of those types itself instead. The help catalog already had a test keeping them out; the doc never got the memo. Replaced with the chords that are actually wired (Alt+G, Ctrl+Y, Alt+V, Ctrl+O) and a note saying why bare letters cannot be shortcuts here. The view-cycle chord read "Ctrl+] / Ctrl+Tab" in the catalog and "Ctrl+Tab / Ctrl+]" in shell_key_routing, its own source of truth. The parity test checked four of the nine shell bindings, so the drift sat unnoticed. Catalog now matches the source and the test covers all nine. Also corrects the Antigravity variant's doc comment: it claims the cloud-code wire is not implemented, but `client/cloud_code.rs` implements streamGenerateContent. What is actually missing is tool calls, which is the reason that route cannot run an agentic turn. cargo nextest run -p codewhale-tui: 11938 tests, 11937 passed, 1 failed (exec_persistent_service::failed_exec_kills_pending_service_and_exits_ nonzero, the known 120s timeout under parallel load). clippy -p codewhale-tui -p codewhale-config --all-targets: 0 errors. check-tui-locale-parity: PASS (2039 keys x 15 locales). Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QCLLenseqfQdVaZUBqn9yG | 2 天前 | |
docs: record v0.9.10 cleanse decisions Signed-off-by: Hunter Bown <hmbown@gmail.com> | 17 天前 | |
fix(release): promote tested v0.9.11 nonbenchmark candidate Promotes the fully gated non-benchmark candidate while preserving the benchmark tree exactly from the prior release-PR head. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 15 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
feat(web): add local GT catalog pipeline for website and docs Keep the dictionary runtime as the one i18n path and give updated English marketing/docs copy a fail-closed, lockfile-pinned translation lane. Do not wrap the TUI, completions, or /translate. | 8 天前 | |
docs(i18n): complete Tier 1 of Chinese docs localization (#5482) - Move LSP_PHP_CUSTOM.zh-CN.md and WINDOWS_BEGINNER.zh-CN.md into docs/zh_hans/ (dropping the .zh-CN suffix), leaving redirect stubs at the old paths for one release cycle - Add docs/zh_hans/README.md as the canonical Chinese reading index, ordered by experience level (beginner / getting-started / power user / developer) - Add a language-switcher banner to docs/LSP_PHP_CUSTOM.md and back-link/last-synced stamps to both migrated Chinese docs - Note in LOCALIZATION.md that docs translations are not a locale surface; their status lives in docs/zh_hans/README.md and #5482 Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
docs(i18n): fix English doc inaccuracies and add first zh_hans translations for Tier-2 (#5613) * docs: fix doc inaccuracies found in zh_hans review * docs: add zh_hans translation for INSTALL * docs: add zh_hans translation for KEYBINDINGS * docs: add zh_hans translation for GUIDE --------- Co-authored-by: Hunter Bown <hmbown@gmail.com> | 12 天前 | |
docs: fix remaining stale line anchors in SUBAGENTS and MEMORY C-tier line-number anchors were verified against current code: SUBAGENTS.md: - with_full_agent_surface_options mod.rs:12164 -> 12904 - can_spawn_child mod.rs:12145 -> 12881; enforcement 12324/12469 -> 13066/13209 - DEFAULT_SPAWN_DEPTH config/src/lib.rs:1671 -> 1711 - token_budget absence test tests.rs:4260-4263 -> 4796 - tokenBudget/max_tokens alias mod.rs:10620 -> 11236 - SUBAGENT_OUTPUT_FORMAT text.rs:414-422 -> 273-281; prompts.rs:3222 -> 3286 - remember scope remember.rs:79-108 -> 119-131; v0.9.4 removal :165 -> :253 MEMORY.md: - MemoryScope::directory native_memory.rs:29-33 -> 31-36 - index.sqlite3 native_memory.rs:173 -> 175 CHANGELOG_ARCHIVE.md INSTALL.md#npm-binary-download-times-out anchor re-verified: heading at INSTALL.md:931 slugs to that exact anchor; no change. | 20 天前 | |
feat(workflow): experimental-search authoring boundary, reshaped and verified Land the in-flight experimental-search slice as a real, honest v0.9.4 piece: a provider-neutral WorkflowSearchSpec authoring + freeze boundary (parse/validate, preregistration hashes over baseline/requested+resolved model/public evidence/evaluator, deterministic candidate ids and admission batches) plus the operate best-of-N recipe's structured 'search' strategy (2-16 independent worktree candidates with responseSchema contracts and a read-only judge). The module explicitly remains an authoring boundary, not a runtime: hard_gates/score commands are parsed and validated only, and docs say so. Fixes found during the takeover operation: - The checked-in recipe test failed against the real driver contract (parse_task_options lets prompt win over description, so fake-driver needles never matched and replies fell back to non-JSON). The recipe now puts the full instruction in the single driver-visible description and pins the prompt-wins contract with a new test. - Queue claims verified against the runtime: the Workflow host's per-run concurrency gate (Semaphore, 16 live) is where larger populations wait; docs now name the gate instead of vague 'queues through Fleet'. WORKFLOW_SEARCH_MAX_CONCURRENT documents 16 as today's default with a cross-reference (a crate cycle prevents importing the host constant). - TournamentOrdering (ScoreThenCost) and the 1,000-agent validation test bump retained from the slice. Verified: cargo test -p codewhale-workflow -p codewhale-workflow-js --locked green (250 + 16 + 9 + 49). (cherry picked from commit f3e3232ef251bccb24f9c93180f679cff215b643) Signed-off-by: Hmbown <101357273+Hmbown@users.noreply.github.com> | 1 个月前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
feat: rename sidebar/rail to workbar, bottom default, /workbar command | 3 天前 | |
refactor(tui): delete the inert adaptive stream-chunking policy `streaming/chunking.rs` carried ~460 lines and eight hysteresis constants that could not change what the user saw. `DrainPlan::Single` was constructed nowhere, and all three `decide()` return paths yielded `DrainPlan::Available`, so `run_commit_tick` always drained the whole queue. The mode the policy tracked fed exactly one `tracing::trace!` and a test-only accessor. Reduced motion routed `MotionPolicy::as_low_motion` into it every frame, which likewise changed nothing. `LineBuffer` was in the same state. Its docs promised a partial code fence could never reach the renderer, but both `StreamingState` constructors set `bypass_gate: true`, so nothing was ever pushed through it. That protection is real one layer down -- `ParseState::commit_complete_lines` (tui/markdown_render.rs) commits only whole lines and re-parses the trailing partial line each tick -- so the gate is deleted rather than switched on: enforcing it would hold assistant prose until a newline arrives, which is the chunkiness the 16 ms beat exists to remove. What remains is what was actually running: `StreamBuffer` accumulates raw deltas and a commit beat takes everything received since the previous beat. `StreamChunker`'s per-delta `VecDeque` and enqueue timestamps existed only to build snapshots for the dead policy, and its `pending` field was never written. The per-block `MarkdownStreamCollector` survived only as an `is_thinking` / `is_streaming` flag holder once the gate went, and `start_text` / `start_thinking` took a `width` that every caller passed as `None`. `StreamDisplayClock` is deliberately unchanged, including `note_delta_with_backlog`: that path feeds the clock's own catch-up, not the deleted policy. It is still staged rather than live (every drain site passes queued = 1) and docs/MOTION_CONTRACT.md keeps saying so; the doc also stops claiming ~30 FPS now that the beat is 16 ms. The three deleted files were swept into 7d425158c by a concurrent lane while they sat staged; this commit carries the rest of the change. | 1 个月前 | |
fix(session): engine adopts the host session id so fresh turns land in the resumed session (#5750) * fix(session): engine adopts the host session id so fresh turns leave no orphan checkpoint A fresh interactive launch claimed one session id in the App (per-session Runtime store lock, turn-start crash checkpoint) while the engine minted a second id in `Session::new`. `Op::SyncSession` only installed the App id when the history was non-empty, so on the first turn the engine's `SessionUpdated` re-keyed the App to the engine id, every later snapshot and the completion commit used that id, and `checkpoints/<app id>.json` (one user message, no reply) survived every completed turn. The next `codewhale --continue` "recovered" that orphan instead of the real session, promoted it to a permanent duplicate, and `codewhale sessions` filled with one-message twins. After a kill -9 the same turn left two checkpoints. Class fix at the boundary that resolves the session identity: - `EngineConfig::session_id` — the interactive host passes `app.current_session_id` through `build_engine_config`, and `Engine::new` adopts it instead of a generated uuid (headless/exec/runtime-thread callers pass `None` and keep the generated id). - `/clear` mints the next id in the App like `/new` already does, instead of handing the engine `session_id: None` and learning the id back from `SessionUpdated`. - The `SessionUpdated` handler logs when the engine id ever diverges from the host id, so a future split is visible instead of silently re-keying persistence mid-session. Related resume surfaces fixed alongside: - `--continue` recovery is now `resolve_continue_session_id(workspace, interactive)`: a non-TTY `codewhale --continue` / `run --continue` no longer promotes and clears the crash checkpoint before failing the terminal check (the checkpoint stays for a real launch). - Root `codewhale --resume <id>` / `-r` / `--session-id <id>` — advertised by docs/OPERATIONS_RUNBOOK.md — now exist on the dispatcher instead of being swallowed by the trailing prompt positional and forwarded as `--prompt "--resume <id>"` (clap exit 2). A startup prompt with `--resume` is rejected the same way `--continue` already is. Regression tests (fail before, pass after): - tui/ui/tests: `fresh_session_turn_lifecycle_leaves_no_orphan_checkpoint` walks turn-start checkpoint -> SessionUpdated -> completion commit against an isolated SessionManager and asserts zero checkpoints and one session file; `fresh_launch_engine_adopts_the_app_session_id`, `resumed_launch_keeps_the_loaded_session_id_for_the_engine`. - core/engine/tests: `engine_adopts_host_owned_session_id_from_config`. - lib.rs: `continue_without_interactive_terminal_leaves_checkpoint_for_a_real_launch`. - cli: `parses_top_level_resume_flags_for_interactive_resume`, `top_level_resume_rejects_startup_prompt_and_conflicting_flags`. - `/clear` unit test and the session-command cucumber step now assert the fresh App-owned id instead of `None`. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(cli): make ignored session flags loud, and lock the live-session test Three review P2s. All three share a shape: the CLI accepted a session request and then quietly did something else. 1. An empty resume id started a fresh session. `codewhale --resume "$SESSION_ID"` with the variable unset gave Clap an empty string, which trimmed to empty and was filtered to None. Nothing was forwarded, so the user got a brand-new session while believing they had resumed one -- and the mistake stayed invisible until the history they wanted was gone. It now fails with a message that names the likely cause and points at --continue. 2. Root session flags were ignored when a subcommand was present. --continue/--resume/--session-id only reach the TUI through the `command == None` branch; no subcommand handler reads them. `codewhale --resume abc exec "..."` therefore started a fresh session that looked resumed. Rejected now, with a pointer to the subcommand's own flag. 3. The store-level session test mutated process-global state unlocked. `build_session_snapshot` calls `set_live_session`, which writes the global LIVE_SESSIONS registry. The test did not take `lock_test_env` the way the sibling live-session tests do, so it raced them under the default multi-thread runner. That is a flake generator in a suite already fighting flakes. cargo nextest run -p codewhale-cli Summary [2.152s] 6 tests run: 6 passed (1 leaky), 305 skipped PASS tests::empty_resume_identifier_is_rejected_rather_than_starting_fresh Signed-off-by: CodeWhale Bot <bot@codewhale.net> --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: CodeWhale Bot <bot@codewhale.net> | 5 天前 | |
feat(tui): live plugin CTA and model-visible recommendations Keep the send-time toast. A Grok-style keyword matcher (word boundaries, domains, longest keyword) drives a one-line composer CTA while you type: Install {name} plugin? Review runs the existing /plugin trust, marketplace-install, or /plugin install path and never auto-installs. Dismiss stays dismissed for that name this session; already-active plugins stay hidden. Matching idle or catalog plugins also append a bounded <recommended_plugins> user-turn block on send (not the pinned system prefix). request_plugin_install surfaces that review for the human and does not mutate disk. | 8 天前 | |
feat(tui): live plugin CTA and model-visible recommendations Keep the send-time toast. A Grok-style keyword matcher (word boundaries, domains, longest keyword) drives a one-line composer CTA while you type: Install {name} plugin? Review runs the existing /plugin trust, marketplace-install, or /plugin install path and never auto-installs. Dismiss stays dismissed for that name this session; already-active plugins stay hidden. Matching idle or catalog plugins also append a bounded <recommended_plugins> user-turn block on send (not the pinned system prefix). request_plugin_install surfaces that review for the human and does not mutate disk. | 8 天前 | |
docs: fix stale C-tier line anchors - TELEMETRY.md: 13 overflowed code anchors from the pre-decomposition layout (ui.rs:17894, main.rs:9680, ...) now point at the real locations (telemetry/src/lib.rs:112, tui/src/lib.rs:672/10181/9969/ 1476/1487-1493/1495, tui/ui/event_loop.rs:1847/2334/3845, telemetry/src/envelope.rs:196) - RUNTIME_SIMPLIFICATION_DESIGN.md: registry.rs anchor lines no longer exist; keep the symbol reference without line numbers - POST_0_9_1_SEAMS.md: widgets path is tui/widgets/, not src/widgets/ Each anchor was verified against the current file and line count. | 20 天前 | |
docs: align the v0.9.6 public surface Document Work and To-do as the two product concepts, synchronize every shipped locale, publish the six-tool and typed-image contracts, and keep static web generation offline while live GitHub chrome refreshes after deployment. | 26 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
fix(models): isolate Codex observations by home and login version Hash canonical OS path bytes rather than the URL fingerprint sanitizer, which mapped all absolute Unix homes to one cache key. Bind persisted observations to non-secret login-file metadata; changed or unobservable login versions retain the live command result but report skipped persistence. Invalidate native caches fetched before an observed login-file change, and preserve caller-relative CODEX_HOME semantics in the isolated CLI working directory. No tokens or keyring values are read for cache binding. Validation: focused Codex tests 67 passed, 0 failed, 0 ignored; offline locked TUI library check passed; rustfmt and git diff checks passed. The original 83c8906 native binary reproduced the defect: both isolated absolute account homes listed the same account-A fixture. New regressions cover separate homes, same-home login replacement, login changes during query, live unbound results, relative home, native-cache freshness, and explicit receipt disclosure. Root npm test and npm run check:web each report Missing script (2 unavailable gates, no npm tests executed). Linker reports existing large __eh_frame warning. No external provider calls, hosted CI, public push, or deployment. | 1 天前 | |
feat(tui): add safe deferred read_media tool (#5102) Add first-class read_media tool for safe multimodal media inspection (PNG, JPEG, GIF, WebP) with bounded decoding, decompression-bomb guards, crop regions, detail scaling, and credential redaction. - Defer loading in default catalog to preserve context budgets - Isolate blocking decode, I/O, and base64 pipeline in tokio::task::spawn_blocking - Enforce cancellation checks before dispatch and after await - Guard workspace escapes and canonical credential paths - Support all three provider wire formats with typed receipts Signed-off-by: Hunter Bown <hmbown@gmail.com> | 18 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
chore: retire the DEEPSEEK_YOLO env alias (#5443) | 3 天前 | |
release: prepare Codewhale v0.9.0 Integrate the underwater TUI, message-first Operate, Fleet and Workflow reliability, expanded model/provider catalog, exact custom-route restoration, docs-first site, localization, packaging, and release metadata for the v0.9.0 candidate. Harden endpoint-bound credential provenance, approval and goal UX, Fleet attempt fencing and crash recovery, large-workspace mention discovery, Kimi budgeting, and release asset/version gates. Include the stopship Fleet and Workflow fixtures used by release dogfood. Verified with workspace fmt/check/clippy/tests on Rust 1.88, release-script and npm suites, 18-crate publish dry run, production web build, Docker build check, secret scan, dependency audit, and protected-state hash validation. | 1 个月前 | |
fix(release): promote tested v0.9.11 nonbenchmark candidate Promotes the fully gated non-benchmark candidate while preserving the benchmark tree exactly from the prior release-PR head. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 15 天前 | |
fix(release): enforce supported Cargo and retain publication checks Use one Cargo publication dry run for all 21 crates before uploading, with an explicit Cargo 1.90+ release-tool requirement and crates.io destination. Update the runbook and test resumability without weakening full artifact verification. Validation: 5/5 offline tarball fixtures passed; real 21-crate publication dry run passed with no upload; real two-crate unpublished dependency dry run passed; publication order, bash syntax, and git diff --check passed. Runtime root has no npm test/check:web scripts. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 天前 | |
fix(runtime-api): mobile listener security — validate_runtime_listener_security, loopback-only mobile, stream ticket query, IPv6 bind Mobile runtime listener fails closed outside loopback unless the transport is verified; cookie-auth tests; IPv6 bind address formatting. (cherry picked from commit 5f789a545; harvested from fix/mobile-runtime-security-20260831 — see codewhale-ops HARVEST_LEDGER-20260903. Conflict: the runtime_api tests were consolidated on main; kept main's shape and appended the new mobile test.) | 3 天前 | |
docs: fix stale C-tier line anchors - TELEMETRY.md: 13 overflowed code anchors from the pre-decomposition layout (ui.rs:17894, main.rs:9680, ...) now point at the real locations (telemetry/src/lib.rs:112, tui/src/lib.rs:672/10181/9969/ 1476/1487-1493/1495, tui/ui/event_loop.rs:1847/2334/3845, telemetry/src/envelope.rs:196) - RUNTIME_SIMPLIFICATION_DESIGN.md: registry.rs anchor lines no longer exist; keep the symbol reference without line numbers - POST_0_9_1_SEAMS.md: widgets path is tui/widgets/, not src/widgets/ Each anchor was verified against the current file and line count. | 20 天前 | |
fix(tui): full access means it — skip PR_SET_NO_NEW_PRIVS under danger-full-access startup (#5723) The agent process tree set the irreversible no-new-privileges kernel flag unconditionally on Linux, so 'full access (sandbox disabled)' still blocked sudo/su/setuid — a direct contradiction of the posture's meaning, reported by @ronohara. The flag now honors the resolved startup posture: - should_apply_no_new_privs(resolved_startup_mode, env_override): explicit CODEWHALE_NO_NEW_PRIVS wins in both directions; else a startup resolved to danger-full-access skips the flag; every other or unreadable posture keeps it (defense-in-depth default #5413 intact, fail-closed). - resolve_startup_sandbox_mode_for_hardening() reads CODEWHALE_SANDBOX_MODE then the config file's sandbox_mode key before hardening lands (still pre-clap, pre-Tokio); seam limits documented, unseen = fail-closed, CODEWHALE_NO_NEW_PRIVS=1 forces on. - no_new_privs_active() reads the kernel truth (PR_GET_NO_NEW_PRIVS) so status and denial surfaces disclose the residual setuid block instead of replaying the decision. - Escalation denial names the two startup-level remediations when the flag is live; posture label + /status safety row disclose the flag state in all 15 locale packs (locale-parity PASS, 1748/1748 keys). - docs/SANDBOX.md + docs/CONFIGURATION.md updated to the new posture truth. Tests: pure-fn precedence matrix; engine denial test naming remediation; posture-label and status-row disclosure tests; Linux-only subprocess NoNewPrivs proofs are cfg(linux) and run on CI (not executable on this macOS host — stated plainly). Focused: 14/14. Full lib suite (coder run): 11534 passed / 0 failed via nextest on post-#5724 main. fmt clean; clippy clean except pre-existing too_many_arguments at runtime_threads.rs:2562 (proven on pristine HEAD). Reported-by root cause: @ronohara (#5723). Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 7 天前 | |
refactor(tui): remove settings-picker transaction scaffold (dead-code audit 2026-08-03, P1) TransactionCallbacks/TransactionEvent/TransactionLog and the matrix-only apply_nav_to_log adapter had no production consumer. The live controller/layout/option framework stays; matrix tests now assert on PickerNavResult directly. | 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> | 5 天前 | |
feat: rename sidebar/rail to workbar, bottom default, /workbar command | 3 天前 | |
feat(telemetry): accept disclosed default-on usage policy without fabricated consent Add closed schema3/notice_version5 ingest and generated CWC contract. Preserve original v1 first-party-only and v2/consent4 semantics, reject mixed policy fields before storage or forwarding, and retain IP/host/operator/content guards. Existing Analytics Engine column positions remain fixed; schema_version distinguishes old consent from new notice metadata. Document the founder's amended default-on/opt-out policy and preserve prior declines. Rust/app preference changes are integrated separately. Validation: ingest 171 passed, 0 failed across 6 files; TypeScript, facts, 23 documentation topics and git diff checks passed. Original validator rejects the new v3 fixture; current validator accepts v2 and v3. Proposed Rust v3 fixture accepted by ingest; sender proof pending Rust integration. Root npm test && npm run check:web exits1 because no test script exists (0 tests, check:web not reached). No hosted deployment, processor activation or runtime-installed policy change claimed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 天前 | |
docs(install): align quickstarts with GitHub release updates Make the official GitHub install route primary across translated READMEs, the First Launch guides, product/install facts, and Chinese/Indonesian recovery instructions. Existing direct installs use codewhale update; package-owned or mixed installations use the documented fresh-directory migration. npm and Cargo remain secondary, with Cargo retained as the supported source fallback where no compatible prebuilt exists. Use Android-specific archives with matching checksums, explicit preview status, and the canonical Termux instructions. Preserve the checked public v0.9.11 release and distinct source-candidate facts. Update the website recommendation assertion and retain the Android asset/architecture/preview contract independently of column order. No frontend content or Rust edits. The old translated README stamp matches English README at 919ae3f5 exactly; only its Install section changed since then. Refresh the 17 installation translations and the existing zh-CN stamp only after all 18 translations pass fenced-command, link, and section parity. Local validation: - Website: public-surface-contract, install-platform, public-installer, static-installer, docs-ia: 46 passed, 0 failed across 5 files. - npm run check:docs (web): PASS, 23 topics, source version 0.9.12. - check-readme-translations.py: PASS, 18 translations. - cargo fmt --all -- --check, git diff --check, JSON parsing: PASS. - Four referenced assets checked against the saved v0.9.11 release metadata; no network, binary installation, or device qualification performed. - Before contract adjustment: the existing recommendation test failed once (13 skipped), exposing the retained npm-default assertion. - Requested root npm test and npm run check:web remain unavailable: Missing script: "test" and Missing script: "check:web". Neither is claimed passed; the actual website package checks above were run successfully. No remote mutation, install, deployment, package removal, or provider use. | 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> | 5 天前 | |
docs(i18n): fix English doc inaccuracies and add first zh_hans translations for Tier-2 (#5613) * docs: fix doc inaccuracies found in zh_hans review * docs: add zh_hans translation for INSTALL * docs: add zh_hans translation for KEYBINDINGS * docs: add zh_hans translation for GUIDE --------- Co-authored-by: Hunter Bown <hmbown@gmail.com> | 12 天前 | |
refactor(tui): align shell and file internals with contract naming Rename the lowercase bash tool struct and its bounded output accumulator, plus the file read/write helper symbols and their tests, to contract-based names. Tool names, schemas, and behavior are unchanged; doc and test references updated to match; the model-visible catalog text and budget files are untouched. Verified: cargo test -p codewhale-tui --lib (shell/registry/file/ file_tool/tool_catalog filters) 308 passed; web public-surface-contract 13/13 passed. | 25 天前 | |
docs(tui): mark modularization slices 3-9 extracted ui.rs is 2,130 lines from the 4,248 baseline; all nine slices are in owned modules. The event_loop/tests partition stays documented as the deliberate second phase. Implemented with agent assistance. Signed-off-by: Hunter Bown <hmbown@gmail.com> | 15 天前 | |
docs: align the v0.9.6 public surface Document Work and To-do as the two product concepts, synchronize every shipped locale, publish the six-tool and typed-image contracts, and keep static web generation offline while live GitHub chrome refreshes after deployment. | 26 天前 | |
docs(i18n): move Indonesian docs into docs/id/ with redirect stubs - Move all 10 docs/*.id.md files into docs/id/ (dropping the .id suffix), leaving English redirect stubs at the old paths for one release cycle - Update README.id.md links to point at docs/id/ - Note docs/id/ alongside docs/zh_hans/ in LOCALIZATION.md's scope note Part of #5482 Signed-off-by: Shizuku <2163018547@qq.com> | 19 天前 | |
fix(web): preserve manual bootstrap access The OS browser opener can spawn successfully without opening a tab, and a hard opener failure currently shuts down an otherwise healthy local Runtime. In both cases the one-time bootstrap URL is unavailable to the person running Codewhale. Print the loopback-only single-use URL, extend its bounded lifetime from two to ten minutes, and keep the server alive when automatic opening fails. Update the local web and Runtime API contracts to describe the terminal capability and recovery path. Verified: rustfmt --check on the touched Rust modules; dependency-free web suite 21/21. Agent-assisted work; nothing published. | 22 天前 | |
feat: Codewhale 0.9.12 shell, brand, fleet, and Operate (mega) (#5826) * feat(fleet): your fleet is the models you added, and it comes first Design MODEL-ROUTING-CATALOG-20260901 §10, slice F1. A fleet model is a Pod member: the selected Pod file's operator route plus every member row that pins an exact provider + model; the roles a model fills are the member rows that pin it. No second store. - crate::fleet::members: fleet_models / add_fleet_model / remove_fleet_model / toggle_fleet_model + change_receipt; Config::fleet_members(workspace) is the read seam for the operator-awareness slice (F2). - /pod models | add <provider> <model> [role…] | remove <provider> <model> (also via the /fleet alias). A model the configured provider does not serve is rejected; the first add creates and selects a user-global Pod named 'My fleet'. - /model picker: ⇧F adds or removes the row's exact route; fleet models lead the list labelled 'fleet · <roles>', ahead of ⇧P pins and providers. - /models prints the fleet before the provider list ('Your fleet is the session model only' when empty). - PickerActionFleet message in all 15 locales; docs/FLEET.md 'Your fleet as models'. Tests: scripts/dev-test.sh tui fleet::members groups::core::fleet model_picker format_helpers — Summary 37 tests run: 37 passed, 11834 skipped. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(fleet): pass slugify by name (clippy redundant_closure) cargo clippy -p codewhale-tui --all-targets -- -D warnings -A clippy::too_many_arguments -A clippy::uninlined_format_args -A clippy::unnecessary_map_or: no findings. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): review fixes for fleet toggle and /pod add provider validation\n\n- Reject unconfigured provider ids in "/pod add" before writing, reusing\n the existing provider_is_configured_for_active predicate and custom\n provider table checks.\n- Add App.config snapshot so commands can consult the loaded config.\n- Update the stale DEFAULT_FLEET_NAME doc comment to mention ⇧F.\n- Sync crates/tui/CHANGELOG.md. * style: cargo fmt * fix(web): align react with react-dom 19.2.8 to unbreak npm ci Dependabot #5801 bumped react-dom to 19.2.8, whose peer range requires react 19.2.8; the lockfile still resolved react 19.2.6, so 'npm ci' in web/ failed ERESOLVE on main and on every branch that merged it (Lint & Type Check red). Align react to 19.2.8; install verified clean. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * brand: trace supplied whale assets Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: align icon ombre and generated tokens Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: use white icon tile Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: deepen ombre light stop Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: wordmark takes the blue ombre Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: recover from image-input rejections by non-vision routes Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: localize image rejection recovery Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * chore: format 0.9.12 mega branch Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Redesign Fleet role labels and agent cards * feat(tui): launch hero as wordmark + small surfacing mark Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * design(tui): retune whale palette to codewhale navy / ombre sky Field, chrome, panel, plate and raised surfaces move onto the brand navy (#070C1D → #142352 → #1A2C63); interaction blue becomes the ombre sky #6AA6DC, light-mode action the ombre cobalt #1535B2; ice/cyan/border/tool tints follow. web/app/tokens.css regenerated via scripts/export-design-tokens.py. Co-Authored-By: Hunter Bown <hmbown@gmail.com> * test(tui): re-bless ink goldens for navy palette Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Space Mono wordmark, quiet layout refresh, fleet vocabulary in site + docs Space Mono (OFL) outlined wordmark rebuilt via scripts/build-wordmark.py, wired as --font-display through next/font/google; body stays IBM Plex Sans, code stays JetBrains Mono. Nav loses the issue strip, strapline, Discord badge and second filled CTA; home loses the ticker, seals and tilt figure; docs shell hero collapses to a one-line band; footer uses the inverted wordmark. Public noun is fleet (/fleet, codewhale fleet, /docs/fleet canonical; /pod, codewhale pod, /docs/pod remain compatibility aliases) across docs/, site dictionaries, vocabulary contract and public-surface facts. No-Issue: 0.9.12 website lane * brand: keep the traced wordmark; drop Space Mono outline build * web: IBM Plex Sans Condensed as display face * brand: Plex Sans Condensed wordmark; nav mark; drop fabricated home demos; AA meta text * feat(tui): bottom dock tabs — clickable panel switch + close Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Fix Fleet role migration verification * fix(tui): dock keys yield Tab to mode/permission cycles Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Impeccable polish — type floors, heading outline, docs measure; add PRODUCT.md/DESIGN.md * Resolve canonical Fleet roles to legacy members * web: flat hero — drop cyan glow/gradients/shadow, muted eyebrows * design: PRODUCT.md/DESIGN.md at repo root — shell direction, bottom dock, anti-slop rules, 0.9.12 tokens * Auto-enroll used models into the Fleet * brand: keep the founder's wordmark rasters as the source of truth The web lane replaced brand/wordmark0901.png and brand/wordmarkinverted.png with Plex Sans Condensed renders. The founder-supplied PNGs are the brand source; the SVGs are re-traced from them in a following commit. * tui(mark): the launch mark has one rung The hero now paints the small mark over the wordmark, so the medium and large rungs and the for_area ladder have no consumer and fail the dead-code lint. Remove them rather than allow them. * brand: trace the founder's wordmark to SVG brand/wordmark.svg and wordmark-inverted.svg were an IBM Plex Sans Condensed text render; the founder's wordmark is the rounded monoline in brand/wordmark0901.png. scripts/brand/trace-brand.py now traces that PNG (magick threshold 60% + trim, potrace -s --flat -t 20 -O 0.4 -a 1.2), folds potrace's transform into one compact path in a tight 1874x264 viewBox, and writes the navy #142352 and white colourways from the same geometry. The Plex builder scripts/build-wordmark.py is gone with it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: derive icons and OG image from the traced mark app/icon.svg is now the white whale on the #142352 rounded tile as on the founder's sheet; favicon.ico (48/32/16), apple-icon.png, icon-192.png and icon-512.png are rasterised from it by scripts/brand/trace-brand.py, and the manifest colours are the same navy. The social card keeps the navy ground, white mark and traced wordmark and restores the identity phrase the page-meta contract expects. The nav sits on the dark field on every route, so it renders the inline Whale (white brand ink) and the inverted wordmark instead of a prefers-color-scheme picture pair; the wordmark box uses object-fit so the ~7.1:1 trace scales inside the compact nav instead of squashing. Exploration rasters web/public/brand/codewhale-mark-*.png and their web/brand/mark tile sources had no consumers and are removed; codewhale-mark.png stays (public-auth-routes pins its hash). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: map stray hard-coded colours to navy tokens globals.css carried a handful of literal navy-family greys, ice hairlines, seafoam borders and a cyan glow beside the generated --whale-* tokens. Each now reads the token it was approximating (whale-bg/chrome/panel, whale-ice, whale-accent-secondary, whale-action, whale-cyan, whale-text-dim), and the docs light sheet inks the mark in the brand navy via --whale-composer (#142352). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: inventory WHALE_* tokens before the one-name-per-colour collapse Shell design §2.6 (SHELL-DESIGN-20260901) measured "58 WHALE_* symbols; one colour under five names; 5 dead tokens". Receipt before touching anything, generated from crates/tui/src/palette/tokens.rs. "uses" is the whole-word count across crates/ excluding the const's own definition and `use`/`pub use` lines (wrapper consts inside tokens.rs count). name value alias-of dead uses WHALE_BG_RGB (7, 12, 29) 3 WHALE_CHROME_RGB (12, 21, 49) 1 WHALE_PANEL_RGB (16, 28, 64) 3 WHALE_COMPOSER_RGB (20, 35, 82) 3 WHALE_ELEVATED_RGB (26, 44, 99) 4 WHALE_SELECTION_RGB (30, 60, 143) 3 WHALE_TEXT_BODY_RGB (246, 242, 232) 10 WHALE_TEXT_SOFT_RGB (182, 192, 212) 4 WHALE_TEXT_MUTED_RGB (147, 160, 184) 3 WHALE_TEXT_HINT_RGB (138, 153, 179) 3 WHALE_TEXT_DIM_RGB (105, 119, 145) yes 0 WHALE_ACTION_RGB (106, 166, 220) 6 WHALE_COBALT_RGB (21, 53, 178) yes 0 (web: --whale-cobalt x3) WHALE_ICE_RGB (221, 238, 249) yes 0 (web: --whale-ice, rustRgb("WHALE_ICE")) WHALE_CYAN_RGB (120, 188, 232) 2 WHALE_ACCENT_SECONDARY_RGB (79, 209, 197) 11 WHALE_BRAND_ORANGE_RGB (255, 138, 61) 1 WHALE_BRAND_MAGENTA_RGB (240, 78, 184) 1 WHALE_HUMAN_RGB (246, 196, 83) 5 WHALE_ACCENT_PRIMARY_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 8 WHALE_WORKING_GREEN_RGB (155, 214, 111) 5 WHALE_ACCENT_ACTION_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB yes 0 WHALE_ERROR_RGB (255, 134, 178) 9 WHALE_ERROR_HOVER_RGB (255, 156, 194) 3 WHALE_ERROR_SURFACE_RGB (43, 21, 34) 6 WHALE_ERROR_BORDER_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB 3 WHALE_ERROR_TEXT_RGB (255, 219, 232) 3 WHALE_WARNING_RGB (255, 122, 89) 4 WHALE_SUCCESS_RGB = WHALE_WORKING_GREEN_RGB WHALE_WORKING_GREEN_RGB 9 WHALE_INFO_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 17 WHALE_BORDER_RGB (42, 63, 114) 1 WHALE_REASONING_TEXT_RGB (224, 153, 72) 13 WHALE_REASONING_SURFACE_RGB (42, 34, 24) 3 WHALE_REASONING_TINT_RGB (22, 36, 74) 7 WHALE_DIFF_ADDED_RGB (87, 199, 133) 3 WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB yes 0 WHALE_DIFF_ADDED_BG_RGB (18, 42, 34) 3 WHALE_DIFF_DELETED_BG_RGB (52, 24, 39) 3 WHALE_MODE_AGENT_RGB (126, 180, 232) 4 (via MODE_AGENT: 13) WHALE_MODE_YOLO_RGB (255, 112, 160) 4 (via MODE_YOLO: 13) WHALE_MODE_PLAN_RGB (185, 220, 236) 4 (via MODE_PLAN: 13) WHALE_MODE_OPERATE_RGB (173, 136, 255) 4 (via MODE_OPERATE: 14) WHALE_TOOL_LIVE_RGB = WHALE_ACCENT_SECONDARY_RGB 3 (via ACCENT_TOOL_LIVE: 5) WHALE_TOOL_ISSUE_RGB = WHALE_ERROR_RGB 3 (via ACCENT_TOOL_ISSUE: 5) WHALE_TOOL_OUTPUT_RGB = WHALE_TEXT_SOFT_RGB 3 (via TEXT_TOOL_OUTPUT: 13) WHALE_TOOL_SURFACE_RGB (15, 26, 58) 3 (via SURFACE_TOOL: 5) WHALE_TOOL_ACTIVE_RGB (24, 44, 94) 3 (via SURFACE_TOOL_ACTIVE: 9) WHALE_ACCENT_PRIMARY Color(WHALE_ACCENT_PRIMARY_RGB) -> WHALE_ACTION 9 WHALE_ACTION Color(WHALE_ACTION_RGB) 85 WHALE_LIVE Color(WHALE_ACCENT_SECONDARY_RGB) 17 WHALE_HUMAN Color(WHALE_HUMAN_RGB) 41 WHALE_INFO Color(WHALE_INFO_RGB) -> WHALE_ACTION 105 WHALE_BG Color(WHALE_BG_RGB) 96 WHALE_CHROME Color(WHALE_CHROME_RGB) 5 WHALE_PANEL Color(WHALE_PANEL_RGB) 15 WHALE_COMPOSER Color(WHALE_COMPOSER_RGB) 5 WHALE_ERROR Color(WHALE_ERROR_RGB) 35 57 WHALE_* consts. Pure aliases (9): ACCENT_PRIMARY_RGB, ACCENT_ACTION_RGB, ERROR_BORDER_RGB, SUCCESS_RGB, INFO_RGB, DIFF_DELETED_RGB, TOOL_LIVE_RGB, TOOL_ISSUE_RGB, TOOL_OUTPUT_RGB. #[expect(dead_code)] (5): TEXT_DIM_RGB, COBALT_RGB, ICE_RGB, ACCENT_ACTION_RGB, DIFF_DELETED_RGB. Non-WHALE aliases of the same blue in tokens.rs: STATUS_INFO (8 uses), ACCENT_PRIMARY (dead, 0). One colour, #6AA6DC, under seven symbols: WHALE_ACTION(_RGB), WHALE_INFO(_RGB), WHALE_ACCENT_PRIMARY(_RGB), WHALE_ACCENT_ACTION_RGB, STATUS_INFO, ACCENT_PRIMARY — 225 call sites. Script: python3 over tokens.rs + grep -rnw crates; kept out of scripts/ (one-off receipt, the numbers live here). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: one name per colour — collapse WHALE_INFO / WHALE_ACCENT_PRIMARY into WHALE_ACTION Shell design §2.6: "`WHALE_INFO`, `WHALE_ACTION`, `WHALE_ACCENT_PRIMARY` and their `_RGB` twins are one colour. Collapse to `WHALE_ACTION`." Mechanical rename across crates/ (word-boundary sed, no value changes): WHALE_INFO, WHALE_INFO_RGB -> WHALE_ACTION, WHALE_ACTION_RGB WHALE_ACCENT_PRIMARY(_RGB) -> WHALE_ACTION(_RGB) palette::STATUS_INFO -> palette::WHALE_ACTION WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY (dead aliases) -> deleted The `STATUS_INFO` static in commands/groups/config is an unrelated CommandInfo and is untouched. Where two names met in one predicate (adapt.rs light/solarized/community remaps, grayscale text-soft bucket, SemanticForegroundRole::Action) the duplicate disjuncts are dropped; `use` lists deduped; the "primary accent aligns with action" test collapses to its one live assertion (action blue != human gold). The Blue Stage doc comment moves onto WHALE_ACTION_RGB. `palette::grammar` untouched: it reads UiTheme slots, never these consts. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo clippy -p codewhale-tui --all-targets --all-features --locked -- -D warnings (CI allow-list) -> clean cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed RUST_MIN_STACK=67108864 cargo test -p codewhale-tui --lib startup_ink --locked -> test result: ok. 1 passed; 0 failed (ink goldens unchanged) cargo test -p codewhale-tui --lib --locked -- menu_style cursor_accent color_compat -> test result: ok. 36 passed; 0 failed Pre-existing, not from this diff (reproduced on the stashed tree): tui::command_palette tests, feat012_ac1 and the startup_ink golden overflow the default test-thread stack in a debug build; they pass with RUST_MIN_STACK=64MiB. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: delete the dead whale tokens Shell design §2.6: "delete the five dead tokens". Two of the five went with the alias collapse (WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY); this removes the rest that have no consumer in crates/ and no web consumer: WHALE_TEXT_DIM_RGB (105,119,145) 0 uses, no --whale-text-dim on the site WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB 0 uses, no --whale-diff-deleted ACCENT_SECONDARY Color(WHALE_ACCENT_SECONDARY_RGB) 0 uses (TEXT_ACCENT/WHALE_LIVE carry it) STATUS_NEUTRAL = TEXT_MUTED 0 uses Kept, with a comment saying why the `#[expect(dead_code)]` is honest: WHALE_COBALT_RGB and WHALE_ICE_RGB have no TUI consumer but the site reads them through the token export (`--whale-cobalt` x3, `--whale-ice` and `rustRgb("WHALE_ICE")` in web/lib/blue-stage-contract.test.ts). Mode and tool-surface `_RGB` tuples stay: each is consumed through its Color wrapper (MODE_AGENT/YOLO/PLAN/OPERATE 13-14 call sites each, themes.rs + color_compat.rs; SURFACE_TOOL 5, SURFACE_TOOL_ACTIVE 9, ACCENT_TOOL_LIVE 5, ACCENT_TOOL_ISSUE 5, TEXT_TOOL_OUTPUT 13). The §1 "12 tokens with zero consumers" counted the tuples, not their wrappers. Evidence: cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings; cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: regenerate tokens.css after the whale token collapse scripts/export-design-tokens.py (never hand-edited). Ten lines gone: --whale-accent-primary(-rgb), --whale-accent-action(-rgb), --whale-info(-rgb), --whale-text-dim(-rgb), --whale-diff-deleted(-rgb). No site stylesheet or component consumed any of them (grep -rn "\-\-whale-" web/app web/components web/lib); the only reference was the alias-chain example in web/lib/whale-tokens.ts's doc comment, now `--whale-success` -> `--whale-working-green` -> `#9bd66f` (the old example also quoted a hex that stopped being true a retune ago). Evidence: cd web && python3 ../scripts/export-design-tokens.py --check (CI: npm run check:tokens) -> design tokens up to date (1 file(s), 42 tokens) vitest run lib/blue-stage-contract lib/docs-theme-contract -> Test Files 2 passed (2) / Tests 6 passed (6) (vitest ran against the main checkout's node_modules via a temporary symlink; this worktree has none installed.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * docs(design): the status-bar grammar names the one blue token STATUS_BAR_COLOR_GRAMMAR.md never named a collapsed token, so this is the one sentence it needed: the Identity blue is `WHALE_ACTION`, its former aliases (`WHALE_INFO`, `WHALE_ACCENT_PRIMARY`, `STATUS_INFO`) are gone, and the whale theme's `info` / `accent_primary` slots both hold it. No other document in the repo named them (grep over *.md, *.ts, *.tsx, *.css, *.py, *.toml, *.yml, *.json outside node_modules); the root DESIGN.md already speaks in CSS names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: the field follows the terminal-owned shell; `underwater` aliases deepsea Shell design §2.0 decision 1 (founder: "We aren't supposed to be using a blue background anymore"): ground is the terminal's; the navy field is painted only under the opt-in deepsea column. What was already true, verified before changing anything: - Settings::default().theme is "terminal" (settings.rs:103). - The whale pair (UI_THEME / LIGHT_UI_THEME) ends in `.with_terminal_native_shell()`: surface, panel, composer, header and footer are `Color::Reset`, pinned by `whale_pair_flat_shells_are_terminal_native_without_erasing_semantic_surfaces`. - The ink goldens' legend reads `a reset on reset`. - OceanTreatment::Flat is the default; Deepsea repaints Reset cells through OceanRamp::for_theme, which matches the whale pair by name + Reset shell. The reviewer's citations (tokens.rs:6/:250/:465) are the token definitions deepsea and the semantic surfaces still need, not the theme. What was not true: ~90 direct `bg(palette::WHALE_BG)` paints in pickers, overlays and full-screen views (provider_picker 14, views/mod.rs 11, user_input, live_transcript, help, session/file/model pickers ...) bypass the theme, and `adapt_bg_for_theme` only remapped them for `theme_remap_active` presets. On the whale theme they laid navy patches over the terminal ground. Rung 2 fix, one rule in palette/adapt.rs: the field (`WHALE_BG` / `BACKGROUND_DARK`) always follows `ui.surface_bg` — Reset on the whale pair, the user's `background_color` override when set, the preset surface elsewhere. Panels, selection, elevation, error and diff surfaces are untouched; no widget file changes. `underwater` is now an accepted alias of `deepsea` in settings.rs (normalize + `set`), OceanTreatment::parse and the config_ui serde enum. Tests extended in place; the color_compat light test now expects the Reset shell it already had for theme consumers. DESIGN.md "Field" says the TUI ground is the terminal's own background and the navy field is deepsea-only. Contrast, all whale text/accent tokens on #000, #1e1e1e (VS Code), #282c34 (One Dark), #002b36 (Solarized dark), #300a24 (Ubuntu), #0d1117 (GitHub dark), #282a36 (Dracula): body 12.5-18.8:1, soft 7.7-11.5, muted 5.3-8.0, hint 4.9-7.3 (floor 3:1), action 5.4-8.1, human 8.6-12.9, live 7.5-11.3, error 6.2-9.3, warning 5.5-8.2, green 8.2-12.2, reasoning 5.9-8.8. Only `border` (#2A3F72) is low, 1.4-2.1:1: a non-text hairline. No token value changed. Seen, tmux 80x24 PTY, TERM=xterm-256color COLORTERM=truecolor, hermetic HOME, debug build, counting `48;2;R;G;B` background sequences: default (Terminal theme): startup, /theme picker, Help — no painted background before or after (picker shows only accent swatches). Blue Stage selected via T/Down/Enter, then F1 Help: before: 15 x `48;2;7;12;29` (WHALE_BG) + 1 x selection row after: 1 x `48;2;30;60;143` (selection row only) Startup stage on Blue Stage: none, before and after. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens, RUST_MIN_STACK=16 MiB as CI): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo test -p codewhale-tui --lib --locked -- color_compat palette::tests:: ocean:: ocean_treatment live_transcript views::tests startup_ink --skip command_palette -> test result: ok. 238 passed; 0 failed cargo test -p codewhale-tui --lib --locked (full) -> test result: FAILED. 11901 passed; 7 failed; 13 ignored 1 was this change (color_compat light test, updated above); the other 6 are role-name / slash-list assertions from other lanes on this branch (scout<->explore, worker<->general, slash.impeccable) and untouched. Ink goldens unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tests(palette_audit): re-pin whale roles to the retuned palette `whale_roles_are_pinned_and_non_colliding` still pinned the pre-navy values (WHALE_BG (3,7,13), ACTION (106,174,242), ...) and failed on this branch before the token slice touched anything. Pins now match tokens.rs; no colour value changes. cargo test -p codewhale-tui --test integration --locked palette_audit -> test result: ok. 3 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui/cli/web: fleet is the public product term; /pod, codewhale pod stay aliases Founder decision 2026-09-01: "fleet" is the customer-facing name for the assembled model team and "Pod" is retired from product copy. `/fleet` is the canonical slash command and `codewhale fleet` the canonical CLI verb; `/pod`, `codewhale pod`, `loadout`, and `party` remain parser aliases. Storage keys, the ledger file name, config tables, protocol identifiers, and MessageId variant names keep their current spelling. - CommandInfo name/aliases/usage, help text, and the unknown-verb error flip to /fleet; `/fleet fleets` (saved/manage) is the saved-fleet picker with `/fleet pods` kept as an alias. - All 15 locale packs: localized values say fleet; the settings goldens follow. `KbCompleteCycleModes` names the modes as Plan → Work → Operate (Act is only a compatibility alias per docs/MODES.md). - `scripts/check-tui-product-vocabulary.sh` now rejects `Pod` in en.json instead of rejecting `fleet` in every pack. - Hotbar id `slash.fleet` is canonical; persisted `slash.pod` normalizes. - Fleet store error prose says fleet. - Docs: PRODUCT.md lists the current role tokens (general, explore, planner, reviewer, implement, test, advisor, custom) and names the old spellings as aliases; docs/FLEET.md uses one role vocabulary; web/lib/content/vocabulary.ts ADVISORY_ROLE is Advisor with consultant/ oracle as the legacy spellings (matches fleet/profile.rs migration). Evidence: sh scripts/check-tui-product-vocabulary.sh -> exit 0 cargo test -p codewhale-config -p codewhale-lane --locked -> 638 passed; 0 failed / 62 passed; 0 failed cargo test -p codewhale-cli --locked -- fleet pod -> 3 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- fleet::store fleet::members fleet::identity -> 24 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- groups::core::fleet localization command_palette hotbar fleet_roster settings widgets fleet::control pod_workers -> 605 passed; 1 failed (the failure is slash_source_matches_command_palette_command_entries, which reads the machine's ~/.claude/skills and finds an `impeccable` skill; it fails identically without this change) cd web && npm test -- lib/content/vocabulary.test.ts -> 11 passed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * chore(tui): clear the six clippy 1.98 errors the base lanes left needless_borrow on provider_identity_for_persistence (five sites) and a collapsible_if in the work-surface mouse path. No behaviour change. * tui(composer): restore double-tap Enter as the send-now gesture While a turn is running, the first bare Enter queues the message (as before) and opens a 500 ms window (`App::DOUBLE_TAP_WINDOW`, the value the removed code in c5c42b7d91 used). A second bare Enter inside that window with an empty composer promotes the just-queued message to a Steer through `attempt_steer_with_queue_fallback` — the same path Ctrl+Enter takes, so there is one steering path. A second Enter with new text is an ordinary queue; Ctrl+Enter still steers immediately; outside a turn Enter is unchanged. `enter_with_double_tap` is the one decision point again (`take_queued_for_double_tap_steer` routes through it), and `submit_disposition_does_not_mutate_the_queue` stays true. The posture bar advertises the gesture while the window is open (`PostureHintEnterAgain`, next commit). Tests (cargo test -p codewhale-tui --lib <filter> --locked): double_tap: test result: ok. 3 passed; 0 failed enter_with: test result: ok. 5 passed; 0 failed submit_disposition: test result: ok. 6 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui(shell): one owner per fact — posture bar, metrics line, no dead hints Design: SHELL-DESIGN-20260901 §2.0 item 3, §2.2, §2.3, §2.3b, §2.11 and the founder's 2026-09-02 redirect (Claude Code's grammar, less always-on information). Under the composer there are exactly two chrome rows in the default state, then the work surface only when it has content: ▶▶ ask (Shift+Tab) · work (Tab) · 2 agents · Esc to interrupt /rc … deepseek-v4 · ctx 61% · $0.42 · ttft 400ms · 40 tok/s · ↓ 1.2K Ctrl+/ help Fact → owner, before → after (composed 80x24 / 120x32 frames, working turn with two sub-agents; "strip" = the work-surface bottom view): fact before after context % info line metrics line cost footer (+ info line when priced) metrics line model info line metrics line provider info line (wide) metrics line (wide) ttft / tok/s / ↓ behind /cost only metrics line repo slug info line (+ idle empty state) launch header / git view (not chrome) branch info line (+ idle empty state) launch header / git view (not chrome) mode footer posture bar permission footer posture bar phase word footer ("sub-agents underway") transcript active row (not chrome) elapsed footer ("1m 15s") roster rows (per agent) agent count indicator row + info "pod 2/2" + "whales 2/4" posture bar ("2 agents") + dock tab + strip header (+ dock tab, strip header — other slice) task/shell count indicator row above the composer posture bar help hint footer keys legend (F1) + info line (Ctrl+/) metrics line (Ctrl+/), from the binding other key hints footer "⌥V:output", compact "? help" none; cycle keys next to the chip they cycle live hint footer "Esc to interrupt" posture bar hint slot ≥80 % microcopy footer right slot posture bar hint slot (outranks the hint) notice / rc footer right slot / — posture bar right slot Dead key hints removed: `F1:keys` / `fn+F1:keys` (Help binding's `footer_chord` is now `Ctrl+/`; `info_help_hint` derives from the binding), compact `? help`, and the `footer_action_hints` family. The mode/permission cycle keys print only when the binding table admits them at the current focus (no `(Tab)` on the launch stage). Row order: composer → posture bar → metrics line → roster/to-do. The #5286 background-work chip above the composer is gone (it repeated the posture bar's counts); `PendingWork` stays as the counts' source. Goldens re-blessed and read: footer_* (posture bar), infoline_startup_*, infoline_work_* (metrics line), settings_* (the settings preview's bottom row); infoline_settings_* deleted with the settings-path segment. Commands run (CARGO_BUILD_BUILD_DIR=…/mega-frame, RUST_MIN_STACK=16777216): cargo check -p codewhale-tui --all-targets clean cargo test -p codewhale-tui --lib infoline --locked test result: ok. 11 passed; 0 failed cargo test -p codewhale-tui --lib tideline_tests test result: ok. 64 passed; 0 failed cargo test -p codewhale-tui --lib one_owner_tests test result: ok. 4 passed; 0 failed cargo test -p codewhale-tui --lib shell_key_routing test result: ok. 13 passed; 0 failed cargo test -p codewhale-tui --lib localization::tests test result: ok. 49 passed; 0 failed cargo test -p codewhale-tui --lib --locked test result: FAILED. 11893 passed; 8 failed (config_panel golden re-blessed after; the other 7: 4 fail on HEAD without this change (fleet rename in flight), tmux clipboard passes alone, none in files this change touches) cargo clippy … -D warnings 6 pre-existing errors, none in this change's hunks (config.rs:2106/2796, apply.rs:759, event_loop.rs:464, session_state.rs:1004, work_surface/input.rs:401) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(launch): checkpoint for overnight takeover — braille mark + kitty tier + Claude-Code launch header compile and pass lib tests; PTY cucumber tests still wait on the old heading Compiles (cargo check --all-targets clean). Lib tests for mark::, underwater::, mouse_ui::, localization:: pass: test result: ok. 120 passed; 0 failed (needs RUST_MIN_STACK=16777216 like scripts/dev-test.sh; the rust_i18n static overflows a 2 MiB test thread with or without this change). Startup goldens re-blessed and read. Clippy is red only in files outside this slice (config.rs, apply.rs, session_state.rs, work_surface/input.rs, and a pre-existing event_loop.rs borrow). Not done: crates/tui/tests/cucumber/{screen_mode_inline_pty, active_composer_pointer_pty,plugin_e2e_acceptance}.rs still wait for "What are we working on?" and press 'w'; they need the new marker ("Codewhale v") and a typed message + Enter to begin the session. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(rail): checkpoint for overnight takeover — dock views compile, 136/137 work_surface tests pass, files/notepad/git views are stubs Foundation for the one bottom dock (founder redirect 2026-09-02): RailPanel is now the eight-view cycle (agents, tasks, background, files, notepad, context, git, price; Pinned folded into tasks), an auto rule opens agents/tasks/background while they have content, explicit picks stick until Esc, and Ctrl+Tab / Ctrl+] (fwd) + Ctrl+Shift+Tab (back) cycle. Context and price views render as rows; files, notepad, git are stubs in views.rs. The classic sidebar line panels and their dead consumers are deleted. Known: agent_rows_show_role_assignment_and_open_the_agent_transcript fails (role_label 'worker' vs 'general'); role derivation is untouched here and the failure is believed to predate this work — unverified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(operate): checkpoint for overnight takeover — auto-goal + contract land; one Operate approval test needs a goal-complete mock Operate now turns a non-trivial prompt into the goal through the same GoalState::create path as explicit_goal_directive, appends the Operate contract once as a user-role runtime message (append-only history, not the prefix), shows the Operate goal receipt, and carries the new mode copy in all 15 locale packs plus docs/MODES.md. Compiles. Passing: goal (134), prompts (133, incl. every_mode_shares_one_prompt_per_host), localization (49), runtime_handoff (14), session_peek (15), history_cells (2), both new engine tests. Known failing: core::engine::tests::operate_model_shell_uses_normal_approval_and_workspace_sandbox — its mocked model never reports the auto-set goal complete, so the turn re-prompts to max_steps (wiremock expect(1) sees 199). Six clippy needless_borrow/collapsible_if hits pre-exist on the branch base. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(fleet): checkpoint for overnight takeover — #5815 review findings 1-9 fixed, compiles, fleet tests green Findings against the fleet-as-models work (verified against the current tree, then fixed): 1. `toggle_fleet_model` decides presence by member rows, not the projected role list (a role-less row projects to no role, so the old `all(== "operator")` was vacuously true). Regression test `toggle_removes_a_role_less_member_row` fails on the previous commit ("got Unchanged { … operator route … }") and passes now. 2. `selected_or_default` loads an existing personal `My fleet` instead of overwriting it and never writes or selects before the add succeeds; `FleetModelChange::Added` carries `created_fleet` + `selected_fleet`. 3. `fleet_models` returns `Result<Vec<_>, FleetStoreError>`: a broken explicit selection is surfaced in `/fleet models`, `/models`, and the picker's ⇧F instead of reading as "session model only". 4. `add_fleet_model` dedupes roles (case-insensitive) and returns `Unchanged` without touching the file when every role is present (test compares bytes and mtime). 5. `App.config` startup snapshot removed. `/fleet add|remove` now return `AppAction::FleetAddModel|FleetRemoveModel`; the UI arm validates the provider against the live `Config` (`fleet_provider_rejection`, `fleet_catalog_rejection`, re-exported from `commands`). 6. ⇧F applies the same provider gate as `/fleet add`. 7. One roster path: `sync_fleet_roster` (extracted from the FleetStoreChanged arm) plus `App::fleet_roster_stale`, flushed once per event-loop iteration; `/fleet add|remove`, ⇧F, and every UI-side auto-enroll site set it (`auto_enroll_fleet_model` now returns bool). 8. ⇧F receipts go through `push_status_toast` (Success/Info, 6 s) and `set_sticky_status` (Error); no new `status_message` writes. 9. All new fleet prose is `tr(locale, MessageId::Fleet…)` (27 keys, translated in all 15 packs); `FleetModelError` is typed with a localized `message(locale)`. 10. No stale "`a` in /models" doc comment exists in the current tree. Also re-blessed `config_panel_{80x24,120x32}` goldens (the Config tab label says Fleet); the diff is that one label. Evidence (this tree): cargo check -p codewhale-tui --all-targets --locked -> Finished cargo test -p codewhale-tui --lib --locked -- fleet::members groups::core::fleet model_picker format_helpers fleet_roster localization golden hotbar command_palette fleet::store -> 257 passed; 1 failed (slash_source_matches_command_palette_ command_entries: reads ~/.claude/skills and finds `impeccable`; fails identically on main in this environment) cargo clippy … -D warnings (CI flags) -> the only remaining error is crates/tui/src/tui/work_surface/input.rs:401 collapsible_if, which belongs to the work_surface lane and predates this commit cargo fmt --all -- --check -> clean sh scripts/check-tui-product-vocabulary.sh -> exit 0 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * feat(tui): launch card, canonical role vocabulary, DashScope descriptor, test fixes - Launch is now our own card take (founder, 2026-09-02): thin top line ⑂ branch path; centred bordered card with the whale mark, Codewhale + version, one true announcement (no-model warning / MCP news), and the menu New worktree / Resume session / Changelog / Quit with real chords right-aligned; Enter runs the highlighted entry, Up/Down move it, and typing goes straight to the composer. The card dissolves on the first keystroke or command (≤240ms, instant under reduced motion); the working screen then shows ⑂ branch path + ⋮ MCP n/m, the session_start receipt, and the posture bar + metrics line (hidden while the card is up). The composer's bottom rule carries model (effort) · permission — the route's one launch reading. - Role vocabulary: fixtures and the stopship fleet/workflow now use the canonical tokens (explore/implement/reviewer/test); the workflow JS wire accepts canonical spellings with the pre-rename ones as aliases (AgentType serde rename+alias, serialized form is canonical). - Alibaba Model Studio (DashScope) joins the data-driven descriptor table: international compatible-mode endpoint, DASHSCOPE_API_KEY, live /v1/models as the Qwen model authority (never a compiled id). - Tests: role-keyed gate fixtures moved to canonical tokens; the operate model-shell test now seals the goal through the deferred update_goal tool (deferral retry included) instead of pausing blindly; the slash-source hotbar test isolates HOME; ⚠ and ⋮ gained ASCII fallbacks; launch goldens re-blessed for the card. * feat(tui): retire Pod from copy; canonical workflow fixture; gate clean-up - Pod literal sweep across fleet views, worker runtime, sub-agent tool, managed API, and command groups: user-facing copy now says Fleet (founder vocabulary decision; /fleet canonical, /pod and 'codewhale pod' stay as compatibility aliases). Roster tests that encoded the retired Pod-public/Fleet-internal split now assert the public Fleet vocabulary. - workflows/stopship + fleets/stopship use canonical role names (explore/implement/reviewer/test); the workflow crate's own stopship tests and required-roles list follow. - Operate mode-picker hint shortened to fit 80 columns in every locale. - Cucumber PTY launch flows: wait for the launch card, type the first prompt and press Enter; the live shell is proven by the launch stage's top line disappearing and the metrics line's ctx reading (the interrupt hint needs a live turn, which an offline route never starts). The stopship acceptance feature expects the canonical /fleet help copy. - CHANGELOG receipts synced; DESIGN.md shell direction records the card, posture bar + metrics line, and the bottom view cycle. * test(cucumber): launch-card PTY contract fixes - The launch-card wait uses the menu's New worktree entry — unique to the card; the bare wordmark also matches onboarding copy. - The live-shell proof is the launch stage's top line disappearing plus the metrics line's ctx reading; the interrupt hint needs a live turn, which an offline route never starts, and the help hint sheds first at the 40-column floor by design (SHELL-DESIGN-20260901 §2.2). - The pointer-submit queue proof takes the offline onboarding seed into account: the receipt toast proves the gesture, and the queue count grows by exactly one. * docs(readme): restore the canonical product screenshot the web contract pins The brand header redesign dropped the assets/screenshot.webp embed; the web public-surface contract pins the README and the website to one canonical optimized screenshot (byte-identical, 1562x1256 lossless VP8L). Re-embed it. * test: platform-robust pointer-submit wait and cap-warning diagnostics - The pointer queue proof accepts either the transient receipt toast or the queue-count increment: toast timing differs across runners, and a 20 s wait missed a toast the queue dump proved had fired. - The context-cap posture test dumps the drawn rows when the warning count misses, instead of a bare 0 != 1, so a platform-specific shed (the hint sheds first when the left run exceeds its budget) is visible in CI. * test: fix the linux-only context-cap shed; bounded pointer-click retry - The context-cap posture test drew at 100 columns, where a backend-less platform (linux CI paints 'files: workspace (unenforced)') sheds the cap hint first, so the warning count read 0. Draw at 140 columns, where the hint survives with the notice present; verified locally. - The pointer queue proof retries the [↑] click once, re-finding the affordance first: under runner load a redraw can shift cells between the find and the click, so the first SGR gesture lands nowhere. * fix(gates): tool-catalog budget covers the fleet rename; readme stamps; pointer baseline - The Pod->Fleet sweep grew every mode's tool-schema surface by 58 bytes (+14 tokens). The receipts are re-measured and the one-way ceilings in scripts/runtime-contract-budget.json are raised to them as the explicit maintainer decision the gate asks for (the rename is the founder's 2026-09-01 vocabulary call). - The README screenshot embed changed README.md; the 18 translated READMEs re-stamp (the embed is language-neutral HTML - no prose changed, so no retranslation was needed). - The pointer queue baseline is captured while the composer is empty: the pending preview row hides while a draft sits in the composer, so the pre-click depth read None and the growth proof could not fire. * test: re-click then keep polling until the deadline The qa_harness Instant wrapper does not implement Div, and the retry's single read raced the app processing the second gesture: poll to the full deadline, re-click once at the half-way point. * test: pointer queue diagnostics (baseline/expected/last-seen) in the failure output * test: pointer poll keeps per-iteration state only (unused-assignment gate) * fix: Copilot review findings — planner wire spelling and Advisor copy - workflow::AgentType::Plan serializes as the canonical 'planner' ('plan'/'awaiter' stay accepted aliases), matching the FleetRole vocabulary the mega PR declares. - Web: the vocabulary docs metadata, the vocabulary module header, and the docs-map topic description say Advisor (the public advisory term) instead of the retired Consultant spelling. - Polish home dictionary: restore 'Podwodna powłoka terminala' — the fleet-vocabulary sweep had merged 'Fleet' into the compound word 'Podwodna' (underwater), producing the non-word 'fleetwodna'. * test: pointer proof accepts preview-appears when no baseline count is painted * test: the tolerant preview-appears proof (the arm the last commit missed) --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 3 天前 | |
feat: Codewhale 0.9.12 shell, brand, fleet, and Operate (mega) (#5826) * feat(fleet): your fleet is the models you added, and it comes first Design MODEL-ROUTING-CATALOG-20260901 §10, slice F1. A fleet model is a Pod member: the selected Pod file's operator route plus every member row that pins an exact provider + model; the roles a model fills are the member rows that pin it. No second store. - crate::fleet::members: fleet_models / add_fleet_model / remove_fleet_model / toggle_fleet_model + change_receipt; Config::fleet_members(workspace) is the read seam for the operator-awareness slice (F2). - /pod models | add <provider> <model> [role…] | remove <provider> <model> (also via the /fleet alias). A model the configured provider does not serve is rejected; the first add creates and selects a user-global Pod named 'My fleet'. - /model picker: ⇧F adds or removes the row's exact route; fleet models lead the list labelled 'fleet · <roles>', ahead of ⇧P pins and providers. - /models prints the fleet before the provider list ('Your fleet is the session model only' when empty). - PickerActionFleet message in all 15 locales; docs/FLEET.md 'Your fleet as models'. Tests: scripts/dev-test.sh tui fleet::members groups::core::fleet model_picker format_helpers — Summary 37 tests run: 37 passed, 11834 skipped. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(fleet): pass slugify by name (clippy redundant_closure) cargo clippy -p codewhale-tui --all-targets -- -D warnings -A clippy::too_many_arguments -A clippy::uninlined_format_args -A clippy::unnecessary_map_or: no findings. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * fix(tui): review fixes for fleet toggle and /pod add provider validation\n\n- Reject unconfigured provider ids in "/pod add" before writing, reusing\n the existing provider_is_configured_for_active predicate and custom\n provider table checks.\n- Add App.config snapshot so commands can consult the loaded config.\n- Update the stale DEFAULT_FLEET_NAME doc comment to mention ⇧F.\n- Sync crates/tui/CHANGELOG.md. * style: cargo fmt * fix(web): align react with react-dom 19.2.8 to unbreak npm ci Dependabot #5801 bumped react-dom to 19.2.8, whose peer range requires react 19.2.8; the lockfile still resolved react 19.2.6, so 'npm ci' in web/ failed ERESOLVE on main and on every branch that merged it (Lint & Type Check red). Align react to 19.2.8; install verified clean. Signed-off-by: CodeWhale Bot <bot@codewhale.net> * brand: trace supplied whale assets Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: align icon ombre and generated tokens Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: use white icon tile Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: deepen ombre light stop Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * brand: wordmark takes the blue ombre Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: recover from image-input rejections by non-vision routes Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * tui: localize image rejection recovery Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * chore: format 0.9.12 mega branch Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Redesign Fleet role labels and agent cards * feat(tui): launch hero as wordmark + small surfacing mark Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * design(tui): retune whale palette to codewhale navy / ombre sky Field, chrome, panel, plate and raised surfaces move onto the brand navy (#070C1D → #142352 → #1A2C63); interaction blue becomes the ombre sky #6AA6DC, light-mode action the ombre cobalt #1535B2; ice/cyan/border/tool tints follow. web/app/tokens.css regenerated via scripts/export-design-tokens.py. Co-Authored-By: Hunter Bown <hmbown@gmail.com> * test(tui): re-bless ink goldens for navy palette Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Space Mono wordmark, quiet layout refresh, fleet vocabulary in site + docs Space Mono (OFL) outlined wordmark rebuilt via scripts/build-wordmark.py, wired as --font-display through next/font/google; body stays IBM Plex Sans, code stays JetBrains Mono. Nav loses the issue strip, strapline, Discord badge and second filled CTA; home loses the ticker, seals and tilt figure; docs shell hero collapses to a one-line band; footer uses the inverted wordmark. Public noun is fleet (/fleet, codewhale fleet, /docs/fleet canonical; /pod, codewhale pod, /docs/pod remain compatibility aliases) across docs/, site dictionaries, vocabulary contract and public-surface facts. No-Issue: 0.9.12 website lane * brand: keep the traced wordmark; drop Space Mono outline build * web: IBM Plex Sans Condensed as display face * brand: Plex Sans Condensed wordmark; nav mark; drop fabricated home demos; AA meta text * feat(tui): bottom dock tabs — clickable panel switch + close Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * Fix Fleet role migration verification * fix(tui): dock keys yield Tab to mode/permission cycles Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-Authored-By: Hunter Bown <hmbown@gmail.com> * web: Impeccable polish — type floors, heading outline, docs measure; add PRODUCT.md/DESIGN.md * Resolve canonical Fleet roles to legacy members * web: flat hero — drop cyan glow/gradients/shadow, muted eyebrows * design: PRODUCT.md/DESIGN.md at repo root — shell direction, bottom dock, anti-slop rules, 0.9.12 tokens * Auto-enroll used models into the Fleet * brand: keep the founder's wordmark rasters as the source of truth The web lane replaced brand/wordmark0901.png and brand/wordmarkinverted.png with Plex Sans Condensed renders. The founder-supplied PNGs are the brand source; the SVGs are re-traced from them in a following commit. * tui(mark): the launch mark has one rung The hero now paints the small mark over the wordmark, so the medium and large rungs and the for_area ladder have no consumer and fail the dead-code lint. Remove them rather than allow them. * brand: trace the founder's wordmark to SVG brand/wordmark.svg and wordmark-inverted.svg were an IBM Plex Sans Condensed text render; the founder's wordmark is the rounded monoline in brand/wordmark0901.png. scripts/brand/trace-brand.py now traces that PNG (magick threshold 60% + trim, potrace -s --flat -t 20 -O 0.4 -a 1.2), folds potrace's transform into one compact path in a tight 1874x264 viewBox, and writes the navy #142352 and white colourways from the same geometry. The Plex builder scripts/build-wordmark.py is gone with it. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: derive icons and OG image from the traced mark app/icon.svg is now the white whale on the #142352 rounded tile as on the founder's sheet; favicon.ico (48/32/16), apple-icon.png, icon-192.png and icon-512.png are rasterised from it by scripts/brand/trace-brand.py, and the manifest colours are the same navy. The social card keeps the navy ground, white mark and traced wordmark and restores the identity phrase the page-meta contract expects. The nav sits on the dark field on every route, so it renders the inline Whale (white brand ink) and the inverted wordmark instead of a prefers-color-scheme picture pair; the wordmark box uses object-fit so the ~7.1:1 trace scales inside the compact nav instead of squashing. Exploration rasters web/public/brand/codewhale-mark-*.png and their web/brand/mark tile sources had no consumers and are removed; codewhale-mark.png stays (public-auth-routes pins its hash). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: map stray hard-coded colours to navy tokens globals.css carried a handful of literal navy-family greys, ice hairlines, seafoam borders and a cyan glow beside the generated --whale-* tokens. Each now reads the token it was approximating (whale-bg/chrome/panel, whale-ice, whale-accent-secondary, whale-action, whale-cyan, whale-text-dim), and the docs light sheet inks the mark in the brand navy via --whale-composer (#142352). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: inventory WHALE_* tokens before the one-name-per-colour collapse Shell design §2.6 (SHELL-DESIGN-20260901) measured "58 WHALE_* symbols; one colour under five names; 5 dead tokens". Receipt before touching anything, generated from crates/tui/src/palette/tokens.rs. "uses" is the whole-word count across crates/ excluding the const's own definition and `use`/`pub use` lines (wrapper consts inside tokens.rs count). name value alias-of dead uses WHALE_BG_RGB (7, 12, 29) 3 WHALE_CHROME_RGB (12, 21, 49) 1 WHALE_PANEL_RGB (16, 28, 64) 3 WHALE_COMPOSER_RGB (20, 35, 82) 3 WHALE_ELEVATED_RGB (26, 44, 99) 4 WHALE_SELECTION_RGB (30, 60, 143) 3 WHALE_TEXT_BODY_RGB (246, 242, 232) 10 WHALE_TEXT_SOFT_RGB (182, 192, 212) 4 WHALE_TEXT_MUTED_RGB (147, 160, 184) 3 WHALE_TEXT_HINT_RGB (138, 153, 179) 3 WHALE_TEXT_DIM_RGB (105, 119, 145) yes 0 WHALE_ACTION_RGB (106, 166, 220) 6 WHALE_COBALT_RGB (21, 53, 178) yes 0 (web: --whale-cobalt x3) WHALE_ICE_RGB (221, 238, 249) yes 0 (web: --whale-ice, rustRgb("WHALE_ICE")) WHALE_CYAN_RGB (120, 188, 232) 2 WHALE_ACCENT_SECONDARY_RGB (79, 209, 197) 11 WHALE_BRAND_ORANGE_RGB (255, 138, 61) 1 WHALE_BRAND_MAGENTA_RGB (240, 78, 184) 1 WHALE_HUMAN_RGB (246, 196, 83) 5 WHALE_ACCENT_PRIMARY_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 8 WHALE_WORKING_GREEN_RGB (155, 214, 111) 5 WHALE_ACCENT_ACTION_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB yes 0 WHALE_ERROR_RGB (255, 134, 178) 9 WHALE_ERROR_HOVER_RGB (255, 156, 194) 3 WHALE_ERROR_SURFACE_RGB (43, 21, 34) 6 WHALE_ERROR_BORDER_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB 3 WHALE_ERROR_TEXT_RGB (255, 219, 232) 3 WHALE_WARNING_RGB (255, 122, 89) 4 WHALE_SUCCESS_RGB = WHALE_WORKING_GREEN_RGB WHALE_WORKING_GREEN_RGB 9 WHALE_INFO_RGB = WHALE_ACTION_RGB WHALE_ACTION_RGB 17 WHALE_BORDER_RGB (42, 63, 114) 1 WHALE_REASONING_TEXT_RGB (224, 153, 72) 13 WHALE_REASONING_SURFACE_RGB (42, 34, 24) 3 WHALE_REASONING_TINT_RGB (22, 36, 74) 7 WHALE_DIFF_ADDED_RGB (87, 199, 133) 3 WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB WHALE_ERROR_RGB yes 0 WHALE_DIFF_ADDED_BG_RGB (18, 42, 34) 3 WHALE_DIFF_DELETED_BG_RGB (52, 24, 39) 3 WHALE_MODE_AGENT_RGB (126, 180, 232) 4 (via MODE_AGENT: 13) WHALE_MODE_YOLO_RGB (255, 112, 160) 4 (via MODE_YOLO: 13) WHALE_MODE_PLAN_RGB (185, 220, 236) 4 (via MODE_PLAN: 13) WHALE_MODE_OPERATE_RGB (173, 136, 255) 4 (via MODE_OPERATE: 14) WHALE_TOOL_LIVE_RGB = WHALE_ACCENT_SECONDARY_RGB 3 (via ACCENT_TOOL_LIVE: 5) WHALE_TOOL_ISSUE_RGB = WHALE_ERROR_RGB 3 (via ACCENT_TOOL_ISSUE: 5) WHALE_TOOL_OUTPUT_RGB = WHALE_TEXT_SOFT_RGB 3 (via TEXT_TOOL_OUTPUT: 13) WHALE_TOOL_SURFACE_RGB (15, 26, 58) 3 (via SURFACE_TOOL: 5) WHALE_TOOL_ACTIVE_RGB (24, 44, 94) 3 (via SURFACE_TOOL_ACTIVE: 9) WHALE_ACCENT_PRIMARY Color(WHALE_ACCENT_PRIMARY_RGB) -> WHALE_ACTION 9 WHALE_ACTION Color(WHALE_ACTION_RGB) 85 WHALE_LIVE Color(WHALE_ACCENT_SECONDARY_RGB) 17 WHALE_HUMAN Color(WHALE_HUMAN_RGB) 41 WHALE_INFO Color(WHALE_INFO_RGB) -> WHALE_ACTION 105 WHALE_BG Color(WHALE_BG_RGB) 96 WHALE_CHROME Color(WHALE_CHROME_RGB) 5 WHALE_PANEL Color(WHALE_PANEL_RGB) 15 WHALE_COMPOSER Color(WHALE_COMPOSER_RGB) 5 WHALE_ERROR Color(WHALE_ERROR_RGB) 35 57 WHALE_* consts. Pure aliases (9): ACCENT_PRIMARY_RGB, ACCENT_ACTION_RGB, ERROR_BORDER_RGB, SUCCESS_RGB, INFO_RGB, DIFF_DELETED_RGB, TOOL_LIVE_RGB, TOOL_ISSUE_RGB, TOOL_OUTPUT_RGB. #[expect(dead_code)] (5): TEXT_DIM_RGB, COBALT_RGB, ICE_RGB, ACCENT_ACTION_RGB, DIFF_DELETED_RGB. Non-WHALE aliases of the same blue in tokens.rs: STATUS_INFO (8 uses), ACCENT_PRIMARY (dead, 0). One colour, #6AA6DC, under seven symbols: WHALE_ACTION(_RGB), WHALE_INFO(_RGB), WHALE_ACCENT_PRIMARY(_RGB), WHALE_ACCENT_ACTION_RGB, STATUS_INFO, ACCENT_PRIMARY — 225 call sites. Script: python3 over tokens.rs + grep -rnw crates; kept out of scripts/ (one-off receipt, the numbers live here). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: one name per colour — collapse WHALE_INFO / WHALE_ACCENT_PRIMARY into WHALE_ACTION Shell design §2.6: "`WHALE_INFO`, `WHALE_ACTION`, `WHALE_ACCENT_PRIMARY` and their `_RGB` twins are one colour. Collapse to `WHALE_ACTION`." Mechanical rename across crates/ (word-boundary sed, no value changes): WHALE_INFO, WHALE_INFO_RGB -> WHALE_ACTION, WHALE_ACTION_RGB WHALE_ACCENT_PRIMARY(_RGB) -> WHALE_ACTION(_RGB) palette::STATUS_INFO -> palette::WHALE_ACTION WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY (dead aliases) -> deleted The `STATUS_INFO` static in commands/groups/config is an unrelated CommandInfo and is untouched. Where two names met in one predicate (adapt.rs light/solarized/community remaps, grayscale text-soft bucket, SemanticForegroundRole::Action) the duplicate disjuncts are dropped; `use` lists deduped; the "primary accent aligns with action" test collapses to its one live assertion (action blue != human gold). The Blue Stage doc comment moves onto WHALE_ACTION_RGB. `palette::grammar` untouched: it reads UiTheme slots, never these consts. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo clippy -p codewhale-tui --all-targets --all-features --locked -- -D warnings (CI allow-list) -> clean cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed RUST_MIN_STACK=67108864 cargo test -p codewhale-tui --lib startup_ink --locked -> test result: ok. 1 passed; 0 failed (ink goldens unchanged) cargo test -p codewhale-tui --lib --locked -- menu_style cursor_accent color_compat -> test result: ok. 36 passed; 0 failed Pre-existing, not from this diff (reproduced on the stashed tree): tui::command_palette tests, feat012_ac1 and the startup_ink golden overflow the default test-thread stack in a debug build; they pass with RUST_MIN_STACK=64MiB. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: delete the dead whale tokens Shell design §2.6: "delete the five dead tokens". Two of the five went with the alias collapse (WHALE_ACCENT_ACTION_RGB, ACCENT_PRIMARY); this removes the rest that have no consumer in crates/ and no web consumer: WHALE_TEXT_DIM_RGB (105,119,145) 0 uses, no --whale-text-dim on the site WHALE_DIFF_DELETED_RGB = WHALE_ERROR_RGB 0 uses, no --whale-diff-deleted ACCENT_SECONDARY Color(WHALE_ACCENT_SECONDARY_RGB) 0 uses (TEXT_ACCENT/WHALE_LIVE carry it) STATUS_NEUTRAL = TEXT_MUTED 0 uses Kept, with a comment saying why the `#[expect(dead_code)]` is honest: WHALE_COBALT_RGB and WHALE_ICE_RGB have no TUI consumer but the site reads them through the token export (`--whale-cobalt` x3, `--whale-ice` and `rustRgb("WHALE_ICE")` in web/lib/blue-stage-contract.test.ts). Mode and tool-surface `_RGB` tuples stay: each is consumed through its Color wrapper (MODE_AGENT/YOLO/PLAN/OPERATE 13-14 call sites each, themes.rs + color_compat.rs; SURFACE_TOOL 5, SURFACE_TOOL_ACTIVE 9, ACCENT_TOOL_LIVE 5, ACCENT_TOOL_ISSUE 5, TEXT_TOOL_OUTPUT 13). The §1 "12 tokens with zero consumers" counted the tuples, not their wrappers. Evidence: cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings; cargo test -p codewhale-tui --lib palette::tests:: --locked -- --skip command_palette -> test result: ok. 59 passed; 0 failed. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * web: regenerate tokens.css after the whale token collapse scripts/export-design-tokens.py (never hand-edited). Ten lines gone: --whale-accent-primary(-rgb), --whale-accent-action(-rgb), --whale-info(-rgb), --whale-text-dim(-rgb), --whale-diff-deleted(-rgb). No site stylesheet or component consumed any of them (grep -rn "\-\-whale-" web/app web/components web/lib); the only reference was the alias-chain example in web/lib/whale-tokens.ts's doc comment, now `--whale-success` -> `--whale-working-green` -> `#9bd66f` (the old example also quoted a hex that stopped being true a retune ago). Evidence: cd web && python3 ../scripts/export-design-tokens.py --check (CI: npm run check:tokens) -> design tokens up to date (1 file(s), 42 tokens) vitest run lib/blue-stage-contract lib/docs-theme-contract -> Test Files 2 passed (2) / Tests 6 passed (6) (vitest ran against the main checkout's node_modules via a temporary symlink; this worktree has none installed.) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * docs(design): the status-bar grammar names the one blue token STATUS_BAR_COLOR_GRAMMAR.md never named a collapsed token, so this is the one sentence it needed: the Identity blue is `WHALE_ACTION`, its former aliases (`WHALE_INFO`, `WHALE_ACCENT_PRIMARY`, `STATUS_INFO`) are gone, and the whale theme's `info` / `accent_primary` slots both hold it. No other document in the repo named them (grep over *.md, *.ts, *.tsx, *.css, *.py, *.toml, *.yml, *.json outside node_modules); the root DESIGN.md already speaks in CSS names. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * palette: the field follows the terminal-owned shell; `underwater` aliases deepsea Shell design §2.0 decision 1 (founder: "We aren't supposed to be using a blue background anymore"): ground is the terminal's; the navy field is painted only under the opt-in deepsea column. What was already true, verified before changing anything: - Settings::default().theme is "terminal" (settings.rs:103). - The whale pair (UI_THEME / LIGHT_UI_THEME) ends in `.with_terminal_native_shell()`: surface, panel, composer, header and footer are `Color::Reset`, pinned by `whale_pair_flat_shells_are_terminal_native_without_erasing_semantic_surfaces`. - The ink goldens' legend reads `a reset on reset`. - OceanTreatment::Flat is the default; Deepsea repaints Reset cells through OceanRamp::for_theme, which matches the whale pair by name + Reset shell. The reviewer's citations (tokens.rs:6/:250/:465) are the token definitions deepsea and the semantic surfaces still need, not the theme. What was not true: ~90 direct `bg(palette::WHALE_BG)` paints in pickers, overlays and full-screen views (provider_picker 14, views/mod.rs 11, user_input, live_transcript, help, session/file/model pickers ...) bypass the theme, and `adapt_bg_for_theme` only remapped them for `theme_remap_active` presets. On the whale theme they laid navy patches over the terminal ground. Rung 2 fix, one rule in palette/adapt.rs: the field (`WHALE_BG` / `BACKGROUND_DARK`) always follows `ui.surface_bg` — Reset on the whale pair, the user's `background_color` override when set, the preset surface elsewhere. Panels, selection, elevation, error and diff surfaces are untouched; no widget file changes. `underwater` is now an accepted alias of `deepsea` in settings.rs (normalize + `set`), OceanTreatment::parse and the config_ui serde enum. Tests extended in place; the color_compat light test now expects the Reset shell it already had for theme consumers. DESIGN.md "Field" says the TUI ground is the terminal's own background and the navy field is deepsea-only. Contrast, all whale text/accent tokens on #000, #1e1e1e (VS Code), #282c34 (One Dark), #002b36 (Solarized dark), #300a24 (Ubuntu), #0d1117 (GitHub dark), #282a36 (Dracula): body 12.5-18.8:1, soft 7.7-11.5, muted 5.3-8.0, hint 4.9-7.3 (floor 3:1), action 5.4-8.1, human 8.6-12.9, live 7.5-11.3, error 6.2-9.3, warning 5.5-8.2, green 8.2-12.2, reasoning 5.9-8.8. Only `border` (#2A3F72) is low, 1.4-2.1:1: a non-text hairline. No token value changed. Seen, tmux 80x24 PTY, TERM=xterm-256color COLORTERM=truecolor, hermetic HOME, debug build, counting `48;2;R;G;B` background sequences: default (Terminal theme): startup, /theme picker, Help — no painted background before or after (picker shows only accent swatches). Blue Stage selected via T/Down/Enter, then F1 Help: before: 15 x `48;2;7;12;29` (WHALE_BG) + 1 x selection row after: 1 x `48;2;30;60;143` (selection row only) Startup stage on Blue Stage: none, before and after. Evidence (CARGO_BUILD_BUILD_DIR=.../mega-tokens, RUST_MIN_STACK=16 MiB as CI): cargo check -p codewhale-tui --all-targets -> Finished, 0 warnings cargo test -p codewhale-tui --lib --locked -- color_compat palette::tests:: ocean:: ocean_treatment live_transcript views::tests startup_ink --skip command_palette -> test result: ok. 238 passed; 0 failed cargo test -p codewhale-tui --lib --locked (full) -> test result: FAILED. 11901 passed; 7 failed; 13 ignored 1 was this change (color_compat light test, updated above); the other 6 are role-name / slash-list assertions from other lanes on this branch (scout<->explore, worker<->general, slash.impeccable) and untouched. Ink goldens unchanged. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tests(palette_audit): re-pin whale roles to the retuned palette `whale_roles_are_pinned_and_non_colliding` still pinned the pre-navy values (WHALE_BG (3,7,13), ACTION (106,174,242), ...) and failed on this branch before the token slice touched anything. Pins now match tokens.rs; no colour value changes. cargo test -p codewhale-tui --test integration --locked palette_audit -> test result: ok. 3 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui/cli/web: fleet is the public product term; /pod, codewhale pod stay aliases Founder decision 2026-09-01: "fleet" is the customer-facing name for the assembled model team and "Pod" is retired from product copy. `/fleet` is the canonical slash command and `codewhale fleet` the canonical CLI verb; `/pod`, `codewhale pod`, `loadout`, and `party` remain parser aliases. Storage keys, the ledger file name, config tables, protocol identifiers, and MessageId variant names keep their current spelling. - CommandInfo name/aliases/usage, help text, and the unknown-verb error flip to /fleet; `/fleet fleets` (saved/manage) is the saved-fleet picker with `/fleet pods` kept as an alias. - All 15 locale packs: localized values say fleet; the settings goldens follow. `KbCompleteCycleModes` names the modes as Plan → Work → Operate (Act is only a compatibility alias per docs/MODES.md). - `scripts/check-tui-product-vocabulary.sh` now rejects `Pod` in en.json instead of rejecting `fleet` in every pack. - Hotbar id `slash.fleet` is canonical; persisted `slash.pod` normalizes. - Fleet store error prose says fleet. - Docs: PRODUCT.md lists the current role tokens (general, explore, planner, reviewer, implement, test, advisor, custom) and names the old spellings as aliases; docs/FLEET.md uses one role vocabulary; web/lib/content/vocabulary.ts ADVISORY_ROLE is Advisor with consultant/ oracle as the legacy spellings (matches fleet/profile.rs migration). Evidence: sh scripts/check-tui-product-vocabulary.sh -> exit 0 cargo test -p codewhale-config -p codewhale-lane --locked -> 638 passed; 0 failed / 62 passed; 0 failed cargo test -p codewhale-cli --locked -- fleet pod -> 3 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- fleet::store fleet::members fleet::identity -> 24 passed; 0 failed cargo test -p codewhale-tui --lib --locked -- groups::core::fleet localization command_palette hotbar fleet_roster settings widgets fleet::control pod_workers -> 605 passed; 1 failed (the failure is slash_source_matches_command_palette_command_entries, which reads the machine's ~/.claude/skills and finds an `impeccable` skill; it fails identically without this change) cd web && npm test -- lib/content/vocabulary.test.ts -> 11 passed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * chore(tui): clear the six clippy 1.98 errors the base lanes left needless_borrow on provider_identity_for_persistence (five sites) and a collapsible_if in the work-surface mouse path. No behaviour change. * tui(composer): restore double-tap Enter as the send-now gesture While a turn is running, the first bare Enter queues the message (as before) and opens a 500 ms window (`App::DOUBLE_TAP_WINDOW`, the value the removed code in c5c42b7d91 used). A second bare Enter inside that window with an empty composer promotes the just-queued message to a Steer through `attempt_steer_with_queue_fallback` — the same path Ctrl+Enter takes, so there is one steering path. A second Enter with new text is an ordinary queue; Ctrl+Enter still steers immediately; outside a turn Enter is unchanged. `enter_with_double_tap` is the one decision point again (`take_queued_for_double_tap_steer` routes through it), and `submit_disposition_does_not_mutate_the_queue` stays true. The posture bar advertises the gesture while the window is open (`PostureHintEnterAgain`, next commit). Tests (cargo test -p codewhale-tui --lib <filter> --locked): double_tap: test result: ok. 3 passed; 0 failed enter_with: test result: ok. 5 passed; 0 failed submit_disposition: test result: ok. 6 passed; 0 failed Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * tui(shell): one owner per fact — posture bar, metrics line, no dead hints Design: SHELL-DESIGN-20260901 §2.0 item 3, §2.2, §2.3, §2.3b, §2.11 and the founder's 2026-09-02 redirect (Claude Code's grammar, less always-on information). Under the composer there are exactly two chrome rows in the default state, then the work surface only when it has content: ▶▶ ask (Shift+Tab) · work (Tab) · 2 agents · Esc to interrupt /rc … deepseek-v4 · ctx 61% · $0.42 · ttft 400ms · 40 tok/s · ↓ 1.2K Ctrl+/ help Fact → owner, before → after (composed 80x24 / 120x32 frames, working turn with two sub-agents; "strip" = the work-surface bottom view): fact before after context % info line metrics line cost footer (+ info line when priced) metrics line model info line metrics line provider info line (wide) metrics line (wide) ttft / tok/s / ↓ behind /cost only metrics line repo slug info line (+ idle empty state) launch header / git view (not chrome) branch info line (+ idle empty state) launch header / git view (not chrome) mode footer posture bar permission footer posture bar phase word footer ("sub-agents underway") transcript active row (not chrome) elapsed footer ("1m 15s") roster rows (per agent) agent count indicator row + info "pod 2/2" + "whales 2/4" posture bar ("2 agents") + dock tab + strip header (+ dock tab, strip header — other slice) task/shell count indicator row above the composer posture bar help hint footer keys legend (F1) + info line (Ctrl+/) metrics line (Ctrl+/), from the binding other key hints footer "⌥V:output", compact "? help" none; cycle keys next to the chip they cycle live hint footer "Esc to interrupt" posture bar hint slot ≥80 % microcopy footer right slot posture bar hint slot (outranks the hint) notice / rc footer right slot / — posture bar right slot Dead key hints removed: `F1:keys` / `fn+F1:keys` (Help binding's `footer_chord` is now `Ctrl+/`; `info_help_hint` derives from the binding), compact `? help`, and the `footer_action_hints` family. The mode/permission cycle keys print only when the binding table admits them at the current focus (no `(Tab)` on the launch stage). Row order: composer → posture bar → metrics line → roster/to-do. The #5286 background-work chip above the composer is gone (it repeated the posture bar's counts); `PendingWork` stays as the counts' source. Goldens re-blessed and read: footer_* (posture bar), infoline_startup_*, infoline_work_* (metrics line), settings_* (the settings preview's bottom row); infoline_settings_* deleted with the settings-path segment. Commands run (CARGO_BUILD_BUILD_DIR=…/mega-frame, RUST_MIN_STACK=16777216): cargo check -p codewhale-tui --all-targets clean cargo test -p codewhale-tui --lib infoline --locked test result: ok. 11 passed; 0 failed cargo test -p codewhale-tui --lib tideline_tests test result: ok. 64 passed; 0 failed cargo test -p codewhale-tui --lib one_owner_tests test result: ok. 4 passed; 0 failed cargo test -p codewhale-tui --lib shell_key_routing test result: ok. 13 passed; 0 failed cargo test -p codewhale-tui --lib localization::tests test result: ok. 49 passed; 0 failed cargo test -p codewhale-tui --lib --locked test result: FAILED. 11893 passed; 8 failed (config_panel golden re-blessed after; the other 7: 4 fail on HEAD without this change (fleet rename in flight), tmux clipboard passes alone, none in files this change touches) cargo clippy … -D warnings 6 pre-existing errors, none in this change's hunks (config.rs:2106/2796, apply.rs:759, event_loop.rs:464, session_state.rs:1004, work_surface/input.rs:401) Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(launch): checkpoint for overnight takeover — braille mark + kitty tier + Claude-Code launch header compile and pass lib tests; PTY cucumber tests still wait on the old heading Compiles (cargo check --all-targets clean). Lib tests for mark::, underwater::, mouse_ui::, localization:: pass: test result: ok. 120 passed; 0 failed (needs RUST_MIN_STACK=16777216 like scripts/dev-test.sh; the rust_i18n static overflows a 2 MiB test thread with or without this change). Startup goldens re-blessed and read. Clippy is red only in files outside this slice (config.rs, apply.rs, session_state.rs, work_surface/input.rs, and a pre-existing event_loop.rs borrow). Not done: crates/tui/tests/cucumber/{screen_mode_inline_pty, active_composer_pointer_pty,plugin_e2e_acceptance}.rs still wait for "What are we working on?" and press 'w'; they need the new marker ("Codewhale v") and a typed message + Enter to begin the session. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(rail): checkpoint for overnight takeover — dock views compile, 136/137 work_surface tests pass, files/notepad/git views are stubs Foundation for the one bottom dock (founder redirect 2026-09-02): RailPanel is now the eight-view cycle (agents, tasks, background, files, notepad, context, git, price; Pinned folded into tasks), an auto rule opens agents/tasks/background while they have content, explicit picks stick until Esc, and Ctrl+Tab / Ctrl+] (fwd) + Ctrl+Shift+Tab (back) cycle. Context and price views render as rows; files, notepad, git are stubs in views.rs. The classic sidebar line panels and their dead consumers are deleted. Known: agent_rows_show_role_assignment_and_open_the_agent_transcript fails (role_label 'worker' vs 'general'); role derivation is untouched here and the failure is believed to predate this work — unverified. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(operate): checkpoint for overnight takeover — auto-goal + contract land; one Operate approval test needs a goal-complete mock Operate now turns a non-trivial prompt into the goal through the same GoalState::create path as explicit_goal_directive, appends the Operate contract once as a user-role runtime message (append-only history, not the prefix), shows the Operate goal receipt, and carries the new mode copy in all 15 locale packs plus docs/MODES.md. Compiles. Passing: goal (134), prompts (133, incl. every_mode_shares_one_prompt_per_host), localization (49), runtime_handoff (14), session_peek (15), history_cells (2), both new engine tests. Known failing: core::engine::tests::operate_model_shell_uses_normal_approval_and_workspace_sandbox — its mocked model never reports the auto-set goal complete, so the turn re-prompts to max_steps (wiremock expect(1) sees 199). Six clippy needless_borrow/collapsible_if hits pre-exist on the branch base. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * wip(fleet): checkpoint for overnight takeover — #5815 review findings 1-9 fixed, compiles, fleet tests green Findings against the fleet-as-models work (verified against the current tree, then fixed): 1. `toggle_fleet_model` decides presence by member rows, not the projected role list (a role-less row projects to no role, so the old `all(== "operator")` was vacuously true). Regression test `toggle_removes_a_role_less_member_row` fails on the previous commit ("got Unchanged { … operator route … }") and passes now. 2. `selected_or_default` loads an existing personal `My fleet` instead of overwriting it and never writes or selects before the add succeeds; `FleetModelChange::Added` carries `created_fleet` + `selected_fleet`. 3. `fleet_models` returns `Result<Vec<_>, FleetStoreError>`: a broken explicit selection is surfaced in `/fleet models`, `/models`, and the picker's ⇧F instead of reading as "session model only". 4. `add_fleet_model` dedupes roles (case-insensitive) and returns `Unchanged` without touching the file when every role is present (test compares bytes and mtime). 5. `App.config` startup snapshot removed. `/fleet add|remove` now return `AppAction::FleetAddModel|FleetRemoveModel`; the UI arm validates the provider against the live `Config` (`fleet_provider_rejection`, `fleet_catalog_rejection`, re-exported from `commands`). 6. ⇧F applies the same provider gate as `/fleet add`. 7. One roster path: `sync_fleet_roster` (extracted from the FleetStoreChanged arm) plus `App::fleet_roster_stale`, flushed once per event-loop iteration; `/fleet add|remove`, ⇧F, and every UI-side auto-enroll site set it (`auto_enroll_fleet_model` now returns bool). 8. ⇧F receipts go through `push_status_toast` (Success/Info, 6 s) and `set_sticky_status` (Error); no new `status_message` writes. 9. All new fleet prose is `tr(locale, MessageId::Fleet…)` (27 keys, translated in all 15 packs); `FleetModelError` is typed with a localized `message(locale)`. 10. No stale "`a` in /models" doc comment exists in the current tree. Also re-blessed `config_panel_{80x24,120x32}` goldens (the Config tab label says Fleet); the diff is that one label. Evidence (this tree): cargo check -p codewhale-tui --all-targets --locked -> Finished cargo test -p codewhale-tui --lib --locked -- fleet::members groups::core::fleet model_picker format_helpers fleet_roster localization golden hotbar command_palette fleet::store -> 257 passed; 1 failed (slash_source_matches_command_palette_ command_entries: reads ~/.claude/skills and finds `impeccable`; fails identically on main in this environment) cargo clippy … -D warnings (CI flags) -> the only remaining error is crates/tui/src/tui/work_surface/input.rs:401 collapsible_if, which belongs to the work_surface lane and predates this commit cargo fmt --all -- --check -> clean sh scripts/check-tui-product-vocabulary.sh -> exit 0 Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HSVsAXZJnKGZmqkwH1CeKH * feat(tui): launch card, canonical role vocabulary, DashScope descriptor, test fixes - Launch is now our own card take (founder, 2026-09-02): thin top line ⑂ branch path; centred bordered card with the whale mark, Codewhale + version, one true announcement (no-model warning / MCP news), and the menu New worktree / Resume session / Changelog / Quit with real chords right-aligned; Enter runs the highlighted entry, Up/Down move it, and typing goes straight to the composer. The card dissolves on the first keystroke or command (≤240ms, instant under reduced motion); the working screen then shows ⑂ branch path + ⋮ MCP n/m, the session_start receipt, and the posture bar + metrics line (hidden while the card is up). The composer's bottom rule carries model (effort) · permission — the route's one launch reading. - Role vocabulary: fixtures and the stopship fleet/workflow now use the canonical tokens (explore/implement/reviewer/test); the workflow JS wire accepts canonical spellings with the pre-rename ones as aliases (AgentType serde rename+alias, serialized form is canonical). - Alibaba Model Studio (DashScope) joins the data-driven descriptor table: international compatible-mode endpoint, DASHSCOPE_API_KEY, live /v1/models as the Qwen model authority (never a compiled id). - Tests: role-keyed gate fixtures moved to canonical tokens; the operate model-shell test now seals the goal through the deferred update_goal tool (deferral retry included) instead of pausing blindly; the slash-source hotbar test isolates HOME; ⚠ and ⋮ gained ASCII fallbacks; launch goldens re-blessed for the card. * feat(tui): retire Pod from copy; canonical workflow fixture; gate clean-up - Pod literal sweep across fleet views, worker runtime, sub-agent tool, managed API, and command groups: user-facing copy now says Fleet (founder vocabulary decision; /fleet canonical, /pod and 'codewhale pod' stay as compatibility aliases). Roster tests that encoded the retired Pod-public/Fleet-internal split now assert the public Fleet vocabulary. - workflows/stopship + fleets/stopship use canonical role names (explore/implement/reviewer/test); the workflow crate's own stopship tests and required-roles list follow. - Operate mode-picker hint shortened to fit 80 columns in every locale. - Cucumber PTY launch flows: wait for the launch card, type the first prompt and press Enter; the live shell is proven by the launch stage's top line disappearing and the metrics line's ctx reading (the interrupt hint needs a live turn, which an offline route never starts). The stopship acceptance feature expects the canonical /fleet help copy. - CHANGELOG receipts synced; DESIGN.md shell direction records the card, posture bar + metrics line, and the bottom view cycle. * test(cucumber): launch-card PTY contract fixes - The launch-card wait uses the menu's New worktree entry — unique to the card; the bare wordmark also matches onboarding copy. - The live-shell proof is the launch stage's top line disappearing plus the metrics line's ctx reading; the interrupt hint needs a live turn, which an offline route never starts, and the help hint sheds first at the 40-column floor by design (SHELL-DESIGN-20260901 §2.2). - The pointer-submit queue proof takes the offline onboarding seed into account: the receipt toast proves the gesture, and the queue count grows by exactly one. * docs(readme): restore the canonical product screenshot the web contract pins The brand header redesign dropped the assets/screenshot.webp embed; the web public-surface contract pins the README and the website to one canonical optimized screenshot (byte-identical, 1562x1256 lossless VP8L). Re-embed it. * test: platform-robust pointer-submit wait and cap-warning diagnostics - The pointer queue proof accepts either the transient receipt toast or the queue-count increment: toast timing differs across runners, and a 20 s wait missed a toast the queue dump proved had fired. - The context-cap posture test dumps the drawn rows when the warning count misses, instead of a bare 0 != 1, so a platform-specific shed (the hint sheds first when the left run exceeds its budget) is visible in CI. * test: fix the linux-only context-cap shed; bounded pointer-click retry - The context-cap posture test drew at 100 columns, where a backend-less platform (linux CI paints 'files: workspace (unenforced)') sheds the cap hint first, so the warning count read 0. Draw at 140 columns, where the hint survives with the notice present; verified locally. - The pointer queue proof retries the [↑] click once, re-finding the affordance first: under runner load a redraw can shift cells between the find and the click, so the first SGR gesture lands nowhere. * fix(gates): tool-catalog budget covers the fleet rename; readme stamps; pointer baseline - The Pod->Fleet sweep grew every mode's tool-schema surface by 58 bytes (+14 tokens). The receipts are re-measured and the one-way ceilings in scripts/runtime-contract-budget.json are raised to them as the explicit maintainer decision the gate asks for (the rename is the founder's 2026-09-01 vocabulary call). - The README screenshot embed changed README.md; the 18 translated READMEs re-stamp (the embed is language-neutral HTML - no prose changed, so no retranslation was needed). - The pointer queue baseline is captured while the composer is empty: the pending preview row hides while a draft sits in the composer, so the pre-click depth read None and the growth proof could not fire. * test: re-click then keep polling until the deadline The qa_harness Instant wrapper does not implement Div, and the retry's single read raced the app processing the second gesture: poll to the full deadline, re-click once at the half-way point. * test: pointer queue diagnostics (baseline/expected/last-seen) in the failure output * test: pointer poll keeps per-iteration state only (unused-assignment gate) * fix: Copilot review findings — planner wire spelling and Advisor copy - workflow::AgentType::Plan serializes as the canonical 'planner' ('plan'/'awaiter' stay accepted aliases), matching the FleetRole vocabulary the mega PR declares. - Web: the vocabulary docs metadata, the vocabulary module header, and the docs-map topic description say Advisor (the public advisory term) instead of the retired Consultant spelling. - Polish home dictionary: restore 'Podwodna powłoka terminala' — the fleet-vocabulary sweep had merged 'Fleet' into the compound word 'Podwodna' (underwater), producing the non-word 'fleetwodna'. * test: pointer proof accepts preview-appears when no baseline count is painted * test: the tolerant preview-appears proof (the arm the last commit missed) --------- Signed-off-by: CodeWhale Bot <bot@codewhale.net> Signed-off-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: CodeWhale Bot <bot@codewhale.net> Co-authored-by: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com> | 3 天前 | |
feat: rename sidebar/rail to workbar, bottom default, /workbar command | 3 天前 | |
feat(telemetry): accept disclosed default-on usage policy without fabricated consent Add closed schema3/notice_version5 ingest and generated CWC contract. Preserve original v1 first-party-only and v2/consent4 semantics, reject mixed policy fields before storage or forwarding, and retain IP/host/operator/content guards. Existing Analytics Engine column positions remain fixed; schema_version distinguishes old consent from new notice metadata. Document the founder's amended default-on/opt-out policy and preserve prior declines. Rust/app preference changes are integrated separately. Validation: ingest 171 passed, 0 failed across 6 files; TypeScript, facts, 23 documentation topics and git diff checks passed. Original validator rejects the new v3 fixture; current validator accepts v2 and v3. Proposed Rust v3 fixture accepted by ingest; sender proof pending Rust integration. Root npm test && npm run check:web exits1 because no test script exists (0 tests, check:web not reached). No hosted deployment, processor activation or runtime-installed policy change claimed. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 天前 | |
feat: general lifecycle outbox — JSONL + webhook, turn_start/stall/failed events Add an opt-in, machine-readable lifecycle event outbox for supervisors and automation harnesses. Unset/empty config = feature OFF = behavior unchanged. Config ([lifecycle_outbox]): - path — JSONL outbox file (unset/empty disables the feature) - webhook_url — optional webhook endpoint; POSTs only when set - webhook_token — optional bearer token for webhook_url Writer (crates/hooks/src/lifecycle_outbox.rs): - One JSONL line per event in the existing RuntimeEventEnvelope shape (schema_version, seq, event, kind, thread_id, turn_id, item_id, timestamp, created_at, payload); append + flush per event. - seq monotonic per file; recovers from the last complete line on open via a bounded 64 KiB tail scan (torn trailing lines ignored). - Single non-blocking writer task: emit() enqueues; no tokio runtime available => drop with warning. - Payloads only from bounded, pre-redacted fields (headline ≤ 80, detail ≤ 120, preview ≤ 200 chars; control bytes stripped). Signed-off-by: M-Maciej <130112810+M-Maciej@users.noreply.github.com> | 10 天前 | |
web: record v0.9.12 as the published release sync-latest-release wrote v0.9.12 (2026-09-05T09:59:53Z) to both facts files; derive-facts regenerated. Trust, FAQ, roadmap, and the facts telemetry line now say the earlier 0.9.11 release asked first, since 0.9.12 is the published release. Website vitest 407 passed; locales, facts OK. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01Bs5x11yXAg3sJ4giZf4krF | 1 天前 |