| Files | Last commit | Last update |
|---|---|---|
feat(web): the homepage whale starts as the mark and comes alive as lights [skip ci] The codewhale.net hero now tells the living mark's story with its existing, owner-approved pieces: the flat C-curl mark (drawn by the vendored kit's WhaleRig.build("mark") in brand navy #142352, reversed on dark) holds for 700 ms, the live canvas whale fades in as the colored-in whale for 2.4 s, then 64 beads of light assemble head first and keep breathing, swimming, hovering and carrying a soft light crest at 12 paints per second. Pointing at it, or picking a terminal view (the existing cueWhale path), brings the whale back; it returns to lights 600 ms after the pointer leaves or 15 s after a pick. The intro plays once per browser session. The canvas whale sleeps (no frames) while the lights show; the lights pause when off screen or hidden. Under reduced motion the hero keeps the still whale and draws no lights. Before the client decides, the hero is hidden briefly so the character no longer flashes before the mark; without JavaScript it appears after 1.2 s. The beads come from web/vendor/whale-lights/whale-lights.json, an unchanged copy of codewhale-app assets/whale-lights.json at 55c9ba0c (SHA-256 recorded), the same file crates/tui-kit pins for the terminal. web/lib/whale-lights.ts restates the app's drift, crest and seeded-star formulas (about 60 lines) because the app source is private (CURRENT_DECISIONS 44); PROVENANCE says to change the three together. lib/whale-motion.ts exposes the vendored WhaleRig. Verified: tsc --noEmit clean; ESLint clean on the five changed TS/TSX files; vitest 74 files, 770 tests passed (design-grammar contract included, which moved the new timings onto the spring tokens and the fallback keyframe behind a motion preference). next dev on 3241 in the browser pane and in Electron's Chromium via Playwright: stages mark (0.3 s) -> whale (0.9-1.7 s) -> lights (3.3 s+), beads move between reads, no console errors; with reducedMotion reduce the stage stays whale, lights are display:none and nothing moves. Not deployed; codewhale.net is unchanged until a founder-authorized deploy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 day ago | |
feat(web): the homepage whale starts as the mark and comes alive as lights [skip ci] The codewhale.net hero now tells the living mark's story with its existing, owner-approved pieces: the flat C-curl mark (drawn by the vendored kit's WhaleRig.build("mark") in brand navy #142352, reversed on dark) holds for 700 ms, the live canvas whale fades in as the colored-in whale for 2.4 s, then 64 beads of light assemble head first and keep breathing, swimming, hovering and carrying a soft light crest at 12 paints per second. Pointing at it, or picking a terminal view (the existing cueWhale path), brings the whale back; it returns to lights 600 ms after the pointer leaves or 15 s after a pick. The intro plays once per browser session. The canvas whale sleeps (no frames) while the lights show; the lights pause when off screen or hidden. Under reduced motion the hero keeps the still whale and draws no lights. Before the client decides, the hero is hidden briefly so the character no longer flashes before the mark; without JavaScript it appears after 1.2 s. The beads come from web/vendor/whale-lights/whale-lights.json, an unchanged copy of codewhale-app assets/whale-lights.json at 55c9ba0c (SHA-256 recorded), the same file crates/tui-kit pins for the terminal. web/lib/whale-lights.ts restates the app's drift, crest and seeded-star formulas (about 60 lines) because the app source is private (CURRENT_DECISIONS 44); PROVENANCE says to change the three together. lib/whale-motion.ts exposes the vendored WhaleRig. Verified: tsc --noEmit clean; ESLint clean on the five changed TS/TSX files; vitest 74 files, 770 tests passed (design-grammar contract included, which moved the new timings onto the spring tokens and the fallback keyframe behind a motion preference). next dev on 3241 in the browser pane and in Electron's Chromium via Playwright: stages mark (0.3 s) -> whale (0.9-1.7 s) -> lights (3.3 s+), beads move between reads, no console errors; with reducedMotion reduce the stage stays whale, lights are display:none and nothing moves. Not deployed; codewhale.net is unchanged until a founder-authorized deploy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 day ago | |
docs(release): fold the 0.10.3 staging entries into the dated release section The release heading is the top CHANGELOG section again, dated 2026-11-08, with the Runtime API agent discovery and provider-key check entries under Added and the website polish under Fixed. Regenerates crates/tui/CHANGELOG.md and web/data/agent-docs.generated.json. Verification: scripts/sync-changelog.sh; scripts/release/check-versions.sh --require-dated-release (version state OK); scripts/check-contributor-credit.py (15 contributors, all credited); cd web && npm run check (lint, tsc, build). | 2 hours ago | |
feat(runtime): reconcile reviewed plugins and unify native account setup [skip ci] Restore missing plugin stages only from receipt-matching bytes under the existing state writer, with generation and policy checks. Refuse changed existing stages. Reuse normal reload/MCP invalidation for explicit restage; add read-only shell status and bounded authenticated DSH asset grants. Expose current-server MCP backoff without treating an absent backoff as health. Share profile-scoped Rust account custody across terminal and native hosts, keep local provider setup optional, and make ordinary logout session-only. Fence browser imports and cleanup by exact revision; preserve ambiguous or newer sessions. Keep definitely unadopted device grants in cleanup custody. Validation: six-crate Mac all-target check exit0, 4,270 source entries unchanged, 35m37s, no disk stop. Grok Linux raw evidence verified: secrets account6 and plugins202 passed, one existing real-home rehearsal ignored; all4,270 entries exactly matched that Mac freeze. Existing command-crate boundary gate passed; 2,816 keys complete in all15 TUI locales. The subsequent two-file private account cleanup has independent source review and exact pre/post hash checks; Linux verification is in progress. Only that cleanup and the already-landed visual-change changelog entry differ from the passing Mac compile snapshot. No new tests or code comments added. Qualification is incomplete: production recovery/asset HTTP smoke, published plugin, Electron, live sign-in, cross-platform/package and final release gates remain. This local candidate commit is not a release or publication. | 1 day ago | |
docs(web): explain plugins and MCP with verified Computer Use setup [skip ci] Answer the integration chooser, actual catalog prerequisites, supported plugin formats, direct-versus-plugin MCP authentication and troubleshooting on the existing paper/blue pages. Link the plugin guide from docs navigation and refresh its plain-text index. Add explicit Computer Use GitHub/contributor links in all18locales and version-aware direct-MCP setup for published CLI0.10.2, whose older built-in bundle is not upgraded by catalog installation. Reconcile repository EN/ZH docs for config precedence, validation/reload, URL-only servers, environment credentials, trust hashes, pinned-source updates and catalog freshness. Current marketplace and unreleased source remain separate from installed-release claims; DSH and MCPApps are not presented as universally qualified. Verified locally:47existingwebtests passed (26dictionary/copy+21llms/docsIA); focused ESLint, TypeScript, locale/GT checks and diff check passed. Initial custom test harness missed Vite alias configuration in2suites; corrected harness passed those21checks. Desktop1280/mobile390 EN/ZH browser review passed; stale development module hydration mismatch cleared after owned dev-server restart. Published CLI0.10.2 discovered current CU0.16.1 tools and executed request_access through a local synthetic model:ok=true/viaapp, accessibilitygranted, screen-captureprobeok. No input or provider spend. Credential-free Cloudflare Docs MCP discovery listed2tools. Existing-helper setup is not clean-Mac/app-task qualification. Generated agent documentation uses51hashedinputs: our5revieweddocs plus committed da143039f79 content for all other inputs, excluding active peer GUIDE/feature/native drafts. Full clean web validation/deployment follows this frozen commit; no Engine release qualification. CU setup README is carried separately by codewhale-cu-plugin afb98e8. Evidence:CW/artifacts/plugin-mcp-discoverability-20261107. Tracking:CW-7848; CU acceptance remains CW-6732. | 1 day ago | |
fix(release): clear the two clippy collapsible_if errors; credit the two 0.10.3 reporters on the website Hosted Lint and the release-candidate Parity job failed on 072468aff2 with clippy::collapsible_if in crates/config/src/catalog.rs and, behind it, crates/tui/src/tui/provider_picker.rs. Both are flattened with let chains, same order and short-circuit. The web credits-parity test failed because @cmdcorp6534 and @Asteria1028 are in the 0.10.3 changelog ledger but not in the website release helpers or the docs/CONTRIBUTORS.md v0.10.3 band; both added. Verified locally: cargo clippy --workspace --all-targets --all-features --locked -D warnings (CI flags) exit 0; cargo fmt clean; web vitest public-copy 6 passed; check-contributor-credit passes. Hosted CI not rerun yet. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> | 17 hours ago | |
Add mixed-material merch collection and private interest signup Visitors can choose cotton tees, stretch ombre/polo/hoodie styles, desk gear and the planned doll, then optionally give CNY/USD item-price feedback. Eight apparel styles retain the Ocean Wave mascot and a separate contributor at-cost flow; all purchase/supplier gates remain disabled. Signup awaits durable CURATED_KV, validates bounded same-origin requests, records explicit unverified opt-ins for 180 days, and applies native 5/min limits. Owner-session admin read/delete has no public contact/count path. No campaign service, live payment, supplier order or deployment is enabled. Validation on wave/0.10.1-next: - npm test: 1266 passed, 7 existing skips (101+19+384+762). - npm run check:web:PASS (facts/docs/tokens/ESLint/TypeScript/production build). - Source interest suite: 38/38 passed; source/assets match reviewed slice. - Native Workerd persisted local KV through restart; sixth request 429. - Full OpenNext local preview:EN/ZH 200, availability true, synthetic save 200, stored server-derived budgets; unauthorized admin 401. - Browser administration-policy verification unavailable; no new rendered interaction or screenshot proof. Existing DraftClaimLock, model settings, dependencies and auth safeguards are preserved. Contributor-language and delivery/artwork routes still need quotes and physical samples; survey prices exclude shipping/tax. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 month ago | |
fix(cli): remove the marked PATH block and Codewhale completions on uninstall A receipted release copy of codewhale uninstall --yes removed its program files but left the user to hand-delete the PATH lines and completion files the installer had told them to create. #7091 asks for a complete, verifiable uninstall; this completes the shell half of it. Uninstall now plans and applies two extra removals, both scoped to this install and gated on the same receipted copy that owns the program files: - This install's exact three-line # >>> codewhale PATH >>> block, in the same profile list the old report walked. The block is only matched when its middle line names this install directory, so another copy's block and a bare export PATH=… line the user wrote are never touched. The profile is edited by staging replacement bytes and renaming the original aside, so a failure installing the replacement restores the user's own file by name; a symlinked, unreadable or non-UTF-8 profile is reported and skipped. The profile's mode is adopted before the guard captures it, since GuardedFile pins ctime. - The Codewhale-generated completion files at their documented paths, honouring XDG_DATA_HOME and XDG_CONFIG_HOME. They are kept while another Codewhale copy remains on PATH, because a second install still wants them. Cleanup failures after the program is already gone are reported individually and exit non-zero rather than being silently swallowed. --help/dry-run prints Would remove and changes nothing. The installers still never edit shell profiles themselves; they now print the PATH line as that marked block, so there is something provably ours to remove. A bare export PATH=… line from an older install remains the user's. Verified: cargo test -p codewhale-cli --lib update:: 109 passed / 0 failed (269 filtered); vitest run lib/public-installer-contract.test.ts 25 passed, covering the printed marker block for zsh/bash/dash and the unrecognised-shell case. Release build of codewhale-cli clean, no warnings. Not verified: no real Windows host, no installed release artifact, and no run against a profile this repository does not own. Refs #7091 | 8 days ago | |
fix(web): send old-domain redirects to https only The deepseek-tui.com redirect worker kept the request's scheme when it swapped the host, so a plain-http request to the old domain was redirected to http://codewhale.net/... instead of https. The worker now sets the scheme to https before it sets the host, so every redirect from the old domain lands on https://codewhale.net with the same path and query. Evidence (source and local only; the worker is not deployed by this change): - A scratch harness outside the repository imports web/redirect/src/index.ts and calls fetch() for two http inputs and one https input. Before: 2 of 3 Location headers were http (exit 1). After: 3 of 3 are https (exit 0). - eslint redirect/src/index.ts: exit 0, no findings. - tsc --noEmit --strict on redirect/src/index.ts: exit 0. - No existing test covers this worker and none was added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 days ago | |
fix(security): bound web dependency glob work with compatible backports [skip ci] Backport upstream minimatch preprocessing and glob abort fixes while keeping existing glob, ESTree and build-tool APIs. The rejected minimatch 11 override silently enumerated no files with real glob 9/12 consumers. Preserve versions, licences, original lock bytes and complete upstream audit findings. Postinstall verifies exact versions and complete original/patched hashes for all declared distributions and four bundled runtime copies. The audit checks all concrete reachable advisory leaves and rejects unknown/missing findings, changed sources and pure cycles. Legacy minimatch 3 lacks the reported path. Verified fresh scripts-enabled npm ci (896 packages),7 existing security cases, targeted ESLint, 54 manual preprocessing/abort/bundle/offline-load controls and 7 real glob/ESTree/legacy consumer observations on Node 22.20.0. All 12 matching runtime files accounted for; official archives matched lock SRI. Actual abort controls observed zero reads after rejection. Public NFT tracing preserved 4 files/0 warnings; its private cancellation remains source/hash proof. Raw audit retains 18 moderate package findings; verified mitigation wrapper passes, alert #244 remains OPEN. No registry-fixed, alert-dismissal, full web validation, hosted CI, provider, deployment or release claim. Refs CW-6949/#6560. Evidence: CW/artifacts/engine-0103-qualification-20261101/minimatch/RECEIPT.json Upstream: isaacs/minimatch 77a0f5c and isaacs/node-glob 4682e8c. Co-authored-by: isaacs <i@izs.me> | 7 days ago | |
fix(catalog): apply signed online facts through the existing provider lake Preserve exact route, expiry, signature, provider facts and billable price authority. Explicitly attested preview IDs can be supplied without inventing sibling capabilities. Correct models.dev enrichment provenance and reuse the existing catalog owner. Add public-only monotonic fact publication storage; trusted production signing keys remain unconfigured and no service was activated. Root validation: 858 Rust config/provider/pricing tests passed, 0 failed (12733 unselected); 26 web cloud-facts tests passed, 0 failed; check:facts passed with 0 active production keys; disposable PostgreSQL publication tests passed all 7 assertion sections with rollback and clean shutdown. cargo fmt and git diff --check passed. Hosted CI, signing/deployment and live provider acceptance remain separate and pending. | 1 month ago | |
feat(web): the homepage whale starts as the mark and comes alive as lights [skip ci] The codewhale.net hero now tells the living mark's story with its existing, owner-approved pieces: the flat C-curl mark (drawn by the vendored kit's WhaleRig.build("mark") in brand navy #142352, reversed on dark) holds for 700 ms, the live canvas whale fades in as the colored-in whale for 2.4 s, then 64 beads of light assemble head first and keep breathing, swimming, hovering and carrying a soft light crest at 12 paints per second. Pointing at it, or picking a terminal view (the existing cueWhale path), brings the whale back; it returns to lights 600 ms after the pointer leaves or 15 s after a pick. The intro plays once per browser session. The canvas whale sleeps (no frames) while the lights show; the lights pause when off screen or hidden. Under reduced motion the hero keeps the still whale and draws no lights. Before the client decides, the hero is hidden briefly so the character no longer flashes before the mark; without JavaScript it appears after 1.2 s. The beads come from web/vendor/whale-lights/whale-lights.json, an unchanged copy of codewhale-app assets/whale-lights.json at 55c9ba0c (SHA-256 recorded), the same file crates/tui-kit pins for the terminal. web/lib/whale-lights.ts restates the app's drift, crest and seeded-star formulas (about 60 lines) because the app source is private (CURRENT_DECISIONS 44); PROVENANCE says to change the three together. lib/whale-motion.ts exposes the vendored WhaleRig. Verified: tsc --noEmit clean; ESLint clean on the five changed TS/TSX files; vitest 74 files, 770 tests passed (design-grammar contract included, which moved the new timings onto the spring tokens and the fallback keyframe behind a motion preference). next dev on 3241 in the browser pane and in Electron's Chromium via Playwright: stages mark (0.3 s) -> whale (0.9-1.7 s) -> lights (3.3 s+), beads move between reads, no console errors; with reducedMotion reduce the stage stays whale, lights are display:none and nothing moves. Not deployed; codewhale.net is unchanged until a founder-authorized deploy. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 day ago | |
docs: point every link at the codewhale-hq organization Hunter moved the Codewhale repositories to github.com/codewhale-hq on 2026-10-05. Rewrite Hmbown/<moved repo> slugs to codewhale-hq/<repo> in docs, READMEs (all 19), website, CHANGELOGs, workflows, issue templates, Cargo/npm/VS Code/nix/winget metadata, install and updater code, the bundled first-party marketplace catalog and their tests: 1,795 references in 434 files, plus four escaped regex literals. Docker images publish to ghcr.io/codewhale-hq/codewhale from the next release. Old URLs keep working through GitHub's transfer redirects (verified live: API releases/latest, HTML releases/latest, release asset downloads, codeload tarballs, git clone), so released clients keep updating. Left unchanged on purpose: Hmbown/codewhale-cu-plugin (not moved yet; its shipped updater refuses redirects), Hmbown/deepseek-skills, cwc and other repos that did not move; package identities (winget Hmbown.CodeWhale, NSIS publisher); vendor/codewhale-ratatui (frozen reviewed package); and the extension-host GitHub adapter with tools/github/report.rs and their parity fixture, which need a bundle rebuild and move together in a follow-up. README translation stamps updated to the new README.md hash. Validation: npm test (wrapper 101/0, SDK 19/0, extension host 398 passed / 0 failed / 7 skipped, web 763/0) and npm run check:web exit 0 (one pre-existing facts-lib.mjs lint warning). cargo check --workspace --tests --all-features --locked: exit 0. cargo test -p codewhale-cli -p codewhale-release -p codewhale-protocol and the touched codewhale-tui modules (client, cloud_dispatch, commands, dispatch_runner, llm_client::mock, oauth, operate, plugins::marketplace, remote_control, remote_setup, tools::mcp_registry, tools::web::fetch, working_set, tui::ui::tests): all ok, 0 failed. check-readme-translations (18 in sync), readme locales, TUI locale parity, product vocabulary, web locales, contributor credit, plugin claims, release-workflows.test.js and check-versions all pass. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 month ago | |
feat(web): give every release its own release-notes page (CW-7497) codewhale.net/<locale>/changelog/<version> shows every entry of one released version, section by section with each section's entry count, from the same CHANGELOG.md derivation as /changelog. The post-update notice in the TUI and CLI links here, so the address has to keep working after a release falls off the list page (which shows the newest six releases and twelve entries per section): all 46 released versions are derived into lib/release-notes.generated.ts, untracked like changelog.generated.ts (~730 KB, imported only by the new route). Pages render on demand and are cached (generateStaticParams returns []), the same pattern as /ratatui/[component]. A v-prefixed version redirects to the bare one; an unknown version is a 404. English and Chinese copy; other locales fall back to English chrome and canonicalize to /en. /changelog now links each released version's "Full notes" and its "12 of 49 entries shown" cap to that page instead of the 800 KB CHANGELOG.md on GitHub; Unreleased still links GitHub. Not deployed. Checks run on this source: - npx tsc --noEmit: 0 errors - npx eslint on the changed files: 0 problems - npx vitest run lib/changelog.test.ts lib/i18n/dictionaries.test.ts: 2 files, 26 passed, 0 failed - npx next build: compiled; /[locale]/changelog/[version] listed as an on-demand static route - next dev in the in-app browser: /en and /zh/changelog/0.10.2 render all seven sections with every entry; /en/changelog/v0.10.2 redirects, /en/changelog/9.9.9 is 404, /en/changelog/0.8.40 is 200; the zh page has no horizontal scroll at 375 px. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 18 days ago | |
fix(web): correct roadmap summaries and links; state code mode as shipped The roadmap's "Shipped" column showed the same boilerplate sentence for every release: summarizeReleaseBody took the first prose line of the release body, and every release body opens with the identical "> **Codewhale** is the public product..." blockquote. It now skips headings, blockquotes, separators and fenced code, and prefers the release's own "What's in vX.Y.Z" section, so a release summarizes itself. Rows also dropped their href when the live feed replaced the static items, so a release title rendered as dead text; roadmap page items now carry and render the link. The introduction described Shipped as possibly including a source candidate, which flattened released work and unreleased implementation into one column; it now separates published releases from work in progress, notes that the static items are an outage fallback, and both locales match. Also: the code-mode page still described the pre-0.10.1 Phase-1 probe (off by default, read-only, no MCP, 30 s cap). It now states the shipped contract — on by default with a config opt-out, nested native/MCP/plugin calls through the same gate as a direct call, approvals pause rather than deny, no fixed 30 s cap — in en and zh with key parity, and the "Try code mode" task card drops "read-only". Rides the file_search default-active rows (docs/public-surface-facts.json, web/lib/content/tools.ts, docs/TOOL_SURFACE.md) so the public tool surface matches the twelve eager names the Rust guard pins. Evidence: npm test 772 passed / 74 files (was 1 failing: the file_search surface contract), npx tsc --noEmit exit 0, npm run check:locales PASS, node scripts/gt-site.mjs check OK, npm run check:facts OK. | 30 days ago | |
docs: align repository guidance with extracted Engine and Next [skip ci] Finish inherited guidance changes: point the existing sole prompt, turn-loop and remember references at the extracted Engine. Preserve the Next.js guidance generated by the installed version rather than leaving its ordinary dev-server write dirty. Verified all three Engine paths exist and the complete generated Next block matches the unescaped template in web/node_modules/next/dist/server/lib/generate-agent-files.js; git diff --check passed. Documentation only; no tests or builds repeated. Root CW operator controls were not copied. | 6 days ago | |
feat(web): paper above, sea below — redesign the homepage around the live whale Founder direction (2026-10-04): replace the blue-wall ocean with "paper above, sea below", animate the real GPUI whale, deslop the copy, fix the sideways-scrolling terminal, and show Windows. Design - Paper (the GPUI light palette) is the site's appearance; dark is a pinned choice in the theme toggle, no longer the OS default. - One named sea ramp (--sea, --sea-band) and the tide ombré (--tide: paper -> light aqua -> logo light -> logo deep -> navy), taken from the merch's Tide ombré tee. Retired the blurred strata bands, the sea texture and the mirrored reflection whale; strata.tsx deleted. - Homepage: paper hero (category headline, install plate, CTAs), the live whale resting where the tide begins, the real terminal in the deep water, reading sections back on paper (no "01 /" eyebrows, terms in the brand face, getting-started steps as ruled columns), install band into the footer. Footer: one horizon line, no waterline band. - Terminal captures scale to their frame (container query on column count) instead of scrolling sideways; scroll hint removed. Whale - Vendored whale-character-v2 (acting/rig/props/habitat/mark-data) from codewhale-app bc1044887b4e, publication approved by the owner; see web/vendor/whale-character-v2/PROVENANCE.md. - components/whale-live.tsx: the app's own Director on a canvas, 30 fps only while visible, poster pose under prefers-reduced-motion, pointer gaze at rest. It performs a session loop (ready, reading request, planning, reading files, editing, running tests, done) with a word for each phase; picking a terminal view (Composer/Workbar/Fleet/Providers/Help) cues the matching state, Fleet shows three calves. Copy (English; other locales follow in a translation pass) - COPY_STYLE.md (UT Dallas JSOM business-communication conventions) and MESSAGING.md (positioning research across opencode, Pi, Codex, Claude Code, Cline, Zed, Kilo, Crush, Aider; translation-safety rules; glossary). - Hero: "The open-source coding agent for any model"; section headings, product/plugins/models/getting-started/runtime/community/faq strings rewritten; claims narrowed to shipped behaviour. Install - Windows tab (Scoop main bucket carries codewhale 0.10.0). No winget: the manifest is not in microsoft/winget-pkgs (checked 2026-10-04). Tests: rewrote the design-contract tests that pinned the retired look (ocean-contract, docs-theme-contract, gpui-role-tokens). The contrast test now resolves var() stops and caught a real defect (muted ink on the logo-deep tide stop was 4.38:1); the tide was re-stopped so muted text sits >= 4.5:1. Evidence (local, this tree): - web: vitest 74 files / 764 tests passed, 0 failed - web: npm run check exit 0 (facts, latest-release, docs, tokens, lint, tsc --noEmit, next build); 1 pre-existing lint warning in scripts/facts-lib.mjs - headless Chrome: whale cycles all 7 phases and cues "pod" on Fleet; pages checked at 1440 and 390 wide: home, product, install, docs/guide, models Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 1 month ago | |
fix(web): restore full ocean design and correct released guides [skip ci] Apply the reviewed Moda desktop/mobile composition with the existing C-whale, Shannon Sans and real interactive terminal captures. Use one coherent headline in all18 locales. Give Computer Use a full-width band, show three concrete work patterns, feature the published two-file skill tutorial and shorten the closing install action. Keep released/source availability distinct. Audit public instructions against published CLI0.10.2 and CU0.16.1: correct hash-bound plugin trust, Workflow proposal/confirmation and limits/forms, Fleet session workers versus durable ledger and explicit recovery, Lane control surfaces, provider setup, Auto-Review user questions and conditional snapshot restoration. Update CU setup/platform guidance across18 languages. Fix lost dark-mode pins on locale navigation with the existing ThemeToggle boundary: server-only bootstrap insertion and locale-keyed layout synchronization. Remove unused auto-mode props/tooltip. Adjust existing assertions to follow the actual session-worker command and moved bootstrap owner; no test cases added. Verification:9 existing web suites110 passed. Focused ESLint covers all58 changed TS/TSX paths; TypeScript no-emit, locale schema, local EN/ZH GT and diff checks pass. Actual browser desktop/mobile light/dark; EN/ZH repeated locale changes and cold dark reload preserve theme, with a single bootstrap in HEAD and no post-fix console errors. Windows installer/Fleet gallery controls work; no sampled page overflow. Official CLI macOS arm64 SHA256 verified and9 isolated --help commands passed; no model/provider execution claimed. Moda:201 editable nodes, desktop/mobile native PNG exports without warnings; existing Codewhale kit, unchanged team visibility,0credits, no publication. Local/source verification only. No hosted CI or website deploy initiated. | 1 day ago | |
feat: integrate the verified 0.10.3 combined Engine batch [skip ci] Lands the 0.10.3 program work that two Codex sessions left uncommitted on canonical main (chats 01a176ff "Review latest MCP updates" / 01a176e0 "DSH plugin compatibility"), on top of contributor PR #7086, which merged as itself (5c3d461d8a) immediately before this commit. The pieces share compiler inputs (the crate-split moves touch most of them), so they land as one verified tree rather than as intermediate commits that would not build. Contents: - Crate split slices: codewhale-net, codewhale-notify and codewhale-sandbox crates; runtime config, config persistence, oauth, settings, catalog cache and Codex model roster moved from tui to runtime; hooks, extension host config and instruction budget to config; callers rewired, re-export facades removed (CW-6129). - Follow-up repairs to #7086 instruction budgets (per-scope budgets, canonical source labels, instruction_assembly session snapshot). - MCP: official SDK 2.4 host backend by default with server/discover and legacy fallback, metadata/output schema handling, OAuth issuer binding, Engine/CU server modernization (CW-6713, CW-7543, CW-7544, CW-7546). - DSH plugin compatibility from the authorized exception lane 26ba80b06a: shared compatibility table, native command lifecycle, reviewed imports, Native-only filesystem sandbox (CW-7054). - Computer Use plugin-only cutover: vendored bundle removed, marketplace install from the independent release (CW-6732). - Image-heavy sessions: 256 KiB read budget, outbound image omission with receipts, one smaller retry on HTTP 413 (CW-7550). - Typed review operation (core/engine/review.rs, runtime_api/review.rs) used by Platform structured reviews. - Receipt-owned Unix uninstall (Refs #7091). - Steering (CW-7552) and Linux Shift+Enter (CW-7551, Refs #7093) source changes; runtime/manual proof still pending. Fixes made during takeover verification: - MCP: Rust now admits the legacy handshake whenever the SDK classifies the discovery probe as legacy (any JSON-RPC error, or a result without the modern supported version); before, servers answering the probe with a result were refused after it. - MCP: an admitted legacy handshake reports initialize's own failure (e.g. 401) instead of the probe's -32601. - MCP: OAuth reactive refresh covers the side-effect-free probe. - MCP: broker launch failures keep their diagnostic (missing command). - Tool images must decode before delivery (truncated PNG was accepted). - THIRD_PARTY_NOTICES lists MCP SDK 2.4.0 and DSH 0.2.1-rc.2 excerpts. - Changelog entries for MCP, DSH, Computer Use and image validation. - #[cfg(test)] on three test-only items; cargo fmt --all; tests updated to post-cutover behavior (no built-in CU, $schema manifests, canonical paths, lazy CU tools, SyncSession resets instruction assembly). Verified on this exact tree (macOS, source sha 4353faf1 before changelog edits; changelog/generated-doc edits only after): - cargo check --workspace --all-targets --locked: exit 0, no warnings - codewhale-config 806 passed; codewhale-runtime 850 passed; codewhale-net 52 passed; codewhale-notify 31 passed; codewhale-cli 501 passed (nextest, 0 failed) - codewhale-tui lib: 14515 passed, 0 failed, 21 skipped - extension host npm test: 420 tests, 413 passed, 0 failed, 7 skipped - web check-facts OK Linux x86_64 (Boat VM, same source before the #7097 fold-in): cargo check --workspace --all-targets --locked exit 0; codewhale-config 808, codewhale-runtime 849, codewhale-net 52, codewhale-notify 31, codewhale-sandbox 100, codewhale-cli 501 passed, 0 failed. The tui lib test binary was still compiling on the 16 GB VM at commit time. #7097 (main) was three-way merged into approval_log.rs and clipboard.rs; re-check after the fold-in: workspace check exit 0; tui approval_log, clipboard, session_export, file_mention, pet_watch 213 passed. Not run: hosted CI, clippy -D warnings, release packaging, live provider or real MCP servers beyond local fixtures, Deepin run for #7093. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 12 days ago | |
build(web): migrate the recovered terminal website to Cloudflare cf Use one authoritative typed Cloudflare config, preserving the existing Worker name, KV identities, Durable Object export, bindings, domains and cron. Generate the ignored OpenNext adapter config from it. Pin cf beta.12 and its official internal build delegate; build and populate OpenNext cache before cf deploy --prebuilt. Fail closed if deployment SHA or storage identities are missing. No production deployment, namespace creation or secret change was performed. Exclude generated cf/preview bundles from the source locale ceiling and fix two vulnerable transitive parser versions. The recovered terminal gallery remains explicitly a 0.10.1 pre-release preview with 0.10.0 the published release. Validation: npm test 1286 passed, 0 failed, 7 skipped (wrapper 101, SDK 19, extension host 399/406, web 767); npm run check:web passed. Focused deployment preflight 13/13 passed, TypeScript passed, OpenNext plus cf bundle build passed, cf deploy --dry-run passed, KV identity guard passed. Real local Worker /api/facts returned 200; browser interaction selected and rendered all six terminal views. Narrow viewport had no horizontal page overflow. No deploy/publication claim. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 month ago | |
build(web): migrate the recovered terminal website to Cloudflare cf Use one authoritative typed Cloudflare config, preserving the existing Worker name, KV identities, Durable Object export, bindings, domains and cron. Generate the ignored OpenNext adapter config from it. Pin cf beta.12 and its official internal build delegate; build and populate OpenNext cache before cf deploy --prebuilt. Fail closed if deployment SHA or storage identities are missing. No production deployment, namespace creation or secret change was performed. Exclude generated cf/preview bundles from the source locale ceiling and fix two vulnerable transitive parser versions. The recovered terminal gallery remains explicitly a 0.10.1 pre-release preview with 0.10.0 the published release. Validation: npm test 1286 passed, 0 failed, 7 skipped (wrapper 101, SDK 19, extension host 399/406, web 767); npm run check:web passed. Focused deployment preflight 13/13 passed, TypeScript passed, OpenNext plus cf bundle build passed, cf deploy --dry-run passed, KV identity guard passed. Real local Worker /api/facts returned 200; browser interaction selected and rendered all six terminal views. Narrow viewport had no horizontal page overflow. No deploy/publication claim. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 month ago | |
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. | 2 months ago | |
fix(web): serve security.txt, drop x-powered-by, send plain http to https codewhale.net had no /.well-known/security.txt, every page response carried x-powered-by: Next.js and x-opennext: 1, and a plain-http request to codewhale.net was answered over http. www.codewhale.net redirected to codewhale.net but kept the http scheme. - web/public/.well-known/security.txt (RFC 9116): Contact is the GitHub private vulnerability report form named in SECURITY.md, Policy is SECURITY.md, Expires 2027-10-19, Preferred-Languages en, zh, Canonical https://codewhale.net/.well-known/security.txt. - next.config.ts: poweredByHeader: false. OpenNext reads the same setting, so it also removes x-opennext. - middleware.ts: the canonical-host redirect now covers both site hosts. A request to codewhale.net or www.codewhale.net whose URL scheme or X-Forwarded-Proto is http gets one 308 to https://codewhale.net with the same path and query, before any other branch. Other hosts (localhost, previews) are untouched. Not covered: paths the Workers asset layer serves before the Worker runs, for example /install.sh and /.well-known/security.txt itself. Middleware never sees them, so plain http for those needs the zone's HTTPS redirect or worker-first routing for those paths. Not deployed by this commit. Evidence (local only): - npx tsc --noEmit: exit 0. - npx eslint middleware.ts next.config.ts: exit 0, no findings. - npm test (web): node --test 7 passed, 0 failed; vitest 74 files, 772 tests passed. - npx next build + next start: security.txt 200 text/plain; /en 200 with no x-powered-by; Host codewhale.net with X-Forwarded-Proto http -> 308 https://codewhale.net/en/install?ref=a; Host www.codewhale.net -> 308 https://codewhale.net/en; X-Forwarded-Proto https -> 200; localhost unchanged; POST over http -> 308 (method kept). - OpenNext Cloudflare build (next build in standalone mode, then opennextjs-cloudflare build --skipNextBuild) under local wrangler dev: worker saw http://codewhale.net/en and answered 308; over https /en is 200 with no x-powered-by and no x-opennext; /install.sh and /.well-known/security.txt were served by the asset layer with no worker invocation (0 worker spans). - No existing test covers the middleware and none was added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 days ago | |
fix(web): serve security.txt, drop x-powered-by, send plain http to https codewhale.net had no /.well-known/security.txt, every page response carried x-powered-by: Next.js and x-opennext: 1, and a plain-http request to codewhale.net was answered over http. www.codewhale.net redirected to codewhale.net but kept the http scheme. - web/public/.well-known/security.txt (RFC 9116): Contact is the GitHub private vulnerability report form named in SECURITY.md, Policy is SECURITY.md, Expires 2027-10-19, Preferred-Languages en, zh, Canonical https://codewhale.net/.well-known/security.txt. - next.config.ts: poweredByHeader: false. OpenNext reads the same setting, so it also removes x-opennext. - middleware.ts: the canonical-host redirect now covers both site hosts. A request to codewhale.net or www.codewhale.net whose URL scheme or X-Forwarded-Proto is http gets one 308 to https://codewhale.net with the same path and query, before any other branch. Other hosts (localhost, previews) are untouched. Not covered: paths the Workers asset layer serves before the Worker runs, for example /install.sh and /.well-known/security.txt itself. Middleware never sees them, so plain http for those needs the zone's HTTPS redirect or worker-first routing for those paths. Not deployed by this commit. Evidence (local only): - npx tsc --noEmit: exit 0. - npx eslint middleware.ts next.config.ts: exit 0, no findings. - npm test (web): node --test 7 passed, 0 failed; vitest 74 files, 772 tests passed. - npx next build + next start: security.txt 200 text/plain; /en 200 with no x-powered-by; Host codewhale.net with X-Forwarded-Proto http -> 308 https://codewhale.net/en/install?ref=a; Host www.codewhale.net -> 308 https://codewhale.net/en; X-Forwarded-Proto https -> 200; localhost unchanged; POST over http -> 308 (method kept). - OpenNext Cloudflare build (next build in standalone mode, then opennextjs-cloudflare build --skipNextBuild) under local wrangler dev: worker saw http://codewhale.net/en and answered 308; over https /en is 200 with no x-powered-by and no x-opennext; /install.sh and /.well-known/security.txt were served by the asset layer with no worker invocation (0 worker spans). - No existing test covers the middleware and none was added. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> | 19 days ago | |
Enable website cache refresh through the existing Worker Wire the OpenNext memory revalidation queue to WORKER_SELF_REFERENCE. Previously the KV cache stored prerendered release availability but the default dummy queue never refreshed it. Validation: npm test 534 passed, 0 failed (66 packaging, 9 SDK, 459 web); npm run check:web passed, including typecheck and production build. Wrangler type generation validates the self-service binding. Two existing img lint warnings remain. Live deployment verification is separate. | 1 month ago | |
Merge current Engine source and resolve React dependency updates Preserve original React19.3.1/DOM and types19.3.0 intent, with current Stripe23.1.0 and Node types26.6.6. Structured three-way dependency delta, root/lock consistency, exact dependency pins and diff checks pass; hosted PR CI supplies runtime/build qualification. | 6 days ago | |
Merge current Engine source and resolve React dependency updates Preserve original React19.3.1/DOM and types19.3.0 intent, with current Stripe23.1.0 and Node types26.6.6. Structured three-way dependency delta, root/lock consistency, exact dependency pins and diff checks pass; hosted PR CI supplies runtime/build qualification. | 6 days ago | |
refactor(web): split globals.css into per-surface partials globals.css (3,828 lines) becomes an import hub over app/styles/*.css, cut at existing section boundaries in the original order: tailwind, tokens-roles, base, shell, utilities, portal, home, docs, states, docs-help, changelog, overrides. Pure move; no rule edited. Tailwind expands each CSS file separately and appends variant utilities (hover:, md:, ...) at the end of whichever file holds @tailwind utilities, which moved them ahead of every site rule. postcss.config now runs postcss-import (already a tailwindcss@3 dependency, hoisted in package-lock) for ./styles/ imports so Tailwind sees one stylesheet again. tokens.css stays a separate module as before. The contract tests and whale-tokens.ts read the stylesheet through a new lib/site-css.ts, which inlines the partials in cascade order. Checks: - Built CSS, back-to-back A/B/A builds (original / split / original): split output byte-identical to original (same md5 and chunk hash). - next build: exit 0 - npm run lint: 0 errors, 2 pre-existing warnings - npx tsc --noEmit: exit 0 - vitest (docs-theme-contract, blue-stage-contract, docs-ia, nav-hit-target, public-surface-contract): 5 files, 43/43 passed - npm run check:tokens: up to date (122 tokens) Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 1 month ago | |
fix(web): keep admin POSTs across the host move and truthful locale coverage Audit 0.10.1 js-ops, web (W01), Refs #6561: - W01-07: the www -> apex canonical-host redirect is 308, not 301, so a client never replays an admin login/post form as a body-less GET. 308 is still a permanent move for crawlers. - W01-02: FAQ English answers render for every non-Chinese route locale; their five internal links now follow that locale instead of /en. - W01-03: /computer-use coverage in the content-locale registry is derived from the COMPUTER_USE dictionary (hasComputerUseTranslation), so canonical, hreflang and sitemap list its 18 translated locales instead of canonicalizing them to English. - W01-04: /docs/guide leaves the registry override. Its fr/de/ca/hi/tr/ it/pl/ar dictionaries translate only the overview and headings; the getting-started steps that are the body ship in en/zh, so those variants canonicalize to English like other partial pages. - W01-m1: Tailwind scans lib/i18n/dictionaries, where the Arabic and Hindi guide's leading-loose lives. - W01-m2: the default caption track follows the page locale when it has captions, else English. Validation (web, npm ci, vitest 4.1.11): - vitest run middleware, faq-schema, media-manifest, docs-ia, page-meta, lib/i18n, public-surface-contract, public-copy: Test Files 14 passed, Tests 142 passed. - tsc --noEmit -p web: exit 0. eslint on touched files: exit 0. - Negative controls: middleware.ts at HEAD -> "keeps an admin form POST" fails (expected 301 to be 308). tailwind.config.ts at HEAD -> built utilities contain leading-loose 0 times (1 with the fix). - Sitemap count 99 -> 107 (+16 computer-use, -8 docs/guide) asserted in docs-ia.test.ts. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 month ago | |
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> | 2 months ago | |
docs, scripts and CI: follow the host move; document stdio/websocket controls and usage statistics Updates moved-file paths in the CI path filters, scripts, vitest config and editor/bridge sources; documents the Runtime API stdio/websocket controls and usage statistics (en and zh_hans); adds the usage-statistics and cache-call-receipts features to features.toml with regenerated web data; updates coarse-split design docs and crate maps, split scripts, the blocking-calls budget and release smoke scripts. Verification: whole-tree evidence only, not per group. A native21 build of the full dirty tree completed (patch sha ea25c782...), and an unsealed nextest rerun of all 389 selected existing checks passed 389/389 on it. The earlier sealed native20 run failed 369/20 before fixes and was not re-sealed. No CI run. Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> | 5 days ago | |
fix(web): derive the changelog and install-guide modules at build time web/lib/changelog.generated.ts and web/lib/install-guide.generated.ts were committed copies of CHANGELOG.md and docs/INSTALL.md. Two PRs that each added a CHANGELOG line regenerated the copy against their own base; git merged both hunks cleanly but kept one "itemCount" bump, so main's parity test went red (ae08853fc and ede108041 on 2026-09-26) and every PR that merged main inherited it. Both files are now untracked (web/.gitignore). prebuild and dev already derived them; a vitest globalSetup now derives them before any test imports them, so npm test, npx vitest and the root npm --prefix web test work on a fresh checkout. OpenNext's deploy build runs npm run build, which triggers prebuild. check:docs renders the guide instead of diffing a tracked copy (rendering still throws on broken links). prepare-release.sh no longer regenerates or snapshots the changelog module. facts.generated.ts stays committed: facts-drift.ts fetches it from the exact revision at runtime for toolCount and models, and check-facts gates it. crates/tui/CHANGELOG.md stays committed: /change include_str!s it from inside the published codewhale-tui crate, and as a byte prefix of the root changelog it merges consistently. Verified: web vitest 55 files / 498 tests passed with both files deleted first; npm run check exit 0 (check-facts OK, check-docs PASS, lint, tsc, next build 839 pages; /en/changelog renders the Unreleased entries); sync-changelog.sh --check up to date; check-versions.sh --range-audit-advisory exit 0; check-contributor-credit.py v0.10.0 exit 0; prepare-release.test.sh passed. No-Issue: derived changelog artifacts raced between merges and reddened main twice on 2026-09-26 Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> | 1 month ago | |
fix(web): make the draft claim exclusive with a Durable Object Claims on a community-agent draft (post or discard) now go through the DraftClaimLock Durable Object when the DRAFT_CLAIM_LOCK binding is present: one SQLite-backed object per draft identity (idFromName), whose one-event- at-a-time input gate makes grant/refuse/release atomic. The lease expires after 15 minutes so a crashed or unknown-outcome post cannot wedge the draft, and after a recorded decision the object keeps refusing claims for 2 minutes while the KV decision marker propagates to other locations. The KV get/put claim stays as the fallback for next dev and tests. A second discard of the same draft (double click) now returns 200 whether the first one has finished or is still holding the draft. worker.ts exports the class (OpenNext custom-worker pattern); wrangler.jsonc adds the binding and a v1 new_sqlite_classes migration, applied on deploy. Tests: draft-claim-lock (6) + 7 new route tests with a serializing fake DO (concurrent posts -> one 200, stale-KV retry refused during the hold, lease kept after 502 and expired after 15 min, 422 frees at once, double discard -> 200/200, post/discard exclusion, unreachable lock fails closed). Against 7cf21caee, 6 of the 7 route tests fail (the 422 release test passes on both, a guard against over-locking). vitest community-agent*/content-watch/public-api-security/draft-claim-lock/ deploy-preflight: 7 files, 89 passed. tsc --noEmit exit 0. eslint on touched files exit 0. esbuild bundles worker.ts with the exported class. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014ZwqatxgVFxHvovngywnks | 1 month ago | |
build(web): migrate the recovered terminal website to Cloudflare cf Use one authoritative typed Cloudflare config, preserving the existing Worker name, KV identities, Durable Object export, bindings, domains and cron. Generate the ignored OpenNext adapter config from it. Pin cf beta.12 and its official internal build delegate; build and populate OpenNext cache before cf deploy --prebuilt. Fail closed if deployment SHA or storage identities are missing. No production deployment, namespace creation or secret change was performed. Exclude generated cf/preview bundles from the source locale ceiling and fix two vulnerable transitive parser versions. The recovered terminal gallery remains explicitly a 0.10.1 pre-release preview with 0.10.0 the published release. Validation: npm test 1286 passed, 0 failed, 7 skipped (wrapper 101, SDK 19, extension host 399/406, web 767); npm run check:web passed. Focused deployment preflight 13/13 passed, TypeScript passed, OpenNext plus cf bundle build passed, cf deploy --dry-run passed, KV identity guard passed. Real local Worker /api/facts returned 200; browser interaction selected and rendered all six terminal views. Narrow viewport had no horizontal page overflow. No deploy/publication claim. Signed-off-by: CodeWhale Bot <bot@codewhale.net> | 1 month ago |
codewhale-web
Documentation and community site for Codewhale — lives at codewhale.net.
Next.js 16 (App Router) + Tailwind, deployed to Cloudflare Workers via @opennextjs/cloudflare. Curated "Today's Dispatch" content is regenerated every 6 hours by a Cloudflare Cron Trigger that calls deepseek-flash to summarise recent repo activity, and stored in Workers KV.
Local dev
cd web
npm install
cp .env.example .env.local # fill in the keys you have
npm run dev # http://localhost:3000
Env (mirrors .env.example):
| Variable | What | Required? |
|---|---|---|
DEEPSEEK_API_KEY |
DeepSeek platform key (sk-...) |
only for the /api/cron tasks (summarization + community agent) |
GITHUB_TOKEN |
Fine-grained PAT, public-repo read scope | optional (raises rate limit 60 → 5000 req/h) |
GITHUB_REPO |
Defaults to codewhale-hq/CodeWhale |
optional |
CRON_SECRET |
Shared secret for manual /api/cron invocation |
optional (Cloudflare cron triggers don't need it) |
DEEPSEEK_MODEL |
Defaults to deepseek-flash |
optional |
DEEPSEEK_BASE_URL |
Defaults to https://api.deepseek.com |
optional |
MAINTAINER_TOKEN |
Admin panel auth; enter it in the /admin login form |
only for /admin |
MAINTAINER_GITHUB_PAT |
PAT with issues:write, for posting comments via /admin |
only for /admin posting |
NEXT_PUBLIC_GITEE_ENABLED |
Set to 1 once the Gitee mirror exists; blank hides Gitee links |
optional |
The site renders fine without any of them — Today's Dispatch falls back to a static editorial; the GitHub feed shows "feed not yet loaded".
Deploy to Cloudflare
The .github/workflows/web.yml workflow runs only for a maintainer-triggered
workflow_dispatch. Ordinary pushes and pull requests do not start it.
A dispatch on main runs the web checks and production build before deploying.
At the approved final publication step, record the exact 40-character
origin/main SHA and trigger that ref:
git fetch origin main
git rev-parse origin/main
gh workflow run web.yml --repo codewhale-hq/CodeWhale --ref main
Confirm that the dispatched run resolved to the recorded SHA before treating
its result as evidence for that candidate. The deploy job checks out the exact
dispatch SHA even if main advances while the run is queued.
The manual job records the pre-deploy source drift, builds the OpenNext bundle,
deploys only after the protected Cloudflare inputs pass, and then requires the
public /api/facts receipt to report the exact workflow SHA. A credential-free
local comparison is available without starting a deployment:
npm run compare:deployed-facts -- --expected-revision <exact-40-character-sha>
The Worker configuration now lives in cloudflare.config.ts; it retains the
existing namespace IDs, domains, cron schedules and SQLite Durable Object.
npm ci installs pinned cf and Cloudflare bundler versions. Use Node 22.18 or
newer. OpenNext currently consumes a generated legacy configuration in the
ignored .cloudflare/ directory, derived from that same source with
Cloudflare's configuration SDK.
npm run build:cloudflare # one OpenNext build, then native cf Build Output
npx cf deploy --prebuilt --dry-run # local validation; no upload
npm run preview # local Worker with populated local cache
The pinned cf beta's Next.js detection currently invokes plain next build,
which does not produce the OpenNext Worker. build:cloudflare therefore runs
OpenNext first and invokes cf's installed bundler (cf-wrangler.js) to emit
Build Output. This is a build step; production deployment uses cf deploy --prebuilt. Do not add a custom post-cache build to wrangler.config.ts:
rebuilding there changes the cache identity after OpenNext populates it.
After production approval, the manual workflow runs npm run deploy,
populates the remote OpenNext cache, and passes the exact prebuilt bundle to
cf. Existing secrets remain managed in Cloudflare; namespace provisioning,
secret changes and domain changes require separate approval. The predeploy
guard rejects unset namespace IDs to avoid accidentally replacing live data.
Use npx cf cli search to find the current resource-management commands.
What's where
Pages are bilingual by default: each app/[locale]/ page renders both
English and Chinese from the same file, keyed by the [locale] segment
(see lib/i18n/config.ts). Copy changes must update both locales. The
v0.9.2 wave adds routed partial locales (ja, vi, ko, ru, uk, es, pt-BR):
their shared chrome (nav/footer/switcher) and home-page copy live in
lib/i18n/dictionaries/<code>/ (checked by npm run check:locales), and
everything else falls back to the English copy. Routing, middleware
detection (lib/i18n/detect.ts), sitemap, and hreflang all derive from the
one registry.
web/
├── app/
│ ├── globals.css ocean portal, docs layout, type, and shared surfaces
│ ├── [locale]/ 10 routed locales; zh has native page bodies,
│ │ the rest fall back to the English body
│ │ ├── layout.tsx root + locale layout: html shell, fonts, nav, footer
│ │ ├── page.tsx home — hero, ticker, proof, decides, workflow,
│ │ │ start, boundaries, surfaces, install band, community
│ │ ├── install/page.tsx per-OS install with auto-detection
│ │ ├── docs/page.tsx modes / tools / approval / config / mcp / providers
│ │ ├── faq/page.tsx frequently asked questions
│ │ ├── feed/page.tsx live mirror of issues + PRs
│ │ ├── roadmap/page.tsx shipped / underway / considered / ruled out
│ │ ├── contribute/page.tsx how to PR + house rules + dev loop
│ │ └── admin/ maintainer panel (page.tsx + admin-client.tsx)
│ └── api/
│ ├── cron/route.ts cron tasks: curate, triage, facts-drift, …
│ ├── facts/route.ts public source/deployment receipt
│ ├── github/feed/route.ts cached JSON endpoint
│ └── admin/ login, logout, post (MAINTAINER_TOKEN-gated)
├── data/
│ └── latest-published-release.json manually advanced only after publication
├── components/
│ ├── native-terminal-gallery.tsx six captured native terminal views
│ ├── nav.tsx sticky header w/ date strip + CJK accents
│ ├── footer.tsx dense 5-column footer
│ ├── whale.tsx shared Codewhale mark
│ ├── ticker.tsx live wire: merges, issues, releases + handles
│ ├── feed-card.tsx one issue/PR card
│ ├── locale-switcher.tsx N-locale dropdown; partial packs grouped last
│ └── install-*.tsx install page blocks (binary, code block, tiles)
├── lib/
│ ├── types.ts shared types
│ ├── i18n/ locale config, en/zh dictionaries
│ ├── github.ts REST client + relative-time formatter
│ ├── deepseek.ts v4-flash chat client + curate() prompt
│ ├── facts.ts getFacts(): KV value, else build-time FACTS
│ ├── facts.generated.ts GENERATED — do not edit by hand
│ ├── changelog.generated.ts GENERATED at build/test time, untracked
│ ├── install-guide.generated.ts GENERATED at build/test time, untracked
│ ├── facts-drift.ts runtime re-derivation for the drift cron
│ ├── community-agent.ts triage / pr-review / digest cron tasks
│ └── kv.ts Cloudflare KV access via OpenNext bindings
├── scripts/
│ ├── derive-facts.mjs prebuild: repo sources → lib/facts.generated.ts
│ ├── derive-changelog.mjs prebuild + vitest setup: CHANGELOG.md → lib/changelog.generated.ts
│ ├── derive-install.mjs prebuild + vitest setup: docs/INSTALL.md → lib/install-guide.generated.ts
│ ├── compare-deployed-facts.mjs credential-free exact-SHA receipt check
│ └── check-kv-id.mjs predeploy guard for KV namespace ids
├── cloudflare.config.ts Worker config + existing bindings, exports and cron
├── wrangler.config.ts cf bundler options (no separate Worker config)
├── open-next.config.ts OpenNext adapter config
└── tailwind.config.ts design tokens
Facts pipeline
Mechanical facts (version, provider list, sandbox backends, crate names, default model, Node engines) are never hand-written into pages:
- Build time —
scripts/derive-facts.mjsruns asprebuild(and beforenpm run dev), parses the parent repo (Cargo.toml,crates/tui/src/config.rs,crates/sandbox/src/lib.rs,npm/codewhale/package.json) and writeslib/facts.generated.ts. Never edit that file by hand. - Published release —
data/latest-published-release.jsonrecords the latest GitHub Release separately from the source candidate. Install commands use this published tag; they never turn the workspace version into a release before publication. The credential-free deployed-facts comparison checks the record against the public receipt. - Runtime — the
/api/cron?task=facts-driftcron (lib/facts-drift.ts) resolves an exactmainrevision, derives every source fact from that SHA, and writes changes toCURATED_KVunderfacts:current. Pages accept that snapshot only when its source provenance is the same as or newer than the deployed build. Legacy, malformed, or older KV data cannot replace newer build facts; published-release metadata is resolved independently. Public fact pages revalidate their cached HTML every five minutes.
/api/facts exposes only public provenance and counts: deployed/resolved source
revision, version, provider count, tool count, selection reason, and latest
published release. It contains no environment values, tokens, or KV contents.
Public provider facts derive the complete roster and optional presentation
labels from crates/config/assets/provider_descriptors.json, alongside the
catalog from the same selected source revision. Both local generation and the
remote drift check validate that descriptor document and refuse missing or
malformed data. Add metadata there; there is no separate website label map or
TUI enum roster to update.
Visual direction
The public site is a documentation portal with a restrained underwater atmosphere. Content and navigation come first; ocean depth, currents, and the whale mark provide identity without turning every section into a themed card.
- Palette: cool paper and mist for reading surfaces, deep navy for terminal and community sections, muted current blue for links, and small gold/coral signals where status needs contrast.
- Type: Space Grotesk for headings, IBM Plex Sans for body copy, and JetBrains Mono for commands and compact interface labels.
- Structure: compact documentation rows, quiet hairline dividers, generous but bounded reading widths, and responsive layouts that remove chrome before content.
If you want to retune the palette, edit :root in app/globals.css and the colors block in tailwind.config.ts.