mirror of
https://github.com/Hmbown/DeepSeek-TUI.git
synced 2026-09-03 06:50:13 +08:00
* design: export the TUI whale palette instead of re-typing it
crates/tui/src/palette/tokens.rs is the whale palette. The web app repeated
its hexes by hand, the desktop shell ran a separate neutral-gray palette, and
the Android theme a fourth one — four palettes sharing exactly one value
(#08111C). Make the Rust file the source and generate the rest.
scripts/export-design-tokens.py parses the 47 WHALE_*_RGB consts (aliases
included: INFO = ACTION = ACCENT_PRIMARY, SUCCESS = WORKING_GREEN,
ERROR_BORDER = ERROR, ...) and emits web/app/tokens.css, plus — when a
codewhale-apps checkout sits beside this repo — the desktop CSS token file
and a Compose WhaleTokens object. Aliases are emitted as var()/val
references, so the alias structure survives the export instead of flattening
into duplicate literals. --check fails when a generated file is stale; it is
wired in as `npm run check:tokens` and runs in the web workflow.
globals.css keeps its own variable names (--paper, --ink, --indigo — the
component rules and the docs light sheet consume them) and now binds them to
--whale-* rather than re-typing the hex. Only byte-identical values were
rebound; --paper-card, --indigo-deep, --stage-ambient and --stage-hint are
not whale tokens and stayed literal. No rendered color changes.
The two contract tests read hexes straight out of globals.css, so they now
resolve one hop through the generated file (lib/whale-tokens.ts). They still
catch a wrong mapping: pointing --paper at --whale-panel fails with
"expected '#0e1729' to be '#03070d'".
Evidence, in web/:
npm test -> Test Files 42 passed (42), Tests 364 passed (364)
npm run lint -> clean; npx tsc --noEmit -> clean
npm run build -> succeeded; built CSS carries --whale-bg:#03070d
and --paper:var(--whale-bg)
npm run check:tokens -> design tokens up to date (47 tokens)
check:facts, check:docs -> PASS
Perturbing tokens.css makes --check exit 1 with "stale: web/app/tokens.css".
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdbuqwHAXSDcikPiS6L6Qw
* design tokens: the generator targets the web app only
The desktop and Android targets were rendered and rejected on sight; the
script now writes nothing outside this repository and has no --apps-root.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01AdbuqwHAXSDcikPiS6L6Qw
---------
Co-authored-by: CodeWhale Bot <bot@codewhale.net>
Co-authored-by: Claude Fable 5.1 <noreply@anthropic.com>
147 lines
6.3 KiB
YAML
147 lines
6.3 KiB
YAML
name: Web Frontend
|
|
|
|
on:
|
|
push:
|
|
branches: [master, main]
|
|
pull_request:
|
|
branches: [master, main]
|
|
workflow_dispatch:
|
|
|
|
permissions:
|
|
contents: read
|
|
|
|
jobs:
|
|
lint:
|
|
name: Lint & Type Check
|
|
runs-on: ubuntu-latest
|
|
defaults:
|
|
run:
|
|
working-directory: web
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
- uses: actions/setup-node@v7
|
|
with:
|
|
node-version: 22
|
|
cache: 'npm'
|
|
cache-dependency-path: web/package-lock.json
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
- name: Check facts drift
|
|
# facts.generated.ts is TRACKED (committed), so verify the committed
|
|
# copy matches the workspace BEFORE regenerating. Running prebuild first
|
|
# would self-heal the working tree and let a stale committed file pass
|
|
# (#3771). check:facts ignores the volatile generatedAt/latestRelease
|
|
# fields by design, so it is safe to run against the committed copy that
|
|
# exists at checkout.
|
|
run: npm run check:facts
|
|
- name: Check published-release fact is current
|
|
# web/data/latest-published-release.json is hand-maintained and feeds
|
|
# facts.generated.ts. Nothing wrote it, so it drifted to v0.9.10 while
|
|
# v0.9.11 was live, and the post-deploy comparison below failed on
|
|
# latestPublishedRelease.tag AFTER the site had already shipped. Gate it
|
|
# here so the mismatch is caught before deploying, not after.
|
|
env:
|
|
GITHUB_TOKEN: ${{ github.token }}
|
|
run: npm run check:latest-release
|
|
- name: Generate derived facts
|
|
# Regenerate after the drift gate so tsc --noEmit (TS2307 without it) and
|
|
# the build use a current facts.generated.ts. When the gate passes this
|
|
# only refreshes the generatedAt timestamp.
|
|
run: npm run prebuild
|
|
- name: Check docs parity
|
|
# Fails CI when docs-map.ts references non-existent repo files or
|
|
# when website version / command snippets are stale.
|
|
run: npm run check:docs
|
|
- name: Check design tokens
|
|
# app/tokens.css is generated from crates/tui/src/palette/tokens.rs.
|
|
# Fails CI when the palette moved and the export was not re-run.
|
|
run: npm run check:tokens
|
|
- name: Run tests
|
|
run: npm test
|
|
- name: Run ESLint
|
|
run: npm run lint
|
|
- name: TypeScript type check
|
|
run: npx tsc --noEmit
|
|
- name: Build production site
|
|
run: npm run build
|
|
|
|
deploy-reminder:
|
|
name: Deployment approval needed
|
|
runs-on: ubuntu-latest
|
|
needs: lint
|
|
if: github.event_name == 'push' && github.ref == 'refs/heads/main'
|
|
steps:
|
|
- name: Surface the manual deployment gate
|
|
env:
|
|
REVISION: ${{ github.sha }}
|
|
run: |
|
|
echo "::notice title=Web deployment approval needed::Revision ${REVISION} passed the web gates but is not deployed. Dispatch web.yml on main to publish it."
|
|
{
|
|
echo "## Web deployment approval needed"
|
|
echo
|
|
echo "Revision \`${REVISION}\` passed the web gates but has **not** been deployed."
|
|
echo
|
|
echo "A maintainer can publish it with \`gh workflow run web.yml --repo Hmbown/CodeWhale --ref main\`."
|
|
} >> "$GITHUB_STEP_SUMMARY"
|
|
|
|
deploy:
|
|
name: Deploy to Cloudflare
|
|
runs-on: ubuntu-latest
|
|
needs: lint
|
|
# Deploy is MANUAL ONLY: a human dispatches this workflow on main. Pushes
|
|
# and pull requests still run `lint` above, but they never reach Cloudflare.
|
|
# This mirrors scripts/check-cloudflare-deploy-env.mjs, which fails closed
|
|
# unless GITHUB_EVENT_NAME is workflow_dispatch, GITHUB_REF is
|
|
# refs/heads/main, and GITHUB_SHA is an exact 40-hex revision — a push
|
|
# trigger here would only produce a red job after `lint` had already run.
|
|
# lib/deploy-preflight.test.ts asserts both halves of that contract.
|
|
# `needs: lint` is the gate: facts drift, docs parity, tests, ESLint, tsc,
|
|
# and a production build all pass before anything reaches Cloudflare.
|
|
if: >-
|
|
github.event_name == 'workflow_dispatch'
|
|
&& github.ref == 'refs/heads/main'
|
|
# Serialize deploys so two dispatches landing close together cannot race and
|
|
# leave Cloudflare serving the older bundle. Never cancel in progress: a
|
|
# half-finished OpenNext upload is worse than a queued one.
|
|
concurrency:
|
|
group: deploy-codewhale-web
|
|
cancel-in-progress: false
|
|
defaults:
|
|
run:
|
|
working-directory: web
|
|
env:
|
|
CLOUDFLARE_ACCOUNT_ID: ${{ vars.CLOUDFLARE_ACCOUNT_ID }}
|
|
CLOUDFLARE_API_TOKEN: ${{ secrets.CLOUDFLARE_API_TOKEN }}
|
|
steps:
|
|
- uses: actions/checkout@v7
|
|
# Pin the checkout to the exact revision this dispatch resolved, so the
|
|
# SHA reported to compare:deployed-facts and asserted on the public
|
|
# receipt below is the SHA that was actually built, even if main moves
|
|
# while the run is queued behind the concurrency group.
|
|
with:
|
|
ref: ${{ github.sha }}
|
|
- uses: actions/setup-node@v7
|
|
with:
|
|
node-version: 22
|
|
cache: 'npm'
|
|
cache-dependency-path: web/package-lock.json
|
|
- name: Install dependencies
|
|
run: npm ci
|
|
- name: Record deployed/source drift
|
|
# Read-only and credential-free. A mismatch is the normal state here —
|
|
# it is the gap this run is about to close — so this step reports
|
|
# without gating. The real assertion is the post-deploy verification
|
|
# below, which must observe this exact revision on the public receipt.
|
|
run: npm run compare:deployed-facts -- --expected-revision "$GITHUB_SHA"
|
|
- name: Check Cloudflare deploy environment
|
|
run: npm run check:deploy-env
|
|
# npm's deploy script performs one OpenNext build, then deploys that exact
|
|
# bundle. Wrangler must not run a custom post-cache build: OpenNext
|
|
# populates the remote cache before it hands the bundle to Wrangler.
|
|
- name: Build and deploy exact OpenNext bundle
|
|
run: npm run deploy
|
|
- name: Verify exact deployed revision
|
|
# The public /api/facts receipt must identify this workflow's exact
|
|
# checkout before the manual deployment run can finish green.
|
|
run: npm run check:deployed-facts -- --expected-revision "$GITHUB_SHA" --attempts 10 --retry-delay-ms 3000
|