Fix Windows install start: writable runtime logs and robust Postgres bootstrap.
Some checks failed
Release Windows / build (push) Has been cancelled

API logs go under ProgramData; first-run verifies CREATE ROLE/DATABASE and login.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
oliver 2026-10-07 11:22:01 +08:00
parent ca97a2a597
commit 86dfd41f44
7 changed files with 64 additions and 33 deletions

View file

@ -148,6 +148,7 @@ function Get-NetxDataEnvMap {
"NETX_AUTH_MCP_TOKEN_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\mcp_token"))
"NETX_AUTH_SECRET_FILE" = (ConvertTo-NetxFsPath (Join-Path $d "data\auth\jwt_secret"))
"NETX_SCHEDULER_HEARTBEAT_PATH" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime\scheduler_heartbeat.json"))
"NETX_RUN_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\runtime"))
"NETX_BIZ_STATE_SPOOL_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\biz_state_spool"))
"NETX_NE_COLLECTION_DATA_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_collections"))
"NETX_NE_EXEC_JOB_DIR" = (ConvertTo-NetxFsPath (Join-Path $d "data\ne_exec_jobs"))

View file

@ -1,10 +1,10 @@
; NetX Windows installer (Inno Setup 6+)
; NetX Windows installer (Inno Setup 6+)
; Compile after: packaging\build_release.ps1
; ISCC.exe packaging\installer\netx.iss
#define MyAppName "NetX"
#ifndef MyAppVersion
#define MyAppVersion "0.4.4"
#define MyAppVersion "0.4.5"
#endif
#define MyAppPublisher "NetX"
#define MyAppURL "https://github.com/hansjone/netx"
@ -34,7 +34,7 @@ WizardStyle=modern
ArchitecturesAllowed=x64compatible
ArchitecturesInstallIn64BitMode=x64compatible
PrivilegesRequired=admin
; Data lives under {commonappdata}\NetX — not overwritten by upgrades
; Data lives under {commonappdata}\NetX 鈥?not overwritten by upgrades
CloseApplications=yes
ShowLanguageDialog=yes
@ -50,20 +50,19 @@ english.StartTrayNow=Start NetX tray now
english.EnableAutostart=Start NetX tray at Windows logon
english.EnableAutoUpdate=Enable daily silent auto-update (needs network later)
english.InstallService=Install as Windows Service (uses bundled WinSW, offline)
chinesesimplified.CreateDesktopIcon=创建桌面快捷方式
chinesesimplified.SetupOptions=安装选项:
chinesesimplified.RunFirstSetup=安装后运行首次配置(内置数据库,可离线)
chinesesimplified.StartTrayNow=立即启动 NetX 托盘
chinesesimplified.EnableAutostart=开机时自动启动 NetX 托盘
chinesesimplified.EnableAutoUpdate=启用每日静默自动更新(以后需要联网)
chinesesimplified.InstallService=安装为 Windows 服务(使用已捆绑的 WinSW,可离线)
chinesesimplified.CreateDesktopIcon=鍒涘缓妗岄潰蹇嵎鏂瑰紡
chinesesimplified.SetupOptions=瀹夎閫夐」:
chinesesimplified.RunFirstSetup=瀹夎鍚庤繍琛岄娆¢厤缃紙鍐呯疆鏁版嵁搴擄紝鍙绾匡級
chinesesimplified.StartTrayNow=绔嬪嵆鍚姩 NetX 鎵樼洏
chinesesimplified.EnableAutostart=寮€鏈烘椂鑷姩鍚姩 NetX 鎵樼洏
chinesesimplified.EnableAutoUpdate=鍚敤姣忔棩闈欓粯鑷姩鏇存柊锛堜互鍚庨渶瑕佽仈缃戯級
chinesesimplified.InstallService=瀹夎涓?Windows 鏈嶅姟锛堜娇鐢ㄥ凡鎹嗙粦鐨?WinSW锛屽彲绂荤嚎锛?
[Tasks]
Name: "desktopicon"; Description: "{cm:CreateDesktopIcon}"; GroupDescription: "{cm:AdditionalIcons}"; Flags: checkedonce
Name: "firstrun"; Description: "{cm:RunFirstSetup}"; GroupDescription: "{cm:SetupOptions}"; Flags: checkedonce
[Files]
; Entire release stage → {app}. Exclude .portable so installed builds use ProgramData.
; Entire release stage 鈫?{app}. Exclude .portable so installed builds use ProgramData.
Source: "{#StageDir}\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs; Excludes: ".portable"
[Dirs]
@ -99,5 +98,6 @@ Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\p
Filename: "powershell.exe"; Parameters: "-ExecutionPolicy Bypass -File ""{app}\packaging\install_service.ps1"" -ProgramRoot ""{app}"" -DataRoot ""{commonappdata}\NetX"" -Start"; WorkingDir: "{app}"; Description: "{cm:InstallService}"; Flags: postinstall skipifsilent unchecked
[UninstallDelete]
; Do NOT delete {commonappdata}\NetX — preserves DB and secrets across reinstall
; Do NOT delete {commonappdata}\NetX 鈥?preserves DB and secrets across reinstall
Type: filesandordirs; Name: "{app}"

View file

@ -1,11 +1,11 @@
{
"channel": "stable",
"latest": "0.4.4",
"latest": "0.4.5",
"min_compatible": "0.3.0",
"notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.4",
"notes_url": "https://github.com/hansjone/netx/releases/tag/v0.4.5",
"windows": {
"url": "https://github.com/hansjone/netx/releases/download/v0.4.4/NetX-0.4.4-win64.zip",
"setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.4/NetX-Setup-0.4.4.exe",
"url": "https://github.com/hansjone/netx/releases/download/v0.4.5/NetX-0.4.5-win64.zip",
"setup_url": "https://github.com/hansjone/netx/releases/download/v0.4.5/NetX-Setup-0.4.5.exe",
"sha256": "",
"size": 0
}

View file

@ -153,21 +153,37 @@ if ($DbMode -eq "bundled") {
$env:PGPASSWORD = $BundledPassword
try {
$role = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -tAc "SELECT 1 FROM pg_roles WHERE rolname='netx'"
if ($role -notmatch "1") {
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
-c "CREATE ROLE netx LOGIN PASSWORD '$sqlPw';"
function Invoke-NetxPsql {
param([string]$Sql, [string]$Database = "postgres")
$out = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d $Database -v ON_ERROR_STOP=1 -tAc $Sql 2>&1
if ($LASTEXITCODE -ne 0) {
throw "psql_failed ($LASTEXITCODE): $Sql`n$out"
}
return (($out | Out-String).Trim())
}
$role = Invoke-NetxPsql -Sql "SELECT 1 FROM pg_roles WHERE rolname='netx'"
if ($role -eq "1") {
Invoke-NetxPsql -Sql "ALTER ROLE netx WITH LOGIN PASSWORD '$sqlPw'" | Out-Null
} else {
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
-c "ALTER ROLE netx WITH LOGIN PASSWORD '$sqlPw';"
Invoke-NetxPsql -Sql "CREATE ROLE netx LOGIN PASSWORD '$sqlPw'" | Out-Null
}
$db = & $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -tAc "SELECT 1 FROM pg_database WHERE datname='netx'"
if ($db -notmatch "1") {
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
-c "CREATE DATABASE netx OWNER netx;"
$db = Invoke-NetxPsql -Sql "SELECT 1 FROM pg_database WHERE datname='netx'"
if ($db -ne "1") {
Invoke-NetxPsql -Sql "CREATE DATABASE netx OWNER netx" | Out-Null
}
Invoke-NetxPsql -Sql "GRANT ALL PRIVILEGES ON DATABASE netx TO netx" | Out-Null
# Verify login as app role (catches auth/hba mismatches early).
$prev = $env:PGPASSWORD
$env:PGPASSWORD = $BundledPassword
try {
$ping = & $psql -h 127.0.0.1 -p $BundledPort -U netx -d netx -v ON_ERROR_STOP=1 -tAc "SELECT 1" 2>&1
if ($LASTEXITCODE -ne 0 -or (($ping | Out-String).Trim()) -ne "1") {
throw "netx_role_login_failed: $ping"
}
} finally {
$env:PGPASSWORD = $prev
}
& $psql -h 127.0.0.1 -p $BundledPort -U postgres -d postgres -v ON_ERROR_STOP=1 `
-c "GRANT ALL PRIVILEGES ON DATABASE netx TO netx;"
} finally {
Remove-Item Env:PGPASSWORD -ErrorAction SilentlyContinue
}