| Files | Last commit | Last update |
|---|---|---|
fix(icons): derive icon alpha from luminance, and drop the bitmap logo from the UI The white square behind the mark came back with a different shape this time: the corner mask radius was estimated from the image size, so wherever it disagreed with the badge's own radius a ring of white canvas stayed opaque. - make_icons: alpha is now a linear function of luminance (canvas ~250 -> 0, badge <150 -> 1) with a 1px erosion so edges land on badge colour, not on a white/badge blend. Pure Pillow, no numpy, so the CI icon contract still runs. - check_icons: also fails on any near-white visible pixel and on white inside the 3% edge ring, not just on opaque corners. - The sidebar and the overview masthead no longer load a bitmap at all: they render BrandMark, four vector strokes with currentColor and no plate. - BrandMark has its own test for the 'no rect / no image / no fill' contract. | 17 days ago | |
feat(ui): pick transport at startup and keep the mode visible The frontend called invoke() directly, so outside Tauri it silently fell back to demoBundle() — a browser could only ever see fake processes. Now transport.ts resolves IPC vs REST vs demo once at boot, shares one probe across concurrent callers, and broadcasts the result so the badge can switch from its placeholder. isTauri() stays a synchronous check (no network), because the first frame must not flicker into the wrong mode; isBackend() is the "do I have real data" question that pages ask. Header and sidebar show Live / Web · live data / Demo so a number on screen is never ambiguous. Three defects found while verifying the result visually: - port "open" was hardcoded to http://localhost:PORT — wrong for IPv6 listeners, HTTPS services and UDP ports; now derived from the actual listen address with UDP dropped. - every overlay used bg-black/55, which in the (now default) light theme turned the page into grey mud under a 2px blur; scrim colour follows data-chart-theme. - the cost trend axis mixed 2026-06 (monthly bucket) with 10-25 (daily), so readers could not tell which points were months; unified to 26/6月 vs 10-25, and the parser now checks shape instead of length so "unknown" no longer becomes un/NaN月. | 1 day ago | |
feat(cost): 0.5.0 — per-project attribution, ledger export, extended trend Per-project attribution: - project_breakdown_sql groups the ledger by project directory, ordered by spend; dashboard card with per-project bars. - estimated rows follow the include-estimated switch like every other money view. Ledger export: - get_cost_export returns raw records (bounded 200k, day+path ordered, estimated rows included - cost_source states itself). - CSV reuses RFC 4180 escaping + formula-injection guard, full float precision; JSON export with matching field names. Extended trend: - get_cost_trend_extended: daily window + monthly buckets strictly before it (no overlap by construction); 14/30/90-day switcher. - trend chart labels months as YYYY-MM, days as MM-DD. Tests: +5 Rust (ordering, estimated filter, bucket boundaries, export limits), +10 frontend (store loadCostTrend paths, demo bundle contract, diagnostics persistence, export escaping). 441 unit + 136 backend, coverage 85.7% branches, clippy clean, e2e 23 passed (costs baseline regenerated for the new cards). Chore: version 0.5.0 across six places; roadmap marks 0.5.0 done and corrects the budget-alert status (it shipped in 0.4.0). | 4 days ago | |
fix(release): make the installed build actually usable — 0.7.1 Acceptance testing followed the real user path (silent install → launch → page-by-page walkthrough) and found two defects that only exist on an end-user machine, both invisible to every prior gate: - **Installed Web mode returned 404 for the page.** The install dir holds one exe and no dist/; the static-dir fallback chain ended at CARGO_MANIFEST_DIR/../dist — the build machine's source tree. Verified by moving dist away: GET / went 404 while /api stayed fine. Frontend assets are now embedded at compile time (rust-embed, 34 files, ~1.3 MB), so workbench serve is self-contained; a disk dist still wins so frontend-only iteration doesn't need a Rust rebuild. /api misses still return 404 JSON instead of falling through to the SPA. - **Pricing editor showed "desktop-only" in the browser.** Its load gate was isTauri() and the HTTP side had no pricing endpoint at all. Added GET/PUT /api/cost/pricing sharing the desktop validation (all-or-nothing), gate changed to isBackend(). Verified PUT → pricing_overrides.json → read-back identical. Acceptance walkthrough also confirmed working: project/task creation with restart persistence, process search + virtual scrolling, command palette jump, diagnostics (7 checks) in web mode, honest log-page degradation, theme badge "Web · live data". Uninstaller removes dir and registry key. | 19 hours ago | |
fix(release): make the installed build actually usable — 0.7.1 Acceptance testing followed the real user path (silent install → launch → page-by-page walkthrough) and found two defects that only exist on an end-user machine, both invisible to every prior gate: - **Installed Web mode returned 404 for the page.** The install dir holds one exe and no dist/; the static-dir fallback chain ended at CARGO_MANIFEST_DIR/../dist — the build machine's source tree. Verified by moving dist away: GET / went 404 while /api stayed fine. Frontend assets are now embedded at compile time (rust-embed, 34 files, ~1.3 MB), so workbench serve is self-contained; a disk dist still wins so frontend-only iteration doesn't need a Rust rebuild. /api misses still return 404 JSON instead of falling through to the SPA. - **Pricing editor showed "desktop-only" in the browser.** Its load gate was isTauri() and the HTTP side had no pricing endpoint at all. Added GET/PUT /api/cost/pricing sharing the desktop validation (all-or-nothing), gate changed to isBackend(). Verified PUT → pricing_overrides.json → read-back identical. Acceptance walkthrough also confirmed working: project/task creation with restart persistence, process search + virtual scrolling, command palette jump, diagnostics (7 checks) in web mode, honest log-page degradation, theme badge "Web · live data". Uninstaller removes dir and registry key. | 19 hours ago | |
feat(ui): pick transport at startup and keep the mode visible The frontend called invoke() directly, so outside Tauri it silently fell back to demoBundle() — a browser could only ever see fake processes. Now transport.ts resolves IPC vs REST vs demo once at boot, shares one probe across concurrent callers, and broadcasts the result so the badge can switch from its placeholder. isTauri() stays a synchronous check (no network), because the first frame must not flicker into the wrong mode; isBackend() is the "do I have real data" question that pages ask. Header and sidebar show Live / Web · live data / Demo so a number on screen is never ambiguous. Three defects found while verifying the result visually: - port "open" was hardcoded to http://localhost:PORT — wrong for IPv6 listeners, HTTPS services and UDP ports; now derived from the actual listen address with UDP dropped. - every overlay used bg-black/55, which in the (now default) light theme turned the page into grey mud under a 2px blur; scrim colour follows data-chart-theme. - the cost trend axis mixed 2026-06 (monthly bucket) with 10-25 (daily), so readers could not tell which points were months; unified to 26/6月 vs 10-25, and the parser now checks shape instead of length so "unknown" no longer becomes un/NaN月. | 1 day ago | |
feat(ui): pick transport at startup and keep the mode visible The frontend called invoke() directly, so outside Tauri it silently fell back to demoBundle() — a browser could only ever see fake processes. Now transport.ts resolves IPC vs REST vs demo once at boot, shares one probe across concurrent callers, and broadcasts the result so the badge can switch from its placeholder. isTauri() stays a synchronous check (no network), because the first frame must not flicker into the wrong mode; isBackend() is the "do I have real data" question that pages ask. Header and sidebar show Live / Web · live data / Demo so a number on screen is never ambiguous. Three defects found while verifying the result visually: - port "open" was hardcoded to http://localhost:PORT — wrong for IPv6 listeners, HTTPS services and UDP ports; now derived from the actual listen address with UDP dropped. - every overlay used bg-black/55, which in the (now default) light theme turned the page into grey mud under a 2px blur; scrim colour follows data-chart-theme. - the cost trend axis mixed 2026-06 (monthly bucket) with 10-25 (daily), so readers could not tell which points were months; unified to 26/6月 vs 10-25, and the parser now checks shape instead of length so "unknown" no longer becomes un/NaN月. | 1 day ago | |
release: v0.6.0 — 视觉 2.0 与全量新截图 - 全套 README 截图按视觉 2.0 后的 UI 重拍(en/zh/ja ×18 张), 新增 6 个镜头:氛围粒子、自定义背景、空态插画、首启引导、 Midnight 暗色、Aurora 玻璃。 - shoot_docs.mjs 迁移到 Playwright(无头 Edge 合成器在 fixed dataURL 背景下 captureScreenshot 只出背景层,DOM 完好—— 换 e2e 同栈后一致可靠)。 - fix(app): 内容列显式 relative z-10 —— 背景图层(fixed z-0、 DOM 靠后)按画家算法盖过 z-auto 的 relative 兄弟,壁纸会糊在 正文上(有头/无头均复现,截图流程抓到的真 bug)。 - 版本 0.6.0 六处同步;CHANGELOG 定稿;README 徽章 489+136。 - 489 单测 + e2e 连跑两遍 23 全过;version:check --tag 通过。 | 3 days ago | |
feat(diagnostics,theme): frontend diagnostics buffer, logs filtering, and a light default that does not flash Frontend diagnostics: - src/lib/diagnostics.ts: capture global error / unhandledrejection (beyond what ErrorBoundary sees), keep the last 50 with id, kind, stack and page; consecutive duplicates collapse; localStorage only. - ErrorBoundary: expandable stack + one-click copy for issue reports, crashes also land in the buffer. - Settings -> Diagnostics: frontend error list, clear button, appended to the copyable report. Theme: - default is light Frost; index.html pins first-paint tokens and syncs saved polarity before paint, so neither polarity flashes. - accentsoft is solved from the 4.6:1 target per theme instead of a fixed mix ratio (Frost measured 4.45:1 before); test covers all eight built-ins. - theme editor shows an auto-adjusted badge when the contrast solve will change the user's color on save. Logs page: - finish the interrupted edit: split("\n") was broken across lines, LogLevel / levelOf were referenced but missing; add keyword search, level filter with counts, shown/total line counter; log pane uses theme-derived panel2 instead of a hardcoded dark mix (timestamps measured 4.02:1 on Frost). E2E: custom-theme accent asserts hue preserved + AA after the solve; visual baselines regenerated for the light default. | 4 days ago | |
feat(diagnostics,theme): frontend diagnostics buffer, logs filtering, and a light default that does not flash Frontend diagnostics: - src/lib/diagnostics.ts: capture global error / unhandledrejection (beyond what ErrorBoundary sees), keep the last 50 with id, kind, stack and page; consecutive duplicates collapse; localStorage only. - ErrorBoundary: expandable stack + one-click copy for issue reports, crashes also land in the buffer. - Settings -> Diagnostics: frontend error list, clear button, appended to the copyable report. Theme: - default is light Frost; index.html pins first-paint tokens and syncs saved polarity before paint, so neither polarity flashes. - accentsoft is solved from the 4.6:1 target per theme instead of a fixed mix ratio (Frost measured 4.45:1 before); test covers all eight built-ins. - theme editor shows an auto-adjusted badge when the contrast solve will change the user's color on save. Logs page: - finish the interrupted edit: split("\n") was broken across lines, LogLevel / levelOf were referenced but missing; add keyword search, level filter with counts, shown/total line counter; log pane uses theme-derived panel2 instead of a hardcoded dark mix (timestamps measured 4.02:1 on Frost). E2E: custom-theme accent asserts hue preserved + AA after the solve; visual baselines regenerated for the light default. | 4 days ago | |
feat(ui): pick transport at startup and keep the mode visible The frontend called invoke() directly, so outside Tauri it silently fell back to demoBundle() — a browser could only ever see fake processes. Now transport.ts resolves IPC vs REST vs demo once at boot, shares one probe across concurrent callers, and broadcasts the result so the badge can switch from its placeholder. isTauri() stays a synchronous check (no network), because the first frame must not flicker into the wrong mode; isBackend() is the "do I have real data" question that pages ask. Header and sidebar show Live / Web · live data / Demo so a number on screen is never ambiguous. Three defects found while verifying the result visually: - port "open" was hardcoded to http://localhost:PORT — wrong for IPv6 listeners, HTTPS services and UDP ports; now derived from the actual listen address with UDP dropped. - every overlay used bg-black/55, which in the (now default) light theme turned the page into grey mud under a 2px blur; scrim colour follows data-chart-theme. - the cost trend axis mixed 2026-06 (monthly bucket) with 10-25 (daily), so readers could not tell which points were months; unified to 26/6月 vs 10-25, and the parser now checks shape instead of length so "unknown" no longer becomes un/NaN月. | 1 day ago | |
feat(cost): 0.5.0 — per-project attribution, ledger export, extended trend Per-project attribution: - project_breakdown_sql groups the ledger by project directory, ordered by spend; dashboard card with per-project bars. - estimated rows follow the include-estimated switch like every other money view. Ledger export: - get_cost_export returns raw records (bounded 200k, day+path ordered, estimated rows included - cost_source states itself). - CSV reuses RFC 4180 escaping + formula-injection guard, full float precision; JSON export with matching field names. Extended trend: - get_cost_trend_extended: daily window + monthly buckets strictly before it (no overlap by construction); 14/30/90-day switcher. - trend chart labels months as YYYY-MM, days as MM-DD. Tests: +5 Rust (ordering, estimated filter, bucket boundaries, export limits), +10 frontend (store loadCostTrend paths, demo bundle contract, diagnostics persistence, export escaping). 441 unit + 136 backend, coverage 85.7% branches, clippy clean, e2e 23 passed (costs baseline regenerated for the new cards). Chore: version 0.5.0 across six places; roadmap marks 0.5.0 done and corrects the budget-alert status (it shipped in 0.4.0). | 4 days ago | |
feat(states,autostart,perf): page-level states, real start-at-login, and a complexity pass Page states: ErrorState (role=alert + retry), Skeleton/SkeletonCard and Empty.action are now used by Processes, Servers, Projects, Tasks, the cost dashboard and the overview widgets. A backend failure shows an in-page error instead of a toast that disappears; a first load shows the shape of the data instead of four zeroed cards. Start at login: tauri-plugin-autostart registers the real OS entry (HKCU Run on Windows, ~/.config/autostart on Linux, LaunchAgent on macOS). The toggle reads is_enabled on every mount, so an entry removed in Task Manager shows as off. Browser preview never calls IPC. Verified against the packaged exe: enable / disable / UI state (3 checks in scripts/e2e-desktop.mjs). Charts: ECharts moved to its own chunk behind a lazy wrapper. Settings, Logs, Tasks and Projects no longer download 540 KB they never draw. Production measurement: FCP 180 ms, chart block requested after the overview paints. Complexity: every function in src/ is now <= 10 (was App 43, CostDashboard 32, parseTheme 22, buildTheme 19, Agent 17, Processes 14). New modules: useAppRuntime, useShellLayout, pages/processFilter, pages/processes/ProcessTable, pages/servers/DevServerList, pages/ai/costCharts. Fixes found while doing the above: - readableOn blended towards the background, so it could never reach 4.5:1 on light themes; it returned the original 2.78:1 grey. Now solves towards black/white first, then fades back (4 tests measure the ratio). - Editing a built-in theme wrote its id into the custom list, where findTheme kept returning the built-in: every edit looked like it did nothing. Editing now duplicates first (editableTheme + 2 tests). - Ledger layout laid a 168 px donut across a 1146 px row; small panels are now paired, large ones stay full width. - Three READMEs still described pricing overrides as read-only and port collection as Windows-only, two releases after both changed. Verification: tsc, eslint, prettier clean; 324 unit tests; coverage 93.66% lines / 85.81% branches (store 95.52%, api 94.73%, ui 89.88%); 16 Playwright visual + contrast tests; 16 desktop E2E checks against the packaged exe. | 15 days ago | |
fix(security,ui): preserve UNC prefixes, unblock main thread, real focus trap - normalize_path dropped the leading // of UNC paths, so \server\share and the relative string server/share collapsed to the same whitelist key: an entry registered for one matched lookups for the other. Bare drive letters (c:) are now rejected too, since they resolve against the CWD. - save_data/load_data called Path::is_dir() on the main thread. A disconnected UNC share or offline mapped drive blocks for seconds on SMB timeout, and save_data fires on a 300ms debounce after every edit. Both commands are now async and validate on a blocking thread (KnownDirs holds an Arc). - Modal's focus trap only intercepted when focus sat exactly on the first or last control. Clicking non-focusable body text moved activeElement to body, and the next Tab walked into the page behind the dialog. The trap now listens on document (keydown capture) and pulls focus back whenever it escapes. Regressions cover both escape and focus restoration. - updateCostSettings also lacked the isTauri() guard (missed in 9d96537) - confirm dialog reused the sentence-length title as its button label; add a dedicated projects.deleteAction key in all three languages | 18 days ago | |
feat(ui): pick transport at startup and keep the mode visible The frontend called invoke() directly, so outside Tauri it silently fell back to demoBundle() — a browser could only ever see fake processes. Now transport.ts resolves IPC vs REST vs demo once at boot, shares one probe across concurrent callers, and broadcasts the result so the badge can switch from its placeholder. isTauri() stays a synchronous check (no network), because the first frame must not flicker into the wrong mode; isBackend() is the "do I have real data" question that pages ask. Header and sidebar show Live / Web · live data / Demo so a number on screen is never ambiguous. Three defects found while verifying the result visually: - port "open" was hardcoded to http://localhost:PORT — wrong for IPv6 listeners, HTTPS services and UDP ports; now derived from the actual listen address with UDP dropped. - every overlay used bg-black/55, which in the (now default) light theme turned the page into grey mud under a 2px blur; scrim colour follows data-chart-theme. - the cost trend axis mixed 2026-06 (monthly bucket) with 10-25 (daily), so readers could not tell which points were months; unified to 26/6月 vs 10-25, and the parser now checks shape instead of length so "unknown" no longer becomes un/NaN月. | 1 day ago | |
chore(release): cut 0.4.0, add version gate and fix chart label contrast The version number lived in four files plus a fifth hand-written copy in the UI. Bump to 0.4.0, move the single source to package.json, inject it at build time, and add npm run version:check to CI so a half-finished bump cannot ship. Three chart regressions found by reading the rendered screenshots: - Horizontal bar value labels inherited the series gradient colour and became near-invisible on dark themes (the "3" in the port distribution read as an empty cell). Labels now use the theme text colour. - Bar-top labels in the process histograms collided with the top gridline; the value axis gets one extra step and no split line. - The AI memory chart put its "NNN MB" label on top of the axis tick; the axis now leaves 30% headroom and the grid widened to fit the label. Also: unify the workflow branch filters on main, document the branch and versioning policy in CONTRIBUTING, add docs/ROADMAP.md with an explicit not-planned section, replace GitHub-only badges with platform-neutral ones, and regenerate the screenshots and the four affected visual baselines. | 5 days ago |
| Files | Last commit | Last update |
|---|---|---|
| 17 days ago | ||
| 1 day ago | ||
| 4 days ago | ||
| 19 hours ago | ||
| 19 hours ago | ||
| 1 day ago | ||
| 1 day ago | ||
| 3 days ago | ||
| 4 days ago | ||
| 4 days ago | ||
| 1 day ago | ||
| 4 days ago | ||
| 15 days ago | ||
| 18 days ago | ||
| 1 day ago | ||
| 5 days ago |