feat(installer): perMachine writes userData to ProgramData; uninstall cleans both#114
feat(installer): perMachine writes userData to ProgramData; uninstall cleans both#114ACCSCI wants to merge 5 commits into
Conversation
… cleans both
This unblocks the install mode page (perUser / perMachine radio) and
makes the data path follow the user's install choice:
- perUser install -> %APPDATA%\AgentDock\ (current user only)
- perMachine install -> %PROGRAMDATA%\AgentDock\ (shared by all users)
Before this change, the global projects DB always lived in
%USERPROFILE%\.agentdock regardless of install mode, which made
perMachine install misleading: the binary was perMachine but the
project list was per-user. Now both move together.
- electron/main/userdata.ts: resolveUserDataPath() picks
ProgramData vs AppData based on process.execPath. Migration
copies legacy perUser AppData into the new location on first
launch after switching install modes.
- electron/main.ts: call app.setPath('userData', resolved) before
any IPC handler registers. Co-locate the global DB with the
rest of the userData.
- plugins/db/global.ts: drop the homedir fallback so the global
DB always follows userData.
- build/installer/custom-uninstall.nsh: NSIS macro that also
cleans %PROGRAMDATA%\AgentDock\ on top of the standard
%APPDATA%\AgentDock\ path electron-builder cleans by default.
- electron-builder.yml: deleteAppDataOnUninstall: true +
include the new uninstall macro.
- electron/main/__tests__/userdata.test.ts: unit coverage for
the decision logic (8/8 tests pass). E2E coverage deferred —
CI doesn't run e2e, so it'll be local-only.
There was a problem hiding this comment.
Code Review
This pull request introduces support for per-machine installation mode on Windows, dynamically resolving the application's user data path to either %PROGRAMDATA% or %APPDATA% depending on the install location, and adds a migration utility for legacy user data. The review feedback highlights a critical logical operator bug in the migration file filtering, potential fragility in detecting the installation mode via hardcoded path substrings, and an issue in the NSIS uninstaller where shared data could be deleted unconditionally during GUI uninstalls. Additionally, it suggests refactoring redundant detection logic in the main process.
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.
customUnInstallSection was compiled into uninstaller.nsh which is
inside a Section body, so commands like ${Silent} and ReadRegStr
(which are valid runtime checks in a Function body but NOT valid in
this Section context) caused compilation to fail with:
'Error: command IfSilent not valid outside Section or Function'
Replace with ${FileExists} + RMDir /r, which are legal NSIS runtime
commands in a Section. The macro now unconditionally cleans
$PROGRAMDATA\AgentDock\ if it exists — regardless of install mode.
For perUser installs (no ProgramData path) the ${FileExists} guard
prevents errors. For perMachine installs it removes the shared data
directory.
… body) customUnInstallSection is expanded at script top-level (after SectionEnd) where runtime NSIS commands are forbidden — and RMDir both cause 'command not valid outside Section or Function' errors. Rename to customUnInstall, which is expanded inside Section 'Uninstall' (line 156-157 of uninstaller.nsh), where runtime commands are valid.
NSIS treats \AgentDock as a single variable lookup (not string concatenation), causing warning 6000 which is fatal in CI. Fix by assigning $PROGRAMDATA to $0 via StrCpy, then appending \AgentDock via StrCpy $0 "$0\AgentDock".
1. userdata.ts:85 — ||→&& in filter (critical: always-true bug) The filter was always true because every string satisfies at least one side. Fixed to && so both files are correctly excluded. 2. custom-uninstall.nsh — replaced NSIS (not a valid NSIS built-in variable, causes warning 6000) with hardcoded 'C:\ProgramData\AgentDock' + StrCpy + guard. This is safe because ProgramData is always English on all Windows locales, and the path doesn't change per-user. 3. electron/main.ts — removed duplicate install mode detection (was re-checking process.execPath manually instead of calling detectInstallMode()) and added the missing import.
概述
把"perMachine 装"和"perUser 装"的语义对齐到数据路径:装到
C:\Program Files\AgentDock\时,数据写到C:\ProgramData\AgentDock\(所有 Windows 用户共享);装到%LOCALAPPDATA%\Programs\AgentDock\时,数据写到%APPDATA%\AgentDock\(当前用户隔离)。安装时保留 install-mode 页面——用户明确知道自己在选什么。改动
resolveUserDataPath()通过process.execPath路径判断安装模式;migrateLegacyUserData()首次启动时把旧%APPDATA%\AgentDock内容复制到新路径(不删旧数据)app.whenReady之前调app.setPath('userData', resolved),并把openGlobalDb()默认路径从~/.agentdock切到 userData 同位置os.homedir()fallback,global DB 永远跟着 userData 走%APPDATA%\AgentDock(标准行为)和%PROGRAMDATA%\AgentDock(perMachine 装的位置)deleteAppDataOnUninstall: true+ 引入自定义卸载宏之前的问题
旧版
perMachine: true装的 exe 装到Program Files\AgentDock\,但 global projects DB 仍然在%USERPROFILE%\.agentdock\projects.db(per-user 路径)——perMachine 装只是名义上"全局",数据其实每个用户独立。新方案让"装模式"和"数据模式"对齐。验证
npx vitest run --project unit electron/main/__tests__/userdata.test.ts—— 8/8 passednpx electron-vite build通过ProgramData、其他用户能访问CI 不跑 e2e,所以实机验证留给人工。
关联
~/.agentdockfallback(plugins/db/global.ts)deleteAppDataOnUninstall