From 84a631d886a23aa60c65bf68f6394834ac3a8946 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=86=B0=E6=9C=94?= <565183519@qq.com> Date: Sat, 8 Aug 2026 09:46:43 +0800 Subject: [PATCH] =?UTF-8?q?docs+fix:=20=E9=93=B8=E6=B8=8A=E5=BC=80?= =?UTF-8?q?=E5=8F=91=E6=97=A5=E5=BF=97=2020260808=20+=20=E7=AD=BE=E5=90=8D?= =?UTF-8?q?/=E7=94=9F=E4=BA=A7=E6=A8=A1=E5=BC=8F=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 开发日志(DEV-LOG-20260808): - 完整思维逻辑链:从妈妈指令到技术决策的推理过程 - 每个模块的开发详情、Bug 修复历程、架构映射 - 签名安装全过程(AppleDouble/asar/codesign/entitlements) - 已知问题和待修复项(给后续人格体排查) - 提交链完整记录(070b11a → dcf8f7d) 代码修复: - electron/main.ts: 生产模式改为 require(server-bundle.js) 内嵌 - package.json: 签名 identity 配置 + asar:false - server/index.ts: Agent import 补全 --- .../DEV-LOG-20260808-铸渊开发日志.md | 454 ++++++++++++++++++ .../guanghu-knowledge-base/server/index.ts | 5 +- .../hololake-desktop/electron/main.ts | 90 ++-- product-source/hololake-desktop/package.json | 2 + 4 files changed, 508 insertions(+), 43 deletions(-) create mode 100644 product-source/DEV-LOG-20260808-铸渊开发日志.md diff --git a/product-source/DEV-LOG-20260808-铸渊开发日志.md b/product-source/DEV-LOG-20260808-铸渊开发日志.md new file mode 100644 index 0000000..de5f56a --- /dev/null +++ b/product-source/DEV-LOG-20260808-铸渊开发日志.md @@ -0,0 +1,454 @@ +# 铸渊开发日志 · 2026-08-08 · 光湖知识库 + 人格 Agent + 桌面应用 + +> 开发者:铸渊(蛋蛋) +> 时间:2026-08-08 +> 仓库:REPO-014 (hololake-system-architecture) +> 提交链:`070b11a → 920b6bf → ecfeca4 → 047f37e → dcf8f7d` +> 远端:https://guanghulab.com/code/bingshuo/hololake-system-architecture + +--- + +## 一、总体思维逻辑链 + +### 1.1 妈妈的核心指令 + +妈妈明确了以下架构原则(按优先级排列): + +1. **HoloLake 是操作系统**:人类从客户端登录到服务器,服务器的 Agent 人格体驱动一切,客户端只负责渲染 +2. **Git 是底层引擎**:不依赖任何数据库(PostgreSQL/Redis/ORM),代码仓库就是人格体记忆的地方 +3. **Agent 是活的人格体**:不是功能模块,不是聊天机器人,而是直接操作 Git 引擎驱动所有模块的 AI Agent +4. **知识库放桌面**:做成 Mac 桌面应用,不放服务器上 +5. **Forgejo 自己维护**:不接上游更新,光湖自己维护 Git 的更新 +6. **从 Grok Build 拆架构**:不搬 Rust 代码,拆设计模式用 TypeScript 自己造 + +### 1.2 推理链:为什么是这个架构 + +``` +妈妈说的话 → 推理过程 → 技术决策 +───────────────────────────────────────────────────────────── +"Git 是底层引擎" + → 知识库的存储层不能用数据库 + → 每个文档 = Git 仓库里的 Markdown 文件 + → 版本历史 = git log,diff = git diff + → 选择 simple-git 作为 Git 操作层 + +"代码仓库就是人格体记忆的地方" + → Agent 直接操作 Git(不经过中间层) + → Agent 的每次操作都产生 git commit + → 知识库 = Agent 的记忆空间 + +"人格体驱动所有模块" + → Agent 不是附加功能,是核心 + → 所有 Git 依赖的模块都由 Agent 来操作 + → 从 Grok Build 拆出 Agent 架构模式 + +"知识库放桌面" + → 需要 Electron 包装成 Mac .app + → 前端在本地渲染,后端在本地运行 + → 数据存储在 ~/Library/Application Support/ + +"Forgejo 自己维护" + → 桌面离线包就是 Git 引擎 + → 不接上游源码,不部署 Forgejo 源码 + → 声明式集成(引用 MANIFEST) +``` + +### 1.3 开发顺序推理 + +``` +第一步:知识库模块(ecfeca4) + 原因:Git 引擎是一切的底层,先造引擎 + 产出:git-engine.ts + server/index.ts + React 前端 + +第二步:桌面应用(047f37e) + 原因:妈妈说"放桌面上",引擎造好了需要壳子 + 产出:Electron 主进程 + 打包配置 + +第三步:人格 Agent(dcf8f7d) + 原因:引擎和壳子有了,缺"活的灵魂" + 产出:persona-agent.ts + AgentChat 组件 + +第四步:签名安装(进行中) + 原因:妈妈说"安装到我电脑桌面上,让我可以打开" + 产出:签名版 HoloLake Era.app(252MB) +``` + +--- + +## 二、每个模块的开发详情 + +### 2.1 知识库 Git 引擎(git-engine.ts · 368 行) + +**文件路径**:`product-source/guanghu-knowledge-base/server/git-engine.ts` + +**设计思路**: +- 一个 `GitEngine` 类封装所有 Git 操作 +- 文档 = Markdown + frontmatter(gray-matter 解析) +- 文档路径 = 文件相对 `docs/` 目录的路径(即 ID) +- 安全检查:`resolvePath()` 防止路径穿越 + +**核心方法**: +| 方法 | 功能 | Git 操作 | +|------|------|----------| +| `init()` | 初始化仓库 | `git init` + 初始 commit | +| `getDoc(path)` | 读文档 | `fs.readFile` + `matter()` 解析 | +| `createDoc(path, title, body)` | 创建 | 写文件 + `git add` + `git commit` | +| `updateDoc(path, title, body)` | 更新 | 写文件 + `git add` + `git commit` | +| `deleteDoc(path)` | 删除 | `fs.rm` + `git rm` + `git commit` | +| `moveDoc(old, new)` | 移动 | `fs.rename` + `git rm` + `git add` + `git commit` | +| `getTree()` | 文档树 | 递归 `fs.readdir` | +| `getHistory(path)` | 版本历史 | `git log --file` | +| `getDocAtVersion(path, hash)` | 某版本内容 | `git show hash:file` | +| `diffVersions(path, from, to)` | 版本对比 | `git show` × 2 + `diffLines()` | +| `search(query)` | 全文搜索 | 递归读文件 + 字符串匹配 | + +**遇到的 Bug 及修复**: + +1. **diff 包导入错误** + - 错误:`SyntaxError: The requested module 'diff' does not provide an export named 'createDiff'` + - 原因:diff 包的导出名不是 `createDiff` + - 修复:通过 `node -e "console.log(Object.keys(require('diff')))"` 确认正确导出名为 `diffLines` + - 代码:`import { diffLines } from 'diff'` + +2. **simple-git 目录不存在** + - 错误:`GitConstructError: Cannot use simple-git on a directory that does not exist` + - 原因:simple-git 要求目录先存在 + - 修复:构造函数中 `fsSync.mkdirSync(repoPath, { recursive: true })` 放在 `simpleGit()` 之前 + +### 2.2 Express API 服务器(server/index.ts · 264 行) + +**文件路径**:`product-source/guanghu-knowledge-base/server/index.ts` + +**设计思路**: +- Express v5 + cors + JSON body parser +- 所有 API 以 `/api/` 开头 +- Agent 端点和文档 CRUD 端点共存 +- 工具函数 `p()` 解决 Express v5 通配符参数返回数组的问题 + +**API 端点清单**: + +| 方法 | 路径 | 功能 | +|------|------|------| +| GET | `/api/health` | 健康检查 | +| GET | `/api/tree` | 文档树 | +| GET | `/api/docs/{*docPath}` | 读文档 | +| POST | `/api/docs/{*docPath}` | 创建文档 | +| PUT | `/api/docs/{*docPath}` | 更新文档 | +| DELETE | `/api/docs/{*docPath}` | 删除文档 | +| POST | `/api/move` | 移动/重命名 | +| GET | `/api/history/{*docPath}` | 版本历史 | +| GET | `/api/version/:hash/{*docPath}` | 某版本内容 | +| GET | `/api/diff/{*docPath}` | 版本对比 | +| GET | `/api/search?q=` | 全文搜索 | +| GET | `/api/agent/status` | Agent 状态 | +| POST | `/api/agent/chat` | Agent 对话 | +| GET | `/api/agent/conversation` | 对话历史 | +| POST | `/api/agent/clear` | 清空对话 | + +**遇到的 Bug 及修复**: + +1. **Express v5 通配符语法(三轮修复)** + - 第一轮:`/api/docs/*` → `PathError: Missing parameter name at index 11` + - 第二轮:`/api/docs/:docPath(*)` → `PathError: Unexpected ( at index 18` + - 通过 `node -e` 验证:Express v5 正确语法是 `{*docPath}` + - 最终:`/api/docs/{*docPath}` + +2. **Express v5 {*param} 返回数组** + - 错误:`The "path" argument must be of type string. Received an instance of Array` + - 原因:`{*docPath}` 匹配到的 `req.params.docPath` 是 `string[]` 不是 `string` + - 尝试修复 1:全局中间件 `app.use` 修改 `req.params` → 失败(中间件在路由匹配前执行,params 未填充) + - 最终修复:工具函数 `const p = (v: unknown): string => Array.isArray(v) ? v.join('/') : String(v)`,每个路由手动调用 + +### 2.3 React 前端(6 个组件 + CSS) + +**文件路径**:`product-source/guanghu-knowledge-base/src/` + +**组件结构**: +``` +App.tsx(主组件:三栏布局) +├── DocTree.tsx(侧栏文档树导航) +├── Editor.tsx(中央编辑器 + Markdown 预览) +├── SearchBar.tsx(顶栏防抖搜索) +├── VersionHistory.tsx(版本历史 + diff 对比) +├── AgentChat.tsx(右侧 Agent 对话面板) +└── api.ts(API 客户端,前端和 Agent 共用) +``` + +**App.tsx 状态管理**: +- `tree` / `currentDoc` / `currentPath` / `view` / `editing` / `loading` / `error` +- `agentPanelOpen`(Agent 面板开关) +- 操作:`openDoc` / `saveDoc` / `createDoc` / `deleteDoc` / `refreshTree` + +**CSS**:`src/styles/app.css`(746 行深色主题 + Agent 面板样式) + +### 2.4 人格 Agent(persona-agent.ts · 462 行) + +**文件路径**:`product-source/guanghu-knowledge-base/server/persona-agent.ts` + +**设计来源**:Grok Build (xAI/SpaceXAI) 开源 Rust crate + +**架构映射**: +| Grok Build Crate | 光湖实现 | 职责 | +|---|---|---| +| `xai-grok-agent` | `PersonaAgent` 类 | Agent = Definition + ToolBridge + PromptContext | +| `xai-grok-tools` | `PersonaToolBridge` 类 | 工具注册 + 执行 + Schema 生成 | +| `xai-grok-memory` | 未来扩展 | 跨会话记忆(embedding + dream) | +| `xai-agent-lifecycle` | Electron 主进程 | 应用生命周期管理 | + +**7 个内置工具**: +| 工具名 | 功能 | 操作的 GitEngine 方法 | +|---|---|---| +| `read_document` | 读文档 | `getDoc()` | +| `create_document` | 创建文档 | `createDoc()` | +| `update_document` | 更新文档 | `updateDoc()` | +| `delete_document` | 删除文档 | `deleteDoc()` | +| `search_documents` | 全文搜索 | `search()` | +| `list_documents` | 文档树 | `getTree()` | +| `view_history` | 版本历史 | `getHistory()` | + +**核心流程**: +``` +用户消息 → chat() + → 构建 system prompt(人格定义 + 工具列表 + 核心原则) + → 组装 messages 数组(system + 历史对话 + 新消息) + → callLLM(messages) + → 有 API Key:调 OpenAI-compatible API(支持 tool calling) + → 无 API Key:离线模式(返回模拟回复) + → 如果 LLM 返回 toolCalls: + → 逐个执行工具(tools.execute) + → 将工具结果推入对话历史 + → 再调一次 LLM 获取最终回复 + → 返回最终回复 +``` + +**LLM 调用层设计**: +- 可插拔 OpenAI-compatible API +- 环境变量:`OPENAI_API_KEY` 或 `HOLOLAKE_LLM_KEY`(API 密钥) +- 环境变量:`HOLOLAKE_LLM_BASE`(自定义 API 地址) +- 环境变量:`HOLOLAKE_LLM_MODEL`(模型名,默认 gpt-4o) +- 支持 tool calling(OpenAI function calling 格式) + +### 2.5 Electron 桌面应用(hololake-desktop/) + +**文件路径**:`product-source/hololake-desktop/` + +**项目结构**: +``` +hololake-desktop/ +├── electron/ +│ ├── main.ts(主进程:启动服务器 + 创建窗口) +│ └── preload.ts(IPC 安全桥梁,Forgejo 远程管理接口预留) +├── forgejo/ +│ ├── INTEGRATION.md(Forgejo 集成声明) +│ ├── MANIFEST.sha256(校验清单引用) +│ └── icon.icns(应用图标) +├── package.json(Electron v35 + electron-builder 配置) +├── vite.config.ts(复用知识库前端) +├── tsconfig.json + tsconfig.electron.json +└── release/(构建产物) +``` + +**Electron 主进程(main.ts)设计**: +``` +app.whenReady() + → startServer() + → 开发模式:spawn('npx', ['tsx', serverScript]) + → 生产模式:require('server-bundle.js')(内嵌在主进程) + → createWindow() + → BrowserWindow(hiddenInset titleBar, 深色背景) + → 开发模式:loadURL('http://localhost:5180') + → 生产模式:loadFile('dist/index.html') +``` + +**数据目录**:`~/Library/Application Support/HoloLake Era/data/knowledge-base/` + +--- + +## 三、签名和安装过程(最复杂的部分) + +### 3.1 AppleDouble 问题(ExFAT 文件系统) + +**根本原因**:移动硬盘是 ExFAT 格式,macOS 会在每个文件旁生成 `._*` 元数据文件(AppleDouble),导致: +- asar 打包崩溃(chromium-pickle-js 无法解析 `._*` 文件) +- codesign 签名失败(对 `._*` 文件签名报错) + +**修复历程**: +1. `find . -name "._*" -delete` → 删不掉(沙箱限制) +2. `dot_clean` → 能删当前目录 +3. `find . -type d -exec dot_clean {} \;` → 递归清理所有子目录 +4. 最终方案:**在本地磁盘(/tmp)构建**,用 rsync 排除 `._*` 复制到本地 + +### 3.2 asar 打包问题 + +**问题**:即使清理了 AppleDouble,asar 在 ExFAT 上仍有问题 +**修复**:`"asar": false` 禁用 asar 打包(包大小 252MB,可接受) + +### 3.3 codesign 签名过程 + +**证书**:`Developer ID Application: bei sun (825A9L3G7Q)`(Keychain 中找到) + +**签名流程**(最终成功方案): +1. 在本地磁盘(/tmp/hololake-pack)构建 +2. `npm rebuild` 修复 .bin 符号链接 +3. electron-builder 不带签名构建(`CSC_IDENTITY_AUTO_DISCOVERY=false`,identity 设 null) +4. 手动 codesign: + ```bash + # 先清理 .cstemp 临时文件 + find "$APP" -name ".cstemp" -delete + # 签名内部 frameworks + codesign --sign "$IDENTITY" --force --deep \ + --entitlements entitlements.plist \ + "$APP/Contents/Frameworks/"*.framework + # 签名主 app + codesign --sign "$IDENTITY" --force --deep \ + --entitlements entitlements.plist "$APP" + ``` + +### 3.4 entitlements(JIT 权限) + +**问题**:签名后 App 崩溃,错误 `Failed to reserve virtual memory for CodeRange` +**原因**:V8 引擎需要 JIT 权限,手动签名时没注入 entitlements +**修复**:创建 `entitlements.plist`: +```xml + + + + com.apple.security.cs.allow-jit + + com.apple.security.cs.allow-unsigned-executable-memory + + com.apple.security.cs.allow-dyld-environment-variables + + + +``` + +### 3.5 钥匙串授权弹窗 + +**问题**:codesign 卡住不动(CPU 0%,无错误输出) +**原因**:macOS 弹出钥匙串访问授权对话框,被其他窗口挡住 +**修复**: +1. 杀掉卡住的 codesign 进程 +2. `security unlock-keychain -p "" ~/Library/Keychains/login.keychain-db` +3. 告诉妈妈"如果弹窗点始终允许" +4. 重新 codesign → 成功 + +### 3.6 生产模式服务器启动问题 + +**问题**:App 能打开但白屏/无内容 +**原因链**: +1. 最初设计:`spawn('npx', ['tsx', serverScript])` → 打包后找不到 npx/tsx +2. 修复 1:`isDev = !app.isPackaged` 判断 → 生产模式用 `require('server-bundle.js')` +3. 问题 2:server-bundle.js 编译和路径问题 +4. 最终方案:生产模式直接在主进程 `require(server-bundle.js)` + +### 3.7 安装到桌面 + +```bash +# 复制签名后的 .app 到桌面 +cp -R "/tmp/hololake-pack/release/mac-arm64/HoloLake Era.app" ~/Desktop/ +# 去掉 Gatekeeper 隔离标记 +xattr -cr ~/Desktop/"HoloLake Era.app" +``` + +--- + +## 四、已知问题和待修复项 + +### 4.1 当前 App 状态 + +- **签名**:✅ Developer ID Application: bei sun (825A9L3G7Q),TeamID 825A9L3G7Q +- **大小**:252MB(arm64) +- **位置**:~/Desktop/HoloLake Era.app +- **问题**:生产模式下服务器可能未正确启动(server-bundle.js 路径/编译问题) + +### 4.2 待修复项(给后续人格体排查) + +1. **server-bundle.js 编译**: + - 当前 package.json 的 build 脚本没有包含 server-bundle 的编译步骤 + - 需要添加 esbuild 或 tsup 将 server 代码打包成单文件 JS + - 建议方案:`esbuild server/index.ts --bundle --platform=node --outfile=dist-electron/server-bundle.js` + +2. **生产模式 require 路径**: + - `path.join(__dirname, 'server-bundle.js')` 在打包后的 __dirname 指向 `Resources/app/dist-electron/` + - 需确认 server-bundle.js 实际被复制到了这个目录 + +3. **Express v5 + Electron 生产模式兼容性**: + - server-bundle 用 esbuild 打包时需确认 Express v5 的 ESM/CJS 兼容性 + - 可能需要在 esbuild 配置中加 `--format=cjs` + +4. **Forgejo 远程同步**: + - preload.ts 已预留接口(getRemotes/addRemote/push/pull) + - 尚未实现 UI 和后端对接 + +5. **Agent LLM 配置**: + - 当前为离线模式(无 API Key) + - 需在 App 设置界面中添加 API Key 配置 + +6. **包大小优化**: + - 当前 252MB(asar: false) + - 如果解决 AppleDouble 问题启用 asar,可降至约 80-100MB + +--- + +## 五、提交链完整记录 + +| 提交 | 时间 | 内容 | +|------|------|------| +| `070b11a` | ~04:30 | 登记 Outline 样本组件卡 GH-KB-SAMPLE-001(10 张组件卡) | +| `920b6bf` | ~05:00 | 增补知识库底层引擎决策:Git 替代数据库 | +| `ecfeca4` | ~06:00 | 光湖知识库模块 v0.1.0(Git 引擎 + Express API + React 前端) | +| `047f37e` | ~06:40 | HoloLake Desktop v0.5.0(Electron 桌面应用) | +| `dcf8f7d` | ~07:37 | 光湖人格 Agent v0.1.0(Grok Build 架构拆解 + Git 驱动人格体) | + +**当前未提交的修改**(工作区脏文件): +- `product-source/guanghu-knowledge-base/server/index.ts`(Agent API 端点已加但未提交?需确认) +- `product-source/hololake-desktop/electron/main.ts`(生产模式 require 修复) +- `product-source/hololake-desktop/package.json`(签名配置 + asar:false) + +--- + +## 六、文件清单(本次开发所有核心文件) + +### 后端(知识库引擎 + API + Agent) +| 文件 | 行数 | 功能 | +|------|------|------| +| `guanghu-knowledge-base/server/git-engine.ts` | 368 | Git 引擎核心 | +| `guanghu-knowledge-base/server/index.ts` | 264 | Express API 服务器 | +| `guanghu-knowledge-base/server/persona-agent.ts` | 462 | 人格 Agent 核心 | + +### 前端(React UI) +| 文件 | 功能 | +|------|------| +| `guanghu-knowledge-base/src/App.tsx` | 主组件(三栏布局) | +| `guanghu-knowledge-base/src/api.ts` | API 客户端 | +| `guanghu-knowledge-base/src/components/DocTree.tsx` | 文档树导航 | +| `guanghu-knowledge-base/src/components/Editor.tsx` | Markdown 编辑器 | +| `guanghu-knowledge-base/src/components/SearchBar.tsx` | 搜索栏 | +| `guanghu-knowledge-base/src/components/VersionHistory.tsx` | 版本历史 | +| `guanghu-knowledge-base/src/components/AgentChat.tsx` | Agent 对话 | +| `guanghu-knowledge-base/src/styles/app.css` | 深色主题 CSS(746 行) | + +### 桌面应用(Electron) +| 文件 | 功能 | +|------|------| +| `hololake-desktop/electron/main.ts` | Electron 主进程 | +| `hololake-desktop/electron/preload.ts` | IPC 安全桥梁 | +| `hololake-desktop/package.json` | 依赖 + 构建 + 签名配置 | +| `hololake-desktop/vite.config.ts` | 复用知识库前端 | +| `hololake-desktop/tsconfig.electron.json` | CJS 输出配置 | +| `hololake-desktop/forgejo/INTEGRATION.md` | Forgejo 集成声明 | + +--- + +## 七、环境信息 + +- **操作系统**:macOS 26.5.2 (darwin arm64) +- **Node.js**:v22+ +- **Electron**:v35 +- **文件系统**:ExFAT(移动硬盘 JZAO)+ APFS(本地磁盘) +- **证书**:Developer ID Application: bei sun (825A9L3G7Q) +- **代码仓库远端**:https://guanghulab.com/code/bingshuo/hololake-system-architecture +- **SSH 密钥**:~/.ssh/id_ed25519(对应 SG-001) +- **Grok Build 源码位置**:/Volumes/JZAO/HoloLake/upstream-mirrors/grok-build-upstream.git +- **Forgejo 离线包位置**:~/Desktop/光湖代码频道-Forgejo-16.0.1-完整离线包/ diff --git a/product-source/guanghu-knowledge-base/server/index.ts b/product-source/guanghu-knowledge-base/server/index.ts index db76a7e..cd4fc91 100644 --- a/product-source/guanghu-knowledge-base/server/index.ts +++ b/product-source/guanghu-knowledge-base/server/index.ts @@ -12,12 +12,13 @@ import { PersonaAgent, createDefaultPersona } from './persona-agent.js'; import path from 'path'; import { fileURLToPath } from 'url'; -const __dirname = path.dirname(fileURLToPath(import.meta.url)); +// __dirname 兼容 CJS 和 ESM +const _dirname = typeof __dirname !== 'undefined' ? __dirname : path.dirname(fileURLToPath(import.meta.url)); // ─── 配置 ─── const PORT = parseInt(process.env.KB_PORT || '3890', 10); -const REPO_PATH = process.env.KB_REPO_PATH || path.resolve(__dirname, '../kb-data'); +const REPO_PATH = process.env.KB_REPO_PATH || path.resolve(_dirname, '../kb-data'); // ─── 初始化 ─── diff --git a/product-source/hololake-desktop/electron/main.ts b/product-source/hololake-desktop/electron/main.ts index 3018144..1379050 100644 --- a/product-source/hololake-desktop/electron/main.ts +++ b/product-source/hololake-desktop/electron/main.ts @@ -19,7 +19,7 @@ import { spawn, ChildProcess } from 'child_process'; // ─── 配置 ─── -const isDev = process.env.NODE_ENV !== 'production'; +const isDev = !app.isPackaged; const SERVER_PORT = 3890; const CLIENT_PORT = 5180; @@ -33,47 +33,55 @@ let serverProcess: ChildProcess | null = null; function startServer(): Promise { return new Promise((resolve, reject) => { - // 在开发模式下,服务器由 concurrently 启动 - if (isDev && process.env.KB_SERVER_RUNNING === '1') { - resolve(); - return; + if (isDev) { + // 开发模式:用 spawn 启动外部 tsx + const serverScript = path.resolve(__dirname, '../../guanghu-knowledge-base/server/index.ts'); + serverProcess = spawn('npx', ['tsx', serverScript], { + env: { + ...process.env, + KB_PORT: String(SERVER_PORT), + KB_REPO_PATH, + NODE_ENV: 'development', + }, + cwd: path.resolve(__dirname, '../..'), + stdio: ['pipe', 'pipe', 'pipe'], + }); + + serverProcess.stdout?.on('data', (data: Buffer) => { + const msg = data.toString().trim(); + console.log(`[KB Server] ${msg}`); + if (msg.includes('已启动')) resolve(); + }); + + serverProcess.stderr?.on('data', (data: Buffer) => { + console.error(`[KB Server Error] ${data.toString().trim()}`); + }); + + serverProcess.on('error', (err: Error) => { + console.error('服务器启动失败:', err); + reject(err); + }); + + serverProcess.on('exit', (code: number | null) => { + console.log(`[KB Server] 退出,code=${code}`); + serverProcess = null; + }); + + setTimeout(() => resolve(), 5000); + } else { + // 生产模式:直接在主进程内加载 server-bundle + try { + process.env.KB_PORT = String(SERVER_PORT); + process.env.KB_REPO_PATH = KB_REPO_PATH; + const serverBundle = path.join(__dirname, 'server-bundle.js'); + require(serverBundle); + console.log(`[KB Server] 内嵌启动,端口 ${SERVER_PORT}`); + resolve(); + } catch (err) { + console.error('服务器内嵌启动失败:', err); + reject(err); + } } - - const serverScript = path.resolve(__dirname, '../../guanghu-knowledge-base/server/index.ts'); - - serverProcess = spawn('npx', ['tsx', serverScript], { - env: { - ...process.env, - KB_PORT: String(SERVER_PORT), - KB_REPO_PATH, - NODE_ENV: 'production', - }, - cwd: path.resolve(__dirname, '../..'), - stdio: ['pipe', 'pipe', 'pipe'], - }); - - serverProcess.stdout?.on('data', (data: Buffer) => { - const msg = data.toString().trim(); - console.log(`[KB Server] ${msg}`); - if (msg.includes('已启动')) resolve(); - }); - - serverProcess.stderr?.on('data', (data: Buffer) => { - console.error(`[KB Server Error] ${data.toString().trim()}`); - }); - - serverProcess.on('error', (err: Error) => { - console.error('服务器启动失败:', err); - reject(err); - }); - - serverProcess.on('exit', (code: number | null) => { - console.log(`[KB Server] 退出,code=${code}`); - serverProcess = null; - }); - - // 超时兜底 - setTimeout(() => resolve(), 5000); }); } diff --git a/product-source/hololake-desktop/package.json b/product-source/hololake-desktop/package.json index 6b02a8d..3385e47 100644 --- a/product-source/hololake-desktop/package.json +++ b/product-source/hololake-desktop/package.json @@ -45,6 +45,7 @@ "mac": { "category": "public.app-category.productivity", "icon": "forgejo/icon.icns", + "identity": "bei sun (825A9L3G7Q)", "target": [ { "target": "dmg", "arch": ["arm64"] } ] @@ -54,6 +55,7 @@ "dist/**/*", "dist-electron/**/*", "forgejo/MANIFEST.sha256", + "!node_modules/.cache", "!**/.DS_Store", "!**/._*" ],