feat(ui): tab 横向滚动 + Ctrl+W 关 project + 新 logo (v0.2.1)#110
Conversation
…ain-process refactor - fix(lifecycle): return backgroundHookPromise=undefined in sync-hook mode so the complete event is sent via process.nextTick; previously sync hooks never triggered onBackgroundHookComplete, leaving createSession.isPending stuck true and the '+' button spinning after the session card had already gone active. - refactor(ui): remove DaemonStatusBar component + styles + testids; single-instance architecture has no separate daemon process, so the bar was a static 'Running' label with no information value. - test: drop 4 v2-daemon specs that asserted on the now-removed bar and on architecture that no longer exists (status-and-fencing, v2-architecture, v2-flow, reconnection). - test(e2e): add scripts/e2e-bun-start-stepwise.ts that simulates bun start → open Copilot-Switch → create session → delete session with real UI clicks; includes a regression guard for the plus-button-spins bug and uses the inner .session-card class for state checks (the testid lives on the wrapper). - chore: bundle miscellaneous in-progress main-process refactor, new e2e specs (agent-e2e-raw, cold-start-race, session-create-progress- persistence, etc.), acceptance scripts, screenshots, and minor formatting touches across many files.
- port-pool: serialize allocate() through a promise chain and reserve picked ports inside the serialized block to prevent two concurrent create-session calls from racing past the bind-probe and grabbing the same ports. - ipc/sessions: add null guard for sessionManager in sessions:delete (matches the existing guards in sessions:create and sessions:reassignPorts). - global-settings: route setPortPoolStart/setPortPoolEnd through updateSettings with strict 1024..65534/1025..65535 clamps and start<end invariant, fixing the 65535→65635 and 1024→1024 edge cases. - instance-lock: mkdirSync the .agentdock parent directory before acquiring the lock, so a fresh userData dir no longer crashes startup with ENOENT. - settings: split handlePortPoolChange (local state) from saveSettings (IPC + disk write); the IPC call now fires on input blur instead of on every keystroke. - ipc/db: wrap JSON.parse(s.steps) in try/catch so a corrupted row doesn't brick the entire db:projects:list handler. - package.json: restore the build:daemon script that CI's 'bun run build:daemon' step still depends on.
Single-instance architecture no longer has a separate daemon process to build. The 'Build daemon JS' step in .github/workflows/build.yml ran build:daemon twice (once standalone, once inside dist:win). Both the script reference and the CI step are removed.
- src/routes/app.$projectId.tsx:22 — change `project?.sessions.find` to
`project?.sessions?.find`. The original parses as `(project?.sessions).find`,
which crashes with 'Cannot read properties of undefined (reading find)'
when useOpenProject inserts a freshly-created project into the React Query
cache without a `sessions` field.
- src/hooks/useOpenProject.ts:insertOrReplaceProject — normalize the inserted
project so `sessions` defaults to [] when missing. The row returned by
`db:projects:create` only has {id, name, path, createdAt}; consumers like
ProjectWorkspace assume the full ProjectData shape.
Verified with e2e/bun-start-simulation.spec.ts — 'Project loaded (no
Project not found)' step now passes (previously triggered the ErrorBoundary
at app.$projectId.tsx:22).
Also includes:
- AGENTS.md rewritten in Chinese to match the single-instance architecture,
testing isolation pipeline (CI does NOT run e2e; parallel tests must use
--user-data-dir + AGENTDOCK_DEV_INSTANCE=1), and the user-agent testing
approach via .flue/. Old link to docs/新架构.md removed (v2 daemon
architecture no longer in use).
- Remove obsolete v2-daemon docs: 新架构.md, v1-deprecation.md,
new-arch-progress.md, main-alignment-audit.md, post-fix-iterations.md,
sse-race-debug.md.
- .flue/ skeleton (agents/user-agent.ts, app.ts, tools/launch-electron.ts)
+ flue.config.ts — initial scaffolding for user-agent testing. The agent
successfully runs end-to-end (Claude Sonnet 4.6 via the project's
Anthropic-compatible gateway) and produced a UX bug report on first run.
The launcher itself hits a Playwright / Node v24 inspector handshake bug
tracked separately; user-agent findings were validated against
e2e/bun-start-simulation.spec.ts instead.
- .gitignore: e2e-report-html/ → e2e/report-html/ (typo: underscore vs slash).
0.2.0 marks the completion of the v2-daemon deprecation arc: - DaemonStatusBar component removed (UI no longer pretends to track a non-existent daemon process) - Single-instance architecture fully documented in AGENTS.md - Project DB + global DB isolation (--user-data-dir + AGENTDOCK_DEV_INSTANCE) replaces what used to be a shared ~/.agentdock/projects.db - 6 obsolete v2-daemon design docs removed (新架构.md, v1-deprecation.md, new-arch-progress.md, main-alignment-audit.md, post-fix-iterations.md, sse-race-debug.md) - project?.sessions.find optional-chain bug fixed; useOpenProject now normalizes inserted projects before writing to the React Query cache See PR #108 for the full diff.
The @flue/cli and @flue/runtime packages were added to package.json but bun.lock was not regenerated. CI's 'bun install --frozen-lockfile' step failed with 'lockfile had changes' — running 'bun install' locally now to capture the resolved package versions.
The 'Build daemon JS' step ran `bun run build:daemon`, which we removed in PR #108 because the v2-daemon architecture is gone and there's nothing to build. The release workflow also had `bun run build:daemon` chained into the final publish step — same removal. After this lands, retag v0.2.0 against master HEAD so the release workflow fires correctly.
…arse Address review comments from gemini-code-assist on PR #108 (now merged into master). Four real bugs fixed: 1. port-pool: serialize allocation via a chain, but a thrown error (e.g. PortPoolExhaustedError) used to poison the queue forever — every subsequent allocate() would reject. Now the queue absorbs the rejection while the original error still propagates to the caller. 2. db:projects:list: per-project DB can be null if db:init hasn't run; return empty session list instead of crashing the renderer. 3. db:projects:delete: same — guard against null per-project DB. 4. ipc/sessions:steps callback: wrap JSON.parse(row.steps) in try/catch to match the defensive parsing in db.ts:322. A corrupted steps blob no longer kills the step-update loop. The 'projectPath is not defined' thread was a false positive — the variable is declared at the top of sessions:create (line 74). The two 'hardcoded local paths' threads (test scripts) are pre-existing technical debt out of scope for this PR.
…/release-workflow-daemon
UI quality-of-life improvements for v0.2.1: - TabBar: enable horizontal scroll. When the tab strip exceeds the window width, the user can now scroll horizontally via trackpad gesture, mouse-wheel (deltaY → scrollLeft), or touch drag. Scrollbar is hidden for visual cleanliness. - TabBar: Ctrl+W / Cmd+W closes the active project tab, matching the common IDE convention. Skipped when an input/textarea/contenteditable has focus so users typing in the terminal or editor aren't surprised. - build/icon.ico: regenerated multi-size ICO (16/32/48/64/128/256) from the new logo design. New agentdock.png is the source raster. electron-builder picks up build/icon.ico automatically — no code references needed. - electron-builder.yml: explicit defensive exclusion of user-data paths (.agentdock/, data/db.sqlite*, global/projects.db*) in the files whitelist. The whitelist was already restrictive enough, but spelling these out makes intent obvious to anyone auditing the installer — the shipped AgentDock-Setup.exe contains only the app bundle, never baked-in user data.
There was a problem hiding this comment.
Code Review
This pull request introduces horizontal scrolling for the project tab bar, adds a Ctrl+W / Cmd+W keyboard shortcut to close the active tab, and adds defensive exclusions in electron-builder.yml to prevent user data directories from being packaged. The reviewer provided several critical pieces of feedback: first, using a global wildcard like !**/data/** in the electron builder configuration risks excluding required runtime assets, so relative paths should be used instead; second, Ctrl+W / Cmd+W shortcuts in Electron are typically intercepted by the main process and will close the window, requiring IPC handling; third, React's onWheel is passive by default, meaning e.preventDefault() will fail and throw warnings, so a manual non-passive event listener via useRef is recommended; and finally, handleRemoveProject should be wrapped in useCallback and added to the useEffect dependency array to prevent potential stale closures.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
Four issues from gemini-code-assist:
1. electron-builder.yml — replace `**/data/**` style global globs with
repo-root-relative patterns (`data/**`, `.agentdock/**`, etc.) so we
don't accidentally exclude runtime resources like `out/renderer/data`
that may legitimately exist inside bundled deps.
2. Ctrl+W shortcut — Electron's default application menu (notably macOS
"Close Window") consumes Ctrl/Cmd+W before the renderer's keydown
fires. Add a before-input-event listener in electron/main/window.ts
that calls event.preventDefault() for Ctrl/Cmd+W so the renderer
handler can take over and close the active project tab.
3. TabBar wheel listener — React's onWheel={...} registers a passive
listener, so e.preventDefault() inside it is silently ignored. Move
to a ref + useEffect pattern that adds the wheel listener with
`{ passive: false }` so we can suppress default vertical scroll.
4. TabBar handleRemoveProject — wrap in useCallback with explicit deps
and add to the Ctrl+W useEffect's dep array, removing the stale
closure risk flagged by the exhaustive-deps lint rule.
概述
v0.2.1 是用户反馈驱动的 UI 修复 + logo 更新小版本。
改动
Tab 横向滚动
当打开的 project tab 超过窗口宽度时,可以横向滚动(mouse wheel / trackpad gesture / 触摸拖动都支持),不再必须关掉一些 tab。滚动条隐藏保持视觉简洁。
src/styles/components/tab-bar.css:overflow-x: auto+ 隐藏滚动条src/components/TabBar.tsx:onWheel handler 把 deltaY 映射到 scrollLeftCtrl+W 关 project
Ctrl+W(macOS 上 Cmd+W)关闭当前 active project tab,符合主流 IDE 习惯。在 input / textarea / contenteditable 中不触发,避免终端/编辑器打字时被误关。
src/components/TabBar.tsx:useEffect 注册全局 keydown listener新 logo
build/icon.ico用 ImageMagick 重新生成多尺寸(16/32/48/64/128/256)从新的 logo 设计。源 PNGbuild/agentdock.png同时入仓作为参考。electron-builder 自动识别build/icon.ico,无需改代码。安装包不打包用户数据
electron-builder.yml的files字段是白名单,本来就不会打用户数据。但显式排除.agentdock/**、data/db.sqlite*、global/projects.db*作为防御,让审计者一眼看清"打包产物里不会有项目数据"。验证
npx electron-vite build通过npx electron-vite preview启动后手动确认 tab 滚动 + Ctrl+W 工作electron-builder --win跑一次,确认 exe 体积没有异常变化、不包含 userData发布计划
合并后 → bump 0.2.0 → 0.2.1 → tag → release workflow 自动出
AgentDock-Setup-0.2.1.exe。