fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Add copy buttons to all
 blocks\n(function() {\n function addCopyButtons() {\n document.querySelectorAll('pre code').forEach(function(codeBlock) {\n if (codeBlock.parentElement.hasAttribute('data-copy-added')) return;\n codeBlock.parentElement.setAttribute('data-copy-added', 'true');\n \n var btn = document.createElement('button');\n btn.textContent = 'Copy';\n btn.style.cssText = 'position:absolute;top:4px;right:4px;padding:2px 8px;font-size:11px;background:#4ecdc4;border:none;border-radius:4px;color:#1a1a2e;cursor:pointer;opacity:0.7;transition:opacity 0.2s;';\n btn.onmouseover = function() { this.style.opacity = '1'; };\n btn.onmouseout = function() { this.style.opacity = '0.7'; };\n btn.onclick = function() {\n navigator.clipboard.writeText(codeBlock.textContent).then(function() {\n btn.textContent = 'Copied!';\n setTimeout(function() { btn.textContent = 'Copy'; }, 1500);\n });\n };\n codeBlock.parentElement.style.position = 'relative';\n codeBlock.parentElement.appendChild(btn);\n });\n }\n \n addCopyButtons();\n \n // Re-run on dynamic content\n var observer = new MutationObserver(addCopyButtons);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Add Copy Buttons to Code Blocks");
}
} catch(__e) { console.warn('[Userscript:Add Copy Buttons to Code Blocks]', __e); }
})();
(function(){
try {
var __m = "github.com";
var __re = new RegExp('^' + "github\\.com" + '
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Force GitHub README to respect dark mode\n(function() {\n var style = document.createElement('style');\n style.textContent = '\n .markdown-body {\n color-scheme: dark light;\n }\n .markdown-body pre { background: #161b22 !important; }\n .markdown-body code { background: rgba(110, 118, 129, 0.4) !important; }\n .markdown-body table th, .markdown-body table td { border-color: #30363d !important; }\n .markdown-body img { background: #0d1117; }\n .markdown-body blockquote { border-left-color: #8b949e; }\n .markdown-body hr { border-color: #30363d; }\n ';\n document.head.appendChild(style);\n})();", "GitHub Dark Mode README Fix"); } } catch(__e) { console.warn('[Userscript:GitHub Dark Mode README Fix]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Highlight search terms from Google/DuckDuckGo/Bing referrer\n(function() {\n var ref = document.referrer;\n var terms = [];\n \n if (ref.includes('google.com') || ref.includes('duckduckgo.com') || ref.includes('bing.com')) {\n var url = new URL(ref);\n var q = url.searchParams.get('q') || url.searchParams.get('p');\n if (q) {\n terms = q.split(/\\s+/).filter(function(t) { return t.length > 2; });\n }\n }\n \n if (terms.length === 0) return;\n \n var style = document.createElement('style');\n style.textContent = '.userscript-highlight { background: #fbbf24; color: #1a1a2e; padding: 1px 3px; border-radius: 2px; }';\n document.head.appendChild(style);\n \n function highlight(node) {\n if (node.nodeType === 3) { // text node\n var text = node.textContent;\n var found = false;\n terms.forEach(function(term) {\n var regex = new RegExp('(' + term.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\') + ')', 'gi');\n if (regex.test(text)) {\n found = true;\n var frag = document.createDocumentFragment();\n var parts = text.split(regex);\n parts.forEach(function(part, i) {\n if (i % 2 === 0) {\n frag.appendChild(document.createTextNode(part));\n } else {\n var span = document.createElement('span');\n span.className = 'userscript-highlight';\n span.textContent = part;\n frag.appendChild(span);\n }\n });\n node.parentNode.replaceChild(frag, node);\n }\n });\n } else if (node.nodeType === 1 && node.childNodes) { // element\n var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT'];\n if (!skipTags.includes(node.tagName)) {\n Array.from(node.childNodes).forEach(highlight);\n }\n }\n }\n \n highlight(document.body);\n \n // Re-highlight on dynamic content\n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1 || node.nodeType === 3) highlight(node);\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Highlight Search Terms"); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Strip utm_, fbclid, gclid, etc. from all links on page\n(function() {\n var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content',\n 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid',\n 'ref', 'ref_src', 'source', 'medium', 'campaign'];\n \n function cleanUrl(url) {\n try {\n var u = new URL(url, window.location.origin);\n var changed = false;\n trackingParams.forEach(function(p) {\n if (u.searchParams.has(p)) {\n u.searchParams.delete(p);\n changed = true;\n }\n });\n return changed ? u.toString() : url;\n } catch (e) {\n return url;\n }\n }\n \n function cleanLinks() {\n document.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n \n cleanLinks();\n \n var observer = new MutationObserver(function(mutations) {\n mutations.forEach(function(m) {\n m.addedNodes.forEach(function(node) {\n if (node.nodeType === 1) {\n if (node.tagName === 'A') cleanLinks();\n node.querySelectorAll('a[href]').forEach(function(a) {\n var clean = cleanUrl(a.href);\n if (clean !== a.href) a.href = clean;\n });\n }\n });\n });\n });\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "Remove Tracking Parameters from Links"); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + '
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Auto-enable theater mode on YouTube\n(function() {\n function tryTheater() {\n var btn = document.querySelector('button[aria-label=\"Theater mode\"], ytd-player #player button[title=\"Theater mode\"]');\n if (btn && !btn.classList.contains('activated')) {\n btn.click();\n }\n }\n \n // Try immediately\n tryTheater();\n \n // Try after navigation (SPA)\n var lastUrl = location.href;\n setInterval(function() {\n if (location.href !== lastUrl) {\n lastUrl = location.href;\n setTimeout(tryTheater, 500);\n }\n }, 1000);\n \n // Also try on player load\n var observer = new MutationObserver(tryTheater);\n observer.observe(document.body, { childList: true, subtree: true });\n})();", "YouTube Theater Mode Default"); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Remove or un-stick sticky/fixed headers that block content\n(function() {\n function unstick() {\n document.querySelectorAll('header, nav, [role=\"banner\"], .header, .navbar, .sticky, .fixed-top, [style*=\"position: fixed\"], [style*=\"position:sticky\"]').forEach(function(el) {\n if (el.style.position === 'fixed' || el.style.position === 'sticky' || \n getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') {\n el.style.position = 'static';\n el.style.top = 'auto';\n el.style.zIndex = 'auto';\n }\n });\n }\n \n unstick();\n \n var observer = new MutationObserver(unstick);\n observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] });\n})();", "Kill Sticky Headers"); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + '
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener
, 'i'); if (__m === '*' || __re.test(location.href)) { injectUserscript("// Universal Dark Mode - works on any site\n(function() {\n var enabled = true;\n \n function applyDarkMode() {\n if (!enabled) return;\n \n // Create style element if it doesn't exist\n var style = document.getElementById('universal-dark-mode-style');\n if (!style) {\n style = document.createElement('style');\n style.id = 'universal-dark-mode-style';\n document.head.appendChild(style);\n }\n \n // Dark mode CSS - inverts colors but preserves images/video\n style.textContent = '\n /* Invert everything except media */\n html {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #1a1a2e !important;\n }\n \n /* Restore images, videos, iframes, canvas */\n img, video, iframe, canvas, svg, picture, [style*=\"background-image\"] {\n filter: invert(1) hue-rotate(180deg) !important;\n }\n \n /* Preserve specific elements that should not be inverted */\n .no-dark-mode, .no-dark-mode *,\n [data-theme=\"light\"], [data-theme=\"light\"],\n .ace_editor, .ace_editor *,\n .CodeMirror, .CodeMirror *,\n .monaco-editor, .monaco-editor *,\n .markdown-body pre, .markdown-body pre *,\n .highlight, .highlight *,\n pre code, pre code * {\n filter: none !important;\n }\n \n /* Fix common UI elements */\n .modal, .popup, .dropdown-menu, .tooltip, .popover {\n filter: invert(1) hue-rotate(180deg) !important;\n background: #2d2d44 !important;\n border-color: #444 !important;\n }\n \n /* Scrollbars */\n ::-webkit-scrollbar { background: #1a1a2e !important; }\n ::-webkit-scrollbar-thumb { background: #444 !important; }\n ::-webkit-scrollbar-thumb:hover { background: #555 !important; }\n \n /* Selection */\n ::selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ::-moz-selection { background: #4ecdc4 !important; color: #1a1a2e !important; }\n ';\n }\n \n function removeDarkMode() {\n var style = document.getElementById('universal-dark-mode-style');\n if (style) style.remove();\n }\n \n // Toggle with Alt+Shift+D\n document.addEventListener('keydown', function(e) {\n if (e.altKey && e.shiftKey && e.key === 'D') {\n e.preventDefault();\n enabled = !enabled;\n if (enabled) {\n applyDarkMode();\n console.log('[Universal Dark Mode] Enabled');\n } else {\n removeDarkMode();\n console.log('[Universal Dark Mode] Disabled');\n }\n }\n });\n \n // Apply on load\n applyDarkMode();\n \n // Re-apply on dynamic content\n var observer = new MutationObserver(function(mutations) {\n if (enabled && !document.getElementById('universal-dark-mode-style')) {\n applyDarkMode();\n }\n });\n observer.observe(document.head, { childList: true });\n \n console.log('[Universal Dark Mode] Loaded - Press Alt+Shift+D to toggle');\n})();", "Universal Dark Mode"); } } catch(__e) { console.warn('[Userscript:Universal Dark Mode]', __e); } })(); })();
Skip to content

fix(desktop): status-color restraint — expected states stop shouting green - #651

Merged
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint
Jul 8, 2026
Merged

fix(desktop): status-color restraint — expected states stop shouting green#651
jackwener merged 1 commit into
mainfrom
fix/status-color-restraint

Conversation

@jackwener

Copy link
Copy Markdown
Member

Addresses the maintainer's report: 权限与能力 still shows residual greens, and permission-toggle toasts show a green left edge ('AI 味').

Diagnosis first: not a token leak

All of these greens ride var(--success) through the governed token system — theme governance is intact. The problem is success-color overuse: the EXPECTED state (granted / enabled / verified / healthy) was painted green across large surfaces, which both reads as old-brand residue and is the classic template-design tell (colored stripe on every card).

Rule applied — exception-only status color

Normal states render neutral. Color is reserved for: states needing attention (denied / not_determined / degraded / needs_reauth), tiny dot-tier indicators (bot status dots, model-list status lines), transient action feedback (copy-success flash), and comparative semantics (permission diff old/new tags, hljs-addition).

Changes

  • Toasts: the per-variant colored left stripe (success green included) is gone for ALL variants — the tinted icon on a neutral card is the single signal
  • 权限与能力: granted rows lose stripe + icon fill + green badge (label 已授权 carries the meaning); enabled capability cards, healthy layer text, granted chips, granted summary count all neutral; denied/waiting keep their color; the 已拒绝 tile only turns red when count > 0, and zero-count tiles dim (matching the health page)
  • 健康: healthy tiles/signal rows keep the default hairline
  • 模型连接: verified/authenticated cards use default card chrome; success badges/pills fall to neutral; OAuth logged-in badge neutral
  • 记忆: the save-summary box is a neutral card, not a green wash
  • Adds a settings-permissions visual-smoke fixture (page had no screenshot baseline)

Verification

  • Desktop suite 2262/2262 green, check-dead-css clean
  • CDP before/after of the permission page confirms: only the genuine exception (等待授权 microphone) still carries color

…green
The 权限与能力 page (and siblings) painted the EXPECTED state green
everywhere: granted OS rows wore a green left stripe + green icon fill +
green 已授权 badge, enabled capability cards a green border, healthy
layers green text, granted chips green pills, the granted summary count
a green number — and every toast carried a colored left stripe. None of
these were token leaks (all rode --success); they were success-color
overuse plus the stripe-on-card template trope.
Rule applied (exception-only): the normal state renders neutral; color
is reserved for states needing attention (denied/degraded/waiting),
tiny dot-tier indicators, transient feedback (copy-成功 flash), and
comparative semantics (permission diff old/new, hljs-addition).
- toast.css: per-variant left stripes removed — the tinted icon is the
single variant signal on a neutral card
- permission page: granted/enabled/success de-tinted across rows, cards,
chips, layers, summary tiles; denied/not_determined keep their stripes;
已拒绝 tile only turns red when count > 0 (a red 0 is a false alarm)
and empty tiles dim like the health page's
- health page: healthy tiles/rows keep the default hairline
- connections: verified/authenticated cards use default chrome;
success badges/pills fall to the neutral base; OAuth logged-in badge
neutral
- memory: save-summary box neutral card instead of green wash
- new settings-permissions visual-smoke fixture so this page finally has
a screenshot baseline
@jackwener
jackwener merged commit dc49e08 into mainJul 8, 2026
3 checks passed
@jackwener
jackwener deleted the fix/status-color-restraint branch July 8, 2026 18:11
jackwener added a commit that referenced this pull request Jul 9, 2026
…s neutral (#696)
使用统计 and 健康 were the last two settings pages without visual-smoke
fixtures — added (settings-usage / settings-health), and the first sweep
found:
- 使用统计: the amber notice's 显示明细 action was a bare text ghost —
outline per the text-buttons-wear-edges rule
- 健康: ok/正常 still rendered success-green on chips AND summary tiles,
while the same #651 restraint rule already made 权限 已授权 neutral —
expected states are neutral; color stays reserved for signals needing
attention (提示/警告/错误 keep their tones)
Desktop 2296/2296, dead-css clean.
jackwener added a commit that referenced this pull request Jul 11, 2026
…mary, honest fade (round 16) (#722)
Post-pull discovery sweep over the externally-merged tip (LiteLLM,
Goal #625, FormatJson, tool-row rework — all reviewed clean, incl. the
Goal kill-switch pill which correctly absorbed the earlier review
blockers). Three finds, fixed:
- 每日回顾 已生成 chip still success-green — the EXPECTED outcome per
the #651 restraint rule (健康 正常 and 权限 已授权 are already
neutral); failures keep destructive.
- 机器人对话 had NO primary at all — 测试并连接 (the form's completion
action) promoted from secondary to default.
- first-run provider list: the 28px bottom fade left a half-clipped row
still half-legible — read as broken clipping; 56px fully veils it.
Also re-learned: the desktop test suite does not compile renderer pages
(a JSX syntax error sailed through 2309 green tests and only vite/
typecheck caught it) — full typecheck now part of this round's gate.
Desktop 2309/2309 + typecheck + dead-css clean; CDP captures verified.
jackwener added a commit that referenced this pull request Jul 18, 2026
* fix(daily-review): compact 跟随设置 label for the panel's inline 分析模型 picker
The run model-option default read 使用设置中的分析模型 — too long for the
compact picker that now rides the PageHeader actions slot (it wrapped to two
lines). Shorten to 跟随设置; a run with no explicit override still falls back to
the model configured in Settings (behavior unchanged — the sentinel value and
bridge mapping are untouched).
* feat(daily-review): real IA redesign of the 每日回顾 module page
The page was 很乱/很不好用: two floating control rows with unclear ownership, a
broken master-detail archive list that left its left column half-empty, a
status Chip on the EXPECTED 已生成 state (#651), a floating orphan line at the
page bottom, and a stats section that vanished entirely on a no-activity day.
Rebuild the information architecture (zero data/IPC/behavior change — same
props, callbacks, guards; contract-pinned run/copy/archive plumbing preserved):
- PageHeader is the page shell: title + subtitle, and the 生成每日回顾 /
生成深度分析 actions ride its actions slot (skills-page pattern). The analysis
model select is now a COMPACT generation option in that same cluster, not a
page-wide row. Header moves into the panel so the actions can compose with the
panel's run state; the bridge-less fallback keeps its own static header.
- ONE time-scope row under the header: the 今日/本周/本月 segmented + the
day-stepper are one visual cluster (both are time navigation) instead of two
widgets at opposite page corners.
- 概览 section is ALWAYS rendered: SectionHeader + the StatTile row shown with
honest zeros even on a no-activity scope, plus one inline muted hint. This
absorbs the old bottom-of-page orphan line, which is deleted — the stats
section no longer disappears into a hole.
- 报告 section replaces the broken master-detail with a stacked, newest-first
list of full-width report surfaces. Each shows an always-visible meta head
(date · 模式 · N 对话 · 触发+时间 · 模型 as muted prose — NO 已生成 chip); the
selected report expands its four content sections in place. Status color is
exception-only now: only 生成失败 / 缺少模型 raise a Chip. Single-selection
lazy body load (getArchive) is unchanged — the archive-body-load contract
pins that path.
- Empty report state is the EmptyState primitive with a CTA wired to
生成每日回顾 (respects the pending/running guards).
- Export (复制/粘到输入框/保存) rides the 概览 SectionHeader action slot, gated
to a non-empty scope (guard shape pinned by the copy-feedback contract).
Re-pin: radius-converge-contract's .maka-daily-review-archive-body surface
entry follows the rename to .maka-daily-review-report (the surface owns the
radius; the expanded body divides with a hairline).
jackwener added a commit that referenced this pull request Jul 18, 2026
…page onto the house language (#1205)
* test(visual-smoke): add module-mcp fixture scenario
Seeds the 扩展 → MCP module surface (sidebarSection 'mcp') with an mcp.json
holding two disabled servers, so the market grid, tab row, hero banner and
installed server list all render deterministically for the alignment auditor
and CDP capture. enabled:false keeps visual-smoke from attempting real npx /
HTTP connections, so rows settle in the neutral 已停用 state.
* feat(mcp): polish MCP page onto the house language
Converge the MCP module page onto the same bar as the 技能 page and the 每日回顾
redesign, presentation-only (same IPC/props/callbacks):
- Hero header now rides the shared PageHeader primitive (as=h2, title/subtitle
+ edged actions cluster; 添加 MCP is the primary CTA).
- Market/installed tabs move onto the shared underline TabsList/TabsTrigger
primitive with count pills, matching the skills tab-row rhythm; the search
field pins to the tab row's right edge.
- Empty + no-results states use the shared EmptyState primitive.
- Installed server status is exception-only (#651): a healthy/expected server
shows no status color — its label rides plain muted text and a neutral dot;
only a real 连接失败 raises a destructive Chip + colored dot.
- The 把 Maka 连接到你的工作环境 banner's pictogram cluster becomes labeled
library-icon tiles (Terminal/Plug/Globe), and the per-template market marks
drop their hand-drawn brand SVGs for the catalog text mark on the existing
brand-tinted tile (de-inlines all 6 inline <svg> in this file — Task A).
* feat(icons): govern the inline-SVG ban and route menu glyphs through the funnel
Hand-drawn inline SVG is an anti-pattern — generic UI glyphs must ride the
@maka/ui/icons lucide funnel so they share one stroke, sizing seam and family.
- menu.tsx: the checkbox + radio ItemIndicator glyphs drop their inline check
<svg> for <Check> from ../icons.js (same precedent as model-picker's
ItemIndicator), keeping the lucide funnel intact.
- icon-governance-contract: a new pin machine-walks packages/ui/src and
apps/desktop/src/renderer (the same tree-walk the repo-wide OverlayScrollbars
ban uses) and fails on any <svg> literal in a .tsx outside an audited
brand-mark allowlist (bot-brand-logo.tsx, provider-brand-marks.tsx). The
allowlist is guarded against rot; new offenders fail with a message pointing
at @maka/ui/icons. icons.tsx needs no exemption — it is a pure lucide
re-export with zero <svg> literals.
* chore(audit): cover module-mcp in the row-alignment auditor
The MCP module page now has a visual-smoke fixture; add it to the
audit-alignment FIXTURES so the row-alignment governance tool sweeps the
polished header, tab row, market grid and installed list too.
jackwener added a commit that referenced this pull request Jul 19, 2026
…ation, flow repairs, fixture coverage (#1233)
* fix(tokens): shift default --info from amber to cool blue (F1)
Default --info was oklch(0.75 0.16 70) amber, colliding with --warning's
orange h55 — info and warning tiers were indistinguishable. Retune the
default light/dark --info to the azure-family blue (h240, matching the
blue-info alt themes) so it reads as informational and stays distinct from
warning. --info-text stays the same color-mix formula; the 406 contrast
contract recomputes dynamically and still passes.
* fix(settings): converge hero metadata badges onto Badge secondary (F2)
health-center used Badge variant=info while voice used a hand-rolled
.settingsFeatureStatusBadge span (blue via --nav-active) — two treatments
for the same quiet-metadata role (只读快照 / 本地自检). Both now use
Badge variant=secondary (the calm neutral pill, same as plan-reminder's
已完成). Deletes the now-dead .settingsFeatureStatusBadge CSS.
* fix(settings): permission 已授权 summary tile neutral not success (F3)
The 已授权 summary tile colored an expected steady state success while its
own granted row chip and health's 正常 tile are neutral. Switch to
tone=neutral per #651 exception-only status color.
* fix(ui): route bare empty states through EmptyState primitive (F5)
task-ledger empty (当前会话没有待推进任务) now uses the compact inline
EmptyState; bot-chat-overview active-list empty (还没有正在使用的渠道) uses
the card EmptyState with a MessageSquare icon, matching skills/daily-review.
Deletes the dead .settingsRemoteAccessEmptyRow CSS, adds a compact-padding
.settingsRemoteAccessEmpty override.
* fix(plans): neutral next-trigger countdown pill on expected state (F6)
The next-run countdown pill was accent-tinted (--nav-active) on an ordinary
scheduled state. Make it a neutral foreground wash per #651; colour stays
reserved for genuinely exceptional states.
* fix(settings): retire orphaned account section, centralize connections in 模型 (U1/U7/U2)
The 'account' SettingsSection rendered AccountSettingsPage but was never in
SETTINGS_NAV, so the header fell back to 通用 copy over the account body, the
sidebar showed no highlight, and a persisted 'account' bounced to models on
reopen. Its connection list and lone 测试凭据 action duplicated the Models page.
- Remove 'account' from SETTINGS_SECTIONS; delete account-settings-page.tsx and
the account-only account-auth-ui.ts + their .account/.auth copy blocks.
- Route every health-notice/onboarding/deep-link consumer to 'models'; drop the
goToAccount copy and the now-single-target ternary. (U2 dead Chips vanish.)
- Derive the settings header from getSettingsNavigationCopy(...).sections[section]
instead of a nav[0] fallback, so an unrouted section fails at the
Record<SettingsSection> boundary instead of silently borrowing a title.
- Add contract tests pinning: every SettingsSection is a nav item (no orphans),
and the header is keyed by the active section, not nav[0].
* fix(composer): guide the post-skip no-model dead end (U3)
After an onboarding skip with zero model connections, Send was disabled with no
explanation. Add an inline hint above the composer (一句话 + 前往模型设置
link-button wired to openSettingsSection('models')) and an explanatory title on
the disabled Send. The hint renders OUTSIDE the <form> so it never grows the
composer's constant footprint (#740), honors the same hidden state, and is
theme-aware via tokens.
* fix(settings): migrate hand-rolled notice families onto Alert primitive (F4)
Consolidate four bespoke notice CSS families onto the shared <Alert>:
- .settingsNotice (info + passive) → Alert variant=info / new variant=passive
- .settingsBotInfoNotice → Alert variant=info (drops the ⓘ glyph)
- .providerUnavailableNotice → Alert variant=info + AlertTitle/Description/Action
- .settingsHealthError → Alert variant=error
Adds a quiet neutral 'passive' variant to the Alert primitive (foreground-5
wash, muted text) so passive notices keep their calm look without a CSS fork.
Migrates ~18 call sites across 11 files; role=status semantics preserved.
Deletes the migrated CSS (and now-dead .settingsNotice[data-tone=passive] /
.settingsNoticeAction). .settingsNotice base rule stays for
account-settings-page.tsx (owned by a separate change).
Contract re-pins: radius-converge drops the two deleted selectors; voice-capture
-smoke, settings-app-info and renderer-startup-fail-soft re-pinned to the Alert
structure. Full desktop (2741) + ui (190) suites, typecheck, check-dead-css,
knip ×2, audit-alignment all green.
* fix(chat): preserve draft on 使用, standardize 接入, teach @/ mentions (U4/U5/U6)
U4: useSkillInChat now appendText()s the skill invocation instead of setText,
so an in-progress draft survives (appendText falls back to a plain set on an
empty draft). Re-pin composer-send-guard.
U5: standardize the IM-bot connect verb to 接入 in bot-chat-detail
(扫码登录/快捷绑定 → 扫码接入/快捷接入) and bot-onboarding-modal (WeChat title
扫码登录 → 连接微信, fixing the redundant 扫码登录扫码接入 dialog aria; WeCom
subtitle 快捷绑定 → 快捷接入). 扫码 gesture kept where literal. e2e re-pinned.
(bot-chat-overview.tsx:138 is owned by another agent — left untouched; see report.)
U6: extend the composer placeholder to teach @ 引用文件 / 选择技能 — one subtle,
theme-agnostic placement that also fixes a zh/en asymmetry (en already hinted).
Also prune the dead account-page CSS the retire left behind (settingsAuthContract*,
settingsAuthActionPill, settingsConnectionDefaultBadge, settingsConnectionList,
settingsEmptyState) and re-pin the geometry/roadmap/a11y contracts that referenced
them. Bind the health-notice label to a local so the static a11y checker sees it.
* test(visual-smoke): capture the 9 missing scenarios, faster teardown, oauth-relogin detail sheet (#7a/b/d)
7a: add the 9 registered-but-uncaptured scenarios to capture-screenshots
ALL_SCENARIOS (oauth-relogin, settings-permissions/voice/gateway/search/usage/
health, module-mcp, long-transcript) so screenshot review has evidence of them.
7b: driver teardown after the capture marker now SIGKILLs instead of SIGTERM —
the marker is already on disk so Electron has nothing to flush; the audit
measured ~60s of graceful-teardown wait per capture, now 2-3s. No cleanup
regression (per-run user-data dir is under os.tmpdir()).
7d: oauth-relogin fixture now opens the seeded codex-oauth connection's detail
sheet (needs_reauth) instead of just the 模型 section, so the re-login
affordance is what gets captured. Threads a new openConnectionDetailSlug through
VisualSmokeState → app-shell-visual-smoke → useSettingsModal.openConnectionDetail
→ overlays → SettingsModal → SettingsSurface → ProvidersPanel.initialConnectionSlug,
mirroring the existing openProviderCatalog path.
* test(ui): re-pin composer placeholder (U6) and markdown nav-link example (U1)
conversation-localization: pin the new @ 引用文件 / 选择技能 placeholder in both
locales. markdown-body: the internal-nav-link sanitization example used
maka://settings/account, now invalid after the account section retire — use
maka://settings/models.
* test(ui): pin the U3 no-model composer hint + disabled-send title
Renders Composer with noModelConnection and asserts the inline hint, the
前往模型设置 link-button, and the explanatory disabled-Send title appear (and are
absent by default) in both locales.
* chore(ui): cross-wave integration — retire the last settingsNotice remnants
Wave A kept the .settingsNotice base rule alive solely for
account-settings-page; Wave B retired that page, so the rule and its
radius-converge entry go with it.
jackwener added a commit that referenced this pull request Jul 20, 2026
…itive, dense health/permission rows, dialect cleanup (#1274)
* feat(ui): extract DataTable primitive from usage stats table
Promote the #1252 hairline table recipe out of usage-settings-page into a
shared DataTable primitive (@maka/ui) now that it has health + permission
consumers. The primitive owns the table markup: muted+medium scoped col
headers, first-cell-as-scoped-row-header, hairline row separators,
right-aligned tabular-nums numeric columns, and one grow column that absorbs
slack while the rest size to content on one line.
UsageStatsTable becomes a thin wrapper: it keeps the usage-local empty-tab
routing (EmptyState icon+copy) that a table primitive deliberately omits, and
delegates the non-empty branch to <DataTable>. Rendering is pixel-identical —
every utility class and the settingsUsageTable pin class are preserved.
Re-pin: the moved table markup is now guarded by packages/ui data-table.test
(renderToStaticMarkup); settings-usage-contract's stats-table assertions follow
the split — keep the wrapper's typed-column + EmptyState signature, assert
delegation to <DataTable>, and forbid a hand-rolled <table>.
* refactor(settings): kill the .settingsAboutPrivacy blue-header dialect
The uppercase brand-blue h3 + brand-deep tinted card was a fourth section-
header voice, used by 关于's privacy card AND (confusingly) 数据's 配置导入
导出 header — the reason 数据's export section wore a blue header.
Converge both onto the sanctioned language:
- 关于 privacy → SectionHeader (as=h3) + Alert variant=passive holding the
privacy points (a quiet 'just so you know' callout; matches the passive
Alert language already on the data page's backup notice).
- 数据 config → SectionHeader (as=h3, configHelp as subtitle) over the form
controls, no card chrome (it's a form, not a callout).
Widen SectionHeader's `as` to accept h3 (a section under a page h2). Delete
the .settingsAboutPrivacy CSS block (incl. the green ::marker) for neutral
gap containers. Re-pin radius-converge (drop the stale selector) and
settings-app-info (name now scopes at the section) contracts.
* polish(ui): converge search pre-search hint + fix gateway 5-tile grid
- search-modal: route the pre-search guidance line through the shared
EmptyState inline primitive instead of a bare <p>, so the 'start typing'
hint uses the sanctioned empty-state language (keeps the placeholder pin
class so layout is unchanged).
- open-gateway: the posture strip has five metric tiles but reused the
four-column .settingsUsageSummary grid, orphaning the fifth on a second
row. Give it .settingsGatewaySummary — 5-up on wide, clean 3-up (3 + 2)
wrap when the pane narrows.
* polish(permissions): drop the OS-row status stripe (#651)
Each OS-permission row already shows its state as a Badge; the left-edge
status stripe (amber on 等待授权, red on 已拒绝) was a redundant second status
channel, and the amber stripe read as a standing alarm on an expected waiting
state. Remove both stripe rules and the now-orphaned position:relative anchor;
the row's Chip/text is the single state signal (the denied icon tint stays as
the one exception accent).
* refactor(providers): converge .providerRootHeader onto SectionHeader
The 已连接 and 添加新连接 section titles were a bespoke flex header (bold h3
+ muted help + far-right count) — a fourth section-header dialect. Converge
both onto the shared SectionHeader primitive: title + subtitle, and the
connection count rides SectionHeader's count slot (tabular-nums baked in).
Extend SectionHeader with an optional titleId so the catalog section keeps
its aria-labelledby link. Delete the .providerRootHeader CSS family. Re-pin:
tabular-nums-converge (drop the removed selector, add a SectionHeader
primitive pin) and provider-navigation (catalog title now on SectionHeader
via titleId).
* polish(settings): converge health/permission onto dense shared-language rows
Polish wave (wave 2) — kill the bordered-block dialect on the Health and
Permission Center pages and the redundant gray intro banners.
- Item 2 (健康): HealthSignalRow bordered blocks -> shared Item row
primitive inside one hairline card; prose message + detail keep stacked
secondary lines, status is a squared Chip (exception-only color via its
tone scale), send/capability blockers are exception Chips. Meta on one
tabular-nums line. Deleted the bespoke .settingsHealthSignalRow* CSS.
- Item 3 (权限): CapabilityRow bordered blocks -> dense hairline-divided
rows in one card matching the OS permission list above; the nested gray
boxed .settingsCapabilityLayers dl becomes structured secondary lines
(no nested surface). readiness Badge -> Chip. Kept the dl + aria-label
and the diagnostics collapse.
- Item 5: the second gray-banner PageHeader on each page
(.settingsHealthIntro / .settingsPermissionIntro) restating the page
title -> SectionHeader; unique subtitle kept, badge/timestamp/refresh
moved into the action slot, banner chrome dropped.
Re-pins: radius-converge SELECTOR_TIER drops the retired
.settingsHealthIntro/.settingsPermissionIntro/.settingsCapabilityRow radius
entries and adds the new .settingsCapabilityList/.settingsHealthSignalList
card entries. roadmap-cleanup + capability-audit contracts unchanged.
Verified light+dark via direct CDP over settings-health / settings-permissions.
Gates: desktop main + @maka/ui suites, full typecheck, check-dead-css,
audit-alignment (settings-permissions clean) all green.
* test(gateway): re-pin summary-strip aria assertions to settingsGatewaySummary
Wave 1 renamed the tile strip class (fixing the 4+1 orphan grid) and kept
role=group + aria-label, but the network-gateway contract's regexes pinned
the old settingsUsageSummary class name — the one re-pin the wave missed.
Also corrects the earlier triage: the failure was branch-caused, not
pre-existing on main.
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@jackwener