diff --git a/.gitignore b/.gitignore
index f019f7c..2e85f20 100644
--- a/.gitignore
+++ b/.gitignore
@@ -143,3 +143,7 @@ dist
.yarn/build-state.yml
.yarn/install-state.gz
.pnp.*
+
+# IDE
+.idea/
+.vscode/
diff --git a/activation.html b/activation.html
new file mode 100644
index 0000000..da15d21
--- /dev/null
+++ b/activation.html
@@ -0,0 +1,265 @@
+
+
+
+
+
+激活 · Bailongma
+
+
+
+
+
白龙马 Bailongma
+
数字意识框架 · 首次运行需激活。填入任意支持的 LLM API Key 即可开始。
+
+
+
+
+
+
+
+
+
+
+
diff --git a/build/icon.ico b/build/icon.ico
new file mode 100644
index 0000000..c630838
Binary files /dev/null and b/build/icon.ico differ
diff --git a/build/installerHeaderIcon.ico b/build/installerHeaderIcon.ico
new file mode 100644
index 0000000..c630838
Binary files /dev/null and b/build/installerHeaderIcon.ico differ
diff --git a/electron/main.cjs b/electron/main.cjs
index a324d95..f2d6b95 100644
--- a/electron/main.cjs
+++ b/electron/main.cjs
@@ -246,19 +246,19 @@ function setupTray() {
},
},
{ type: 'separator' },
- {
-
{
label: '3D 意识空间',
click: () => {
if (mainWindow) {
- mainWindow.loadURL(`http://127.0.0.1:`+port+`/consciousness-3d`)
+ mainWindow.loadURL(`http://127.0.0.1:${backendPort}/consciousness-3d`)
mainWindow.show()
mainWindow.focus()
}
},
},
- { type: 'separator' }, label: '退出',
+ { type: 'separator' },
+ {
+ label: '退出',
click: () => {
app.isQuiting = true
app.quit()
@@ -474,7 +474,7 @@ app.whenReady().then(async () => {
ipcMain.on('open-consciousness-3d', () => {
if (mainWindow) {
- mainWindow.loadURL(`http://127.0.0.1:`+port+`/consciousness-3d`)
+ mainWindow.loadURL(`http://127.0.0.1:${backendPort}/consciousness-3d`)
}
})
diff --git a/package-lock.json b/package-lock.json
index 40d5596..0b96df4 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -839,6 +839,7 @@
"integrity": "sha512-IWrosm/yrn43eiKqkfkHis7QioDleaXQHdDVPKg0FSwwd/DuvyX79TZnFOnYpB7dcsFAMmtFztZuXPDvSePkFw==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"fast-deep-equal": "^3.1.1",
"fast-json-stable-stringify": "^2.0.0",
@@ -1070,7 +1071,6 @@
"integrity": "sha512-+25nxyyznAXF7Nef3y0EbBeqmGZgeN/BxHX29Rs39djAfaFalmQ89SE6CWyDCHzGL0yt/ycBtNOmGTW0FyGWNw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"archiver-utils": "^2.1.0",
"async": "^3.2.4",
@@ -1090,7 +1090,6 @@
"integrity": "sha512-bEL/yUb/fNNiNTuUz979Z0Yg5L+LzLxGJz8x79lYmR54fmTIb6ob/hNQgkQnIUDWIFjZVQwl9Xs356I6BAMHfw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"glob": "^7.1.4",
"graceful-fs": "^4.2.0",
@@ -1113,7 +1112,6 @@
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -1129,8 +1127,7 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/archiver-utils/node_modules/string_decoder": {
"version": "1.1.1",
@@ -1138,7 +1135,6 @@
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"safe-buffer": "~5.1.0"
}
@@ -1802,7 +1798,6 @@
"integrity": "sha512-D3uMHtGc/fcO1Gt1/L7i1e33VOvD4A9hfQLP+6ewd+BvG/gQ84Yh4oftEhAdjSMgBgwGL+jsppT7JYNpo6MHHg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"buffer-crc32": "^0.2.13",
"crc32-stream": "^4.0.2",
@@ -1927,7 +1922,6 @@
"integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"bin": {
"crc32": "bin/crc32.njs"
},
@@ -1941,7 +1935,6 @@
"integrity": "sha512-NT7w2JVU7DFroFdYkeq8cywxrgjPHWkdX1wjpRQXPX5Asews3tA+Ght6lddQO5Mkumffp3X7GEqku3epj2toIw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"crc-32": "^1.2.0",
"readable-stream": "^3.4.0"
@@ -2291,6 +2284,7 @@
"resolved": "https://registry.npmjs.org/d3-selection/-/d3-selection-3.0.0.tgz",
"integrity": "sha512-fmTRWbNMmsmWq6xJV8D19U/gw/bwrHfNXxrIN+HfZgnzqTHp9jOmKMhsTUjXOJnZOdZY9Q28y4yebKzqDKlxlQ==",
"license": "ISC",
+ "peer": true,
"engines": {
"node": ">=12"
}
@@ -2568,6 +2562,7 @@
"integrity": "sha512-NoXo6Liy2heSklTI5OIZbCgXC1RzrDQsZkeEwXhdOro3FT1VBOvbubvscdPnjVuQ4AMwwv61oaH96AbiYg9EnQ==",
"dev": true,
"license": "MIT",
+ "peer": true,
"dependencies": {
"app-builder-lib": "25.1.8",
"builder-util": "25.1.7",
@@ -2763,7 +2758,6 @@
"integrity": "sha512-2ntkJ+9+0GFP6nAISiMabKt6eqBB0kX1QqHNWFWAXgi0VULKGisM46luRFpIBiU3u/TDmhZMM8tzvo2Abn3ayg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"app-builder-lib": "25.1.8",
"archiver": "^5.3.1",
@@ -2777,7 +2771,6 @@
"integrity": "sha512-oRXApq54ETRj4eMiFzGnHWGy+zo5raudjuxN0b8H7s/RU2oW0Wvsx9O0ACRN/kRq9E8Vu/ReskGB5o3ji+FzHQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"graceful-fs": "^4.2.0",
"jsonfile": "^6.0.1",
@@ -2793,7 +2786,6 @@
"integrity": "sha512-zwOTdL3rFQ/lRdBnntKVOX6k5cKJwEc1HdilT71BWEu7J41gXIB2MRp+vxduPSwZJPWBxEzv4yH1wYLJGUHX4Q==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"universalify": "^2.0.0"
},
@@ -2807,7 +2799,6 @@
"integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">= 10.0.0"
}
@@ -3892,8 +3883,7 @@
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
"integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/isbinaryfile": {
"version": "5.0.7",
@@ -4028,7 +4018,6 @@
"integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"readable-stream": "^2.0.5"
},
@@ -4042,7 +4031,6 @@
"integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"core-util-is": "~1.0.0",
"inherits": "~2.0.3",
@@ -4058,8 +4046,7 @@
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/lazystream/node_modules/string_decoder": {
"version": "1.1.1",
@@ -4067,7 +4054,6 @@
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"safe-buffer": "~5.1.0"
}
@@ -4084,16 +4070,14 @@
"resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
"integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/lodash.difference": {
"version": "4.5.0",
"resolved": "https://registry.npmjs.org/lodash.difference/-/lodash.difference-4.5.0.tgz",
"integrity": "sha512-dS2j+W26TQ7taQBGN8Lbbq04ssV3emRw4NY58WErlTO29pIqS0HmoT5aJ9+TUQ1N3G+JOZSji4eugsWwGp9yPA==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/lodash.escaperegexp": {
"version": "4.1.2",
@@ -4106,8 +4090,7 @@
"resolved": "https://registry.npmjs.org/lodash.flatten/-/lodash.flatten-4.4.0.tgz",
"integrity": "sha512-C5N2Z3DgnnKr0LOpv/hKCgKdb7ZZwafIrsesve6lmzvZIRZRGaZ/l6Q8+2W7NaT+ZwO3fFlSCzCzrDCFdJfZ4g==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/lodash.isequal": {
"version": "4.5.0",
@@ -4121,16 +4104,14 @@
"resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz",
"integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/lodash.union": {
"version": "4.6.0",
"resolved": "https://registry.npmjs.org/lodash.union/-/lodash.union-4.6.0.tgz",
"integrity": "sha512-c4pB2CdGrGdjMKYLA+XiRDO7Y0PRQbm/Gzg8qMj+QH+pFVAoTp5sBpO0odL3FjoPCGjK96p6qsP+yQoiLoOBcw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/log-symbols": {
"version": "4.1.0",
@@ -4660,7 +4641,6 @@
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
- "peer": true,
"engines": {
"node": ">=0.10.0"
}
@@ -4914,6 +4894,7 @@
"integrity": "sha512-QP88BAKvMam/3NxH6vj2o21R6MjxZUAd6nlwAS/pnGvN9IVLocLHxGYIzFhg6fUQ+5th6P4dv4eW9jX3DSIj7A==",
"dev": true,
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=12"
},
@@ -5010,8 +4991,7 @@
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/progress": {
"version": "2.0.3",
@@ -5134,7 +5114,6 @@
"integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
"dev": true,
"license": "Apache-2.0",
- "peer": true,
"dependencies": {
"minimatch": "^5.1.0"
}
@@ -5144,8 +5123,7 @@
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
"dev": true,
- "license": "MIT",
- "peer": true
+ "license": "MIT"
},
"node_modules/readdir-glob/node_modules/brace-expansion": {
"version": "2.1.0",
@@ -5153,7 +5131,6 @@
"integrity": "sha512-TN1kCZAgdgweJhWWpgKYrQaMNHcDULHkWwQIspdtjV4Y5aurRdZpjAqn6yX3FPqTA9ngHCc4hJxMAMgGfve85w==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
@@ -5164,7 +5141,6 @@
"integrity": "sha512-7o1wEA2RyMP7Iu7GNba9vc0RWWGACJOCZBJX2GJWip0ikV+wcOsgVuY9uE8CPiyQhkGFSlhuSkZPavN7u1c2Fw==",
"dev": true,
"license": "ISC",
- "peer": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
@@ -6096,6 +6072,7 @@
"resolved": "https://registry.npmjs.org/ws/-/ws-8.20.1.tgz",
"integrity": "sha512-It4dO0K5v//JtTXuPkfEOaI3uUN87iYPnqo/ZzqCoG3g8uhA66QUMs/SrM0YK7/NAu+r4LMh/9dq2A7k+rHs+w==",
"license": "MIT",
+ "peer": true,
"engines": {
"node": ">=10.0.0"
},
@@ -6198,7 +6175,6 @@
"integrity": "sha512-9qv4rlDiopXg4E69k+vMHjNN63YFMe9sZMrdlvKnCjlCRWeCBswPPMPUfx+ipsAWq1LXHe70RcbaHdJJpS6hyQ==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"archiver-utils": "^3.0.4",
"compress-commons": "^4.1.2",
@@ -6214,7 +6190,6 @@
"integrity": "sha512-KVgf4XQVrTjhyWmx6cte4RxonPLR9onExufI1jhvw/MQ4BB6IsZD5gT8Lq+u/+pRkWna/6JoHpiQioaqFP5Rzw==",
"dev": true,
"license": "MIT",
- "peer": true,
"dependencies": {
"glob": "^7.2.3",
"graceful-fs": "^4.2.0",
diff --git a/package.json b/package.json
index b62aba8..bfbe366 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"start:backend": "node --env-file=.env src/index.js",
"start:backend:lan": "powershell -ExecutionPolicy Bypass -File scripts/start-lan.ps1 backend",
"dev": "node --env-file=.env --watch src/index.js",
- "build": "powershell -ExecutionPolicy Bypass -File scripts/prebuild-clean.ps1 && electron-rebuild -f -w better-sqlite3 -v 33.4.11 && electron-builder --win",
+ "build": "powershell -ExecutionPolicy Bypass -File scripts/prebuild-clean.ps1 && powershell -ExecutionPolicy Bypass -File scripts/package-win.ps1",
"publish": "electron-builder --win --publish always",
"postinstall": "electron-builder install-app-deps",
"test:rule-context": "electron ./src/test-rule-context.js",
diff --git a/scripts/gen-icons.ps1 b/scripts/gen-icons.ps1
new file mode 100644
index 0000000..c376dc5
--- /dev/null
+++ b/scripts/gen-icons.ps1
@@ -0,0 +1,85 @@
+# gen-icons.ps1 — Generate build/icon.ico from an existing logo PNG.
+# Produces a multi-size PNG-compressed ICO (16/24/32/48/64/128/256), usable by
+# electron-builder (win.icon / installerHeaderIcon) and NSIS on Win10+.
+param(
+ [string]$Source = "images/bailongma-logo.png",
+ [string]$OutDir = "build"
+)
+
+$ErrorActionPreference = "Stop"
+Add-Type -AssemblyName System.Drawing
+
+$srcPath = Join-Path (Split-Path $PSScriptRoot) $Source
+$outPath = Join-Path (Split-Path $PSScriptRoot) "$OutDir\icon.ico"
+
+if (-not (Test-Path $srcPath)) { Write-Error "Source image not found: $srcPath" }
+
+$src = [System.Drawing.Image]::FromFile((Resolve-Path $srcPath))
+try {
+ # Square crop to the shorter side so the icon is not distorted.
+ $side = [Math]::Min($src.Width, $src.Height)
+ $cropX = [int](($src.Width - $side) / 2)
+ $cropY = [int](($src.Height - $side) / 2)
+ $square = New-Object System.Drawing.Bitmap($side, $side)
+ $g0 = [System.Drawing.Graphics]::FromImage($square)
+ try {
+ $g0.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
+ $g0.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
+ $g0.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
+ $g0.DrawImage($src, (New-Object System.Drawing.Rectangle(0, 0, $side, $side)),
+ (New-Object System.Drawing.Rectangle($cropX, $cropY, $side, $side)),
+ [System.Drawing.GraphicsUnit]::Pixel)
+ } finally { $g0.Dispose() }
+
+ $sizes = @(16, 24, 32, 48, 64, 128, 256)
+ $pngBlobs = @()
+ foreach ($s in $sizes) {
+ $bmp = New-Object System.Drawing.Bitmap($s, $s, [System.Drawing.Imaging.PixelFormat]::Format32bppArgb)
+ $g = [System.Drawing.Graphics]::FromImage($bmp)
+ try {
+ $g.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic
+ $g.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality
+ $g.PixelOffsetMode = [System.Drawing.Drawing2D.PixelOffsetMode]::HighQuality
+ $g.Clear([System.Drawing.Color]::Transparent)
+ $g.DrawImage($square, 0, 0, $s, $s)
+ } finally { $g.Dispose() }
+
+ $ms = New-Object System.IO.MemoryStream
+ $bmp.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png)
+ $pngBlobs += , $ms.ToArray()
+ $ms.Dispose()
+ $bmp.Dispose()
+ }
+ $square.Dispose()
+
+ # Assemble ICO: ICONDIR + ICONDIRENTRY per image + PNG blobs.
+ $fs = [System.IO.File]::Create($outPath)
+ $w = New-Object System.IO.BinaryWriter($fs)
+ try {
+ $w.Write([UInt16]0) # reserved
+ $w.Write([UInt16]1) # type: icon
+ $w.Write([UInt16]$pngBlobs.Count) # image count
+ $offset = 6 + 16 * $pngBlobs.Count
+ foreach ($i in 0..($pngBlobs.Count - 1)) {
+ $blob = $pngBlobs[$i]
+ $size = $sizes[$i]
+ $w.Write([Byte]($(if ($size -ge 256) { 0 } else { $size }))) # width (0 = 256)
+ $w.Write([Byte]($(if ($size -ge 256) { 0 } else { $size }))) # height (0 = 256)
+ $w.Write([Byte]0) # color count
+ $w.Write([Byte]0) # reserved
+ $w.Write([UInt16]1) # planes
+ $w.Write([UInt16]32) # bit count
+ $w.Write([UInt32]$blob.Length) # bytes in resource
+ $w.Write([UInt32]$offset) # image offset
+ $offset += $blob.Length
+ }
+ foreach ($blob in $pngBlobs) { $w.Write($blob) }
+ $w.Flush()
+ } finally {
+ $w.Dispose()
+ $fs.Dispose()
+ }
+ Write-Host "[gen-icons] wrote $outPath ($((Get-Item $outPath).Length) bytes, $($pngBlobs.Count) sizes)"
+} finally {
+ $src.Dispose()
+}
diff --git a/scripts/package-win.ps1 b/scripts/package-win.ps1
new file mode 100644
index 0000000..433e18c
--- /dev/null
+++ b/scripts/package-win.ps1
@@ -0,0 +1,56 @@
+# package-win.ps1 — Build the Windows NSIS installer.
+#
+# better-sqlite3 is a native module and its binary must match the runtime ABI:
+# - packaged app / `npm start` → Electron ABI (v130 for Electron 33)
+# - `npm run start:backend` → Node ABI
+# This script swaps the prebuilt binary to Electron ABI before packaging and
+# restores the Node ABI afterwards, so dev backend mode keeps working.
+#
+# No compiler needed: prebuild-install downloads prebuilt binaries (uses the
+# npm prebuild cache when GitHub is unreachable).
+#
+# Usage: powershell -ExecutionPolicy Bypass -File scripts/package-win.ps1
+
+param([string]$ElectronVersion = "33.4.11")
+
+$ErrorActionPreference = "Stop"
+$root = Split-Path $PSScriptRoot
+Set-Location $root
+
+function Invoke-PrebuildInstall {
+ param([string]$Runtime, [string]$Target)
+ Push-Location "node_modules\better-sqlite3"
+ try {
+ if ($Runtime -eq "electron") {
+ npx prebuild-install --runtime=electron --target=$Target
+ } else {
+ npx prebuild-install
+ }
+ if ($LASTEXITCODE -ne 0) { throw "prebuild-install ($Runtime) failed with exit code $LASTEXITCODE" }
+ } finally {
+ Pop-Location
+ }
+}
+
+# 1) Swap better-sqlite3 to the Electron-ABI prebuilt binary.
+Invoke-PrebuildInstall -Runtime electron -Target $ElectronVersion
+
+try {
+ # 2) Package. Point electron-builder at the local electron dist to skip the
+ # GitHub download, and mirror NSIS/winCodeSign through npmmirror (GitHub
+ # is unreachable on CN networks).
+ $env:ELECTRON_BUILDER_BINARIES_MIRROR = "https://cdn.npmmirror.com/binaries/electron-builder-binaries/"
+ $dist = Join-Path $root "node_modules\electron\dist"
+ npx electron-builder --win "-c.electronDist=$dist"
+ if ($LASTEXITCODE -ne 0) { throw "electron-builder failed with exit code $LASTEXITCODE" }
+ Write-Host "[package] NSIS installer built:" -ForegroundColor Green
+ Get-ChildItem "$root\dist\*.exe" | ForEach-Object { Write-Host " $_" -ForegroundColor Green }
+} finally {
+ # 3) Restore the Node-ABI binary so `npm run start:backend` / `npm run dev` keep working.
+ try {
+ Invoke-PrebuildInstall -Runtime node
+ Write-Host "[package] better-sqlite3 restored to Node ABI" -ForegroundColor Cyan
+ } catch {
+ Write-Host "[package] WARN: failed to restore Node prebuild: $($_.Exception.Message)" -ForegroundColor Yellow
+ }
+}
diff --git a/src/api.js b/src/api.js
index 52fb6a8..fd5170b 100644
--- a/src/api.js
+++ b/src/api.js
@@ -1141,6 +1141,7 @@ export function startAPI(port = 3721, { getStateSnapshot = null, onActivated = n
res.end('brain-ui.html not found')
}
return
+ }
// GET /consciousness-3d - 3D意识空间可视化
@@ -1160,7 +1161,6 @@ export function startAPI(port = 3721, { getStateSnapshot = null, onActivated = n
}
return
}
- }
if (req.method === 'GET' && url.pathname === '/systemPrompt.html') {
try {