@bolloon/bolloon-agent 0.2.9 → 0.2.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (268) hide show
  1. package/README.md +467 -467
  2. package/bin/bolloon-cli.cjs +183 -183
  3. package/bin/bolloon.cjs +0 -0
  4. package/bin/bolloon.js +157 -0
  5. package/dist/agents/agent-manifest-protocol.js +0 -52
  6. package/dist/agents/constraint-layer.js +19 -19
  7. package/dist/agents/pi-sdk.js +287 -1213
  8. package/dist/agents/shell-guard.js +2 -2
  9. package/dist/agents/workflow-pivot-loop.js +2 -81
  10. package/dist/bollharness/src/scripts/deploy-guard.js +8 -8
  11. package/dist/bollharness-integration/context-router-judgment.js +4 -4
  12. package/dist/bollharness-integration/context-router.js +292 -292
  13. package/dist/bollharness-integration/gate-state-machine.js +13 -26
  14. package/dist/bollharness-integration/integration.js +0 -71
  15. package/dist/bollharness-integration/llm-judgment-engine.js +134 -134
  16. package/dist/bollharness-integration/skill-adapter.js +127 -52
  17. package/dist/bootstrap/context-collector.js +3 -6
  18. package/dist/bootstrap/lifecycle-hooks.js +1 -15
  19. package/dist/cli-entry.js +35 -39
  20. package/dist/constraint-runtime/src/_archive_helper.js +9 -0
  21. package/dist/constraint-runtime/src/agent/coordinator.js +48 -0
  22. package/dist/constraint-runtime/src/agent/index.js +1 -0
  23. package/dist/constraint-runtime/src/assistant/index.js +12 -0
  24. package/dist/constraint-runtime/src/bootstrap/index.js +12 -0
  25. package/dist/constraint-runtime/src/bootstrap_graph.js +13 -0
  26. package/dist/constraint-runtime/src/bridge/index.js +12 -0
  27. package/dist/constraint-runtime/src/buddy/index.js +12 -0
  28. package/dist/constraint-runtime/src/cli/index.js +12 -0
  29. package/dist/constraint-runtime/src/command_graph.js +10 -0
  30. package/dist/constraint-runtime/src/commands.js +60 -0
  31. package/dist/constraint-runtime/src/components/index.js +12 -0
  32. package/dist/constraint-runtime/src/constants/index.js +12 -0
  33. package/dist/constraint-runtime/src/constraint/budget.js +22 -0
  34. package/dist/constraint-runtime/src/constraint/index.js +2 -0
  35. package/dist/constraint-runtime/src/constraint/permission.js +20 -0
  36. package/dist/constraint-runtime/src/context.js +30 -0
  37. package/dist/constraint-runtime/src/coordinator/index.js +12 -0
  38. package/dist/constraint-runtime/src/cost_hook.js +4 -0
  39. package/dist/constraint-runtime/src/cost_tracker.js +8 -0
  40. package/dist/constraint-runtime/src/deferred_init.js +10 -0
  41. package/dist/constraint-runtime/src/direct_modes.js +6 -0
  42. package/dist/constraint-runtime/src/dynamic-tool-loader.js +85 -0
  43. package/dist/constraint-runtime/src/entrypoints/index.js +12 -0
  44. package/dist/constraint-runtime/src/execution_registry.js +44 -0
  45. package/dist/constraint-runtime/src/history.js +9 -0
  46. package/dist/constraint-runtime/src/hooks/index.js +12 -0
  47. package/dist/constraint-runtime/src/index.js +26 -0
  48. package/dist/constraint-runtime/src/ink.js +4 -0
  49. package/dist/constraint-runtime/src/keybindings/index.js +12 -0
  50. package/dist/constraint-runtime/src/memdir/index.js +12 -0
  51. package/dist/constraint-runtime/src/migrations/index.js +12 -0
  52. package/dist/constraint-runtime/src/models.js +1 -0
  53. package/dist/constraint-runtime/src/moreright/index.js +12 -0
  54. package/dist/constraint-runtime/src/native_ts/index.js +12 -0
  55. package/dist/constraint-runtime/src/output_styles/index.js +12 -0
  56. package/dist/constraint-runtime/src/parity_audit.js +12 -0
  57. package/dist/constraint-runtime/src/plugins/index.js +12 -0
  58. package/dist/constraint-runtime/src/port_manifest.js +11 -0
  59. package/dist/constraint-runtime/src/prefetch.js +9 -0
  60. package/dist/constraint-runtime/src/query.js +1 -0
  61. package/dist/constraint-runtime/src/remote/index.js +12 -0
  62. package/dist/constraint-runtime/src/remote_runtime.js +9 -0
  63. package/dist/constraint-runtime/src/runtime/index.js +1 -0
  64. package/dist/constraint-runtime/src/runtime/session.js +35 -0
  65. package/dist/constraint-runtime/src/schemas/index.js +12 -0
  66. package/dist/constraint-runtime/src/screens/index.js +12 -0
  67. package/dist/constraint-runtime/src/server/index.js +12 -0
  68. package/dist/constraint-runtime/src/services/index.js +12 -0
  69. package/dist/constraint-runtime/src/session_store.js +22 -0
  70. package/dist/constraint-runtime/src/setup.js +30 -0
  71. package/dist/constraint-runtime/src/skills/index.js +1 -0
  72. package/dist/constraint-runtime/src/skills/skill-registry.js +28 -0
  73. package/dist/constraint-runtime/src/state/index.js +12 -0
  74. package/dist/constraint-runtime/src/system_init.js +20 -0
  75. package/dist/constraint-runtime/src/thinking/engine.js +42 -0
  76. package/dist/constraint-runtime/src/thinking/index.js +1 -0
  77. package/dist/constraint-runtime/src/tool_pool.js +8 -0
  78. package/dist/constraint-runtime/src/tools/OpenCLI/execAdapter.js +7 -0
  79. package/dist/constraint-runtime/src/tools/OpenCLI/listAdapters.js +7 -0
  80. package/dist/constraint-runtime/src/tools/OpenCLI/runCommand.js +7 -0
  81. package/dist/constraint-runtime/src/tools/SafeSDK/confirmTransaction.js +6 -0
  82. package/dist/constraint-runtime/src/tools/SafeSDK/createTransaction.js +8 -0
  83. package/dist/constraint-runtime/src/tools/SafeSDK/executeTransaction.js +6 -0
  84. package/dist/constraint-runtime/src/tools/SafeSDK/getBalance.js +6 -0
  85. package/dist/constraint-runtime/src/tools/SafeSDK/getPendingTransactions.js +6 -0
  86. package/dist/constraint-runtime/src/tools/SafeSDK/proposeTransaction.js +6 -0
  87. package/dist/constraint-runtime/src/tools.js +80 -0
  88. package/dist/constraint-runtime/src/transcript.js +19 -0
  89. package/dist/constraint-runtime/src/types/index.js +12 -0
  90. package/dist/constraint-runtime/src/upstream_proxy/index.js +12 -0
  91. package/dist/constraint-runtime/src/utils/index.js +12 -0
  92. package/dist/constraint-runtime/src/vim/index.js +12 -0
  93. package/dist/constraint-runtime/src/voice/index.js +12 -0
  94. package/dist/constraint-runtime/tests/agent.test.js +16 -0
  95. package/dist/constraint-runtime/tests/constraint.test.js +41 -0
  96. package/dist/constraint-runtime/tests/skill.test.js +19 -0
  97. package/dist/constraint-runtime/tests/thinking.test.js +22 -0
  98. package/dist/context-compaction/auto-compact.js +7 -7
  99. package/dist/electron-preload.js +1 -18
  100. package/dist/electron-preload.js.map +1 -1
  101. package/dist/electron.js +168 -3
  102. package/dist/electron.js.map +1 -1
  103. package/dist/index.js +116 -136
  104. package/dist/llm/config-store.js +8 -24
  105. package/dist/llm/llm-judgment-client.js +102 -102
  106. package/dist/llm/pi-ai.js +85 -126
  107. package/dist/llm/system-prompt/layers/channel/local.md +14 -14
  108. package/dist/llm/system-prompt/layers/channel/p2p-agent.md +18 -18
  109. package/dist/llm/system-prompt/layers/channel/p2p-visitor.md +19 -19
  110. package/dist/llm/system-prompt/layers/core/artifacts_storage.md +89 -89
  111. package/dist/llm/system-prompt/layers/core/evenhandedness.md +21 -21
  112. package/dist/llm/system-prompt/layers/core/hibs_reminders.md +15 -15
  113. package/dist/llm/system-prompt/layers/core/identity.md +37 -37
  114. package/dist/llm/system-prompt/layers/core/knowledge.md +17 -17
  115. package/dist/llm/system-prompt/layers/core/memory_system.md +12 -12
  116. package/dist/llm/system-prompt/layers/core/network_filesystem.md +28 -28
  117. package/dist/llm/system-prompt/layers/core/refusal.md +37 -37
  118. package/dist/llm/system-prompt/layers/core/tone.md +31 -31
  119. package/dist/llm/system-prompt/layers/core/tools.thin.md +13 -13
  120. package/dist/llm/system-prompt/layers/core/wellbeing.md +41 -41
  121. package/dist/llm/system-prompt/layers/role/architect.md +20 -20
  122. package/dist/llm/system-prompt/layers/role/expert.md +19 -19
  123. package/dist/llm/system-prompt/layers/role/implementer.md +15 -15
  124. package/dist/llm/system-prompt/layers/role/security.md +15 -15
  125. package/dist/llm/system-prompt/layers/tool/artifacts.md +72 -72
  126. package/dist/llm/system-prompt/layers/tool/bash.md +25 -25
  127. package/dist/llm/system-prompt/layers/tool/hibs_api.md +171 -171
  128. package/dist/llm/system-prompt/layers/tool/image_search.md +70 -70
  129. package/dist/llm/system-prompt/layers/tool/manifest.md +89 -89
  130. package/dist/llm/system-prompt/layers/tool/mcp_apps.md +53 -53
  131. package/dist/llm/system-prompt/layers/tool/web_search.md +83 -83
  132. package/dist/llm/tool-manifest/ask_user_input.js +1 -1
  133. package/dist/llm/tool-manifest/bash.js +3 -3
  134. package/dist/llm/tool-manifest/create_file.js +4 -4
  135. package/dist/llm/tool-manifest/fetch_sports_data.js +3 -3
  136. package/dist/llm/tool-manifest/image_search.js +2 -2
  137. package/dist/llm/tool-manifest/mcp.js +2 -2
  138. package/dist/llm/tool-manifest/message_compose.js +3 -3
  139. package/dist/llm/tool-manifest/places.js +2 -2
  140. package/dist/llm/tool-manifest/present_files.js +1 -1
  141. package/dist/llm/tool-manifest/recipe.js +2 -2
  142. package/dist/llm/tool-manifest/str_replace.js +5 -5
  143. package/dist/llm/tool-manifest/view.js +3 -3
  144. package/dist/llm/tool-manifest/weather.js +4 -4
  145. package/dist/llm/tool-manifest/web.js +4 -4
  146. package/dist/pi-ecosystem-colony/index.js +365 -0
  147. package/dist/pi-ecosystem-judgment/causal-judge.js +51 -51
  148. package/dist/pi-ecosystem-judgment/distill-prompt.js +42 -42
  149. package/dist/pi-ecosystem-judgment/distillation.js +14 -14
  150. package/dist/pi-ecosystem-judgment/monitor-gate.js +28 -28
  151. package/dist/pi-ecosystem-judgment/value-injection.js +102 -102
  152. package/dist/security/context-router-tool.js +15 -15
  153. package/dist/security/tool-gate.js +0 -11
  154. package/dist/social/ant-colony/AdaptiveHeartbeat.js +101 -0
  155. package/dist/social/ant-colony/PheromoneEngine.js +227 -0
  156. package/dist/social/ant-colony/index.js +6 -0
  157. package/dist/social/ant-colony/types.js +24 -0
  158. package/dist/test/ai-judgment-test.js +80 -0
  159. package/dist/test/bollharness-integration.test.js +318 -0
  160. package/dist/test/channel-agent-multi-dialogue.js +205 -0
  161. package/dist/test/channel-heartbeat-agent-test.js +201 -0
  162. package/dist/test/constraint-layer.test.js +164 -0
  163. package/dist/test/diap-identity-test.js +172 -0
  164. package/dist/test/diap-quick-test.js +62 -0
  165. package/dist/test/global-shared-context.test.js +315 -0
  166. package/dist/test/harness-judgment-injection.test.js +246 -0
  167. package/dist/test/harness-workflow-integrator-test.js +228 -0
  168. package/dist/test/human-value-store.test.js +243 -0
  169. package/dist/test/hybrid-integration-test.js +118 -0
  170. package/dist/test/hybrid-messenger-verify.js +55 -0
  171. package/dist/test/iroh-bistream-debug.js +38 -0
  172. package/dist/test/iroh-communication.test.js +66 -0
  173. package/dist/test/iroh-debug-test.js +57 -0
  174. package/dist/test/iroh-diap-test.js +71 -0
  175. package/dist/test/iroh-direct-connect.js +55 -0
  176. package/dist/test/iroh-e2e-fixed.js +89 -0
  177. package/dist/test/iroh-e2e-same-process.js +63 -0
  178. package/dist/test/iroh-e2e.js +66 -0
  179. package/dist/test/iroh-final-e2e.js +72 -0
  180. package/dist/test/iroh-relay-test.js +37 -0
  181. package/dist/test/iroh-simple-test.js +41 -0
  182. package/dist/test/iroh-transport-verify.js +54 -0
  183. package/dist/test/iroh-transport.test.js +37 -0
  184. package/dist/test/iroh-two-nodes.js +70 -0
  185. package/dist/test/iroh-verify.js +44 -0
  186. package/dist/test/judgment-decision.test.js +219 -0
  187. package/dist/test/llm-judgment-integration.test.js +220 -0
  188. package/dist/test/p2p-agent-complex-dialogue.js +385 -0
  189. package/dist/test/p2p-agent-dialogue.js +341 -0
  190. package/dist/test/p2p-agent-full-bidirectional.js +510 -0
  191. package/dist/test/p2p-agent-harness-flow.js +437 -0
  192. package/dist/test/p2p-agent-harness-single.js +143 -0
  193. package/dist/test/p2p-ai-dialogue-test.js +318 -0
  194. package/dist/test/p2p-cid-connect-test.js +195 -0
  195. package/dist/test/p2p-connect-receiver.js +69 -0
  196. package/dist/test/p2p-doc-transfer.js +110 -0
  197. package/dist/test/p2p-identity-page-test.js +77 -0
  198. package/dist/test/p2p-iroh-test.js +171 -0
  199. package/dist/test/p2p-minimal-test.js +241 -0
  200. package/dist/test/p2p-node-1.js +148 -0
  201. package/dist/test/p2p-node-2.js +148 -0
  202. package/dist/test/p2p-server.js +281 -0
  203. package/dist/test/p2p-two-nodes-test.js +438 -0
  204. package/dist/test/pi-sdk.test.js +44 -0
  205. package/dist/test/set-persona.js +40 -0
  206. package/dist/test/simple.test.js +9 -0
  207. package/dist/test/storage-integration.test.js +150 -0
  208. package/dist/test/subagent-manager.test.js +276 -0
  209. package/dist/test/test-gate-flow.test.js +81 -0
  210. package/dist/test/workflow-engine.test.js +87 -0
  211. package/dist/test/workflow-pivot-loop.test.js +246 -0
  212. package/dist/web/api-config.html +520 -520
  213. package/dist/web/client.js +2917 -3791
  214. package/dist/web/components/p2p/index.js +234 -276
  215. package/dist/web/components/wallet-viem.mjs +118 -118
  216. package/dist/web/index.html +374 -373
  217. package/dist/web/manifest.json +20 -20
  218. package/dist/web/server.js +23 -775
  219. package/dist/web/style.css +4737 -4737
  220. package/dist/web/ui/message-renderer.js +373 -451
  221. package/dist/web/ui/step-timeline.js +255 -351
  222. package/package.json +160 -160
  223. package/scripts/build-cli.js +215 -215
  224. package/scripts/build-web.ts +125 -125
  225. package/scripts/postinstall.js +152 -152
  226. package/bin/bolloon-daemon.sh +0 -207
  227. package/bin/ipfs +0 -0
  228. package/dist/agents/chat-segmenter.js +0 -298
  229. package/dist/agents/judgment-protocol.js +0 -479
  230. package/dist/agents/parse-tool-call.js +0 -304
  231. package/dist/agents/peer-manifest-loader.js +0 -210
  232. package/dist/agents/react-loop.js +0 -120
  233. package/dist/agents/session-store.js +0 -171
  234. package/dist/agents/tool-registry.js +0 -136
  235. package/dist/bootstrap/chat-archiver.js +0 -276
  236. package/dist/bootstrap/memory-compressor.js +0 -170
  237. package/dist/bootstrap/persona-loader.js +0 -94
  238. package/dist/electron/config.js +0 -16
  239. package/dist/electron/config.js.map +0 -1
  240. package/dist/electron/dialogs.js +0 -71
  241. package/dist/electron/dialogs.js.map +0 -1
  242. package/dist/electron/first-run.js +0 -129
  243. package/dist/electron/first-run.js.map +0 -1
  244. package/dist/electron/ipc.js +0 -16
  245. package/dist/electron/ipc.js.map +0 -1
  246. package/dist/electron/logger.js +0 -77
  247. package/dist/electron/logger.js.map +0 -1
  248. package/dist/electron/main.js +0 -60
  249. package/dist/electron/main.js.map +0 -1
  250. package/dist/electron/menu.js +0 -140
  251. package/dist/electron/menu.js.map +0 -1
  252. package/dist/electron/paths.js +0 -33
  253. package/dist/electron/paths.js.map +0 -1
  254. package/dist/electron/server.js +0 -74
  255. package/dist/electron/server.js.map +0 -1
  256. package/dist/electron/tray.js +0 -73
  257. package/dist/electron/tray.js.map +0 -1
  258. package/dist/electron/window.js +0 -69
  259. package/dist/electron/window.js.map +0 -1
  260. package/dist/network/local-inbox-bus.js +0 -73
  261. package/dist/network/p2p-outbox.js +0 -161
  262. package/dist/network/peer-fs.js +0 -420
  263. package/dist/network/peer-resource-bridge.js +0 -216
  264. package/dist/web/components/p2p/P2PModal.js +0 -188
  265. package/dist/web/components/p2p/p2p-modal.js +0 -664
  266. package/dist/web/components/p2p/p2p-tools.js +0 -248
  267. package/dist/web/input-validator.js +0 -103
  268. package/dist/web/util/safe-name.js +0 -32
@@ -1,170 +0,0 @@
1
- /**
2
- * Memory Compressor — session 消息 → LLM 摘要 → ~/.bolloon/memory/<agentId>/sessions/
3
- *
4
- * 触发: 每次 /message 处理后, saveSession 之后 (server.ts:2073 之后)
5
- * 行为:
6
- * - 读 session messages
7
- * - 只压缩 cursor 之后的增量 (≥ 4 条新 messages 才压缩, 防频繁)
8
- * - 调 LLM 生成中文摘要 (失败 fallback 到纯模板)
9
- * - append 模式写入 <safe-channelId>__<safe-sessionId>.summary.md
10
- * - 维护 cursor 文件 <safe-channelId>__<safe-sessionId>.cursor
11
- *
12
- * 失败静默: 调用方 try/catch 后 console.warn, 不阻塞主对话.
13
- */
14
- import * as fs from 'fs/promises';
15
- import * as os from 'os';
16
- import * as path from 'path';
17
- export function sanitizeAgentId(id) {
18
- return id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
19
- }
20
- export function sanitizeKey(id) {
21
- return id.replace(/[^a-zA-Z0-9_.-]/g, '_').slice(0, 128);
22
- }
23
- /**
24
- * ~/.bolloon/memory/<sanitizedAgentId>/
25
- */
26
- export function getMemoryDir(agentId, home) {
27
- return path.join(home || os.homedir(), '.bolloon', 'memory', sanitizeAgentId(agentId));
28
- }
29
- /**
30
- * ~/.bolloon/memory/<agentId>/sessions/<safe-channelId>__<safe-sessionId>.summary.md
31
- */
32
- export function getSessionSummaryPath(agentId, channelId, sessionId, home) {
33
- const key = `${sanitizeKey(channelId)}__${sanitizeKey(sessionId)}`;
34
- return path.join(getMemoryDir(agentId, home), 'sessions', `${key}.summary.md`);
35
- }
36
- export function getSessionCursorPath(agentId, channelId, sessionId, home) {
37
- const key = `${sanitizeKey(channelId)}__${sanitizeKey(sessionId)}`;
38
- return path.join(getMemoryDir(agentId, home), 'sessions', `${key}.cursor`);
39
- }
40
- /**
41
- * Session 缓存文件路径 (跟 server.ts:1806 sessionKey 规则一致)
42
- */
43
- function getSessionCacheFile(channelId, sessionId, home) {
44
- const root = path.join(home || os.homedir(), '.bolloon', 'sessions', 'cache');
45
- const safeChannel = sanitizeKey(channelId);
46
- const safeSession = sanitizeKey(sessionId).replace(/:/g, '__');
47
- return path.join(root, `${safeChannel}__${safeSession}.json`);
48
- }
49
- async function readCursor(cursorPath) {
50
- try {
51
- const raw = await fs.readFile(cursorPath, 'utf-8');
52
- const n = parseInt(raw.trim(), 10);
53
- return Number.isFinite(n) && n >= 0 ? n : 0;
54
- }
55
- catch {
56
- return 0;
57
- }
58
- }
59
- async function writeCursor(cursorPath, value) {
60
- await fs.mkdir(path.dirname(cursorPath), { recursive: true });
61
- await fs.writeFile(cursorPath, String(value), 'utf-8');
62
- }
63
- async function readSessionMessages(sessionCacheFile) {
64
- try {
65
- const raw = await fs.readFile(sessionCacheFile, 'utf-8');
66
- const parsed = JSON.parse(raw);
67
- if (Array.isArray(parsed))
68
- return parsed;
69
- if (Array.isArray(parsed.messages))
70
- return parsed.messages;
71
- return [];
72
- }
73
- catch {
74
- return [];
75
- }
76
- }
77
- /**
78
- * 纯模板摘要 (LLM 失败 fallback, 不依赖外部调用)
79
- */
80
- function templateSummary(opts) {
81
- const userMsgs = opts.newMessages.filter(m => m.type === 'user');
82
- const aiMsgs = opts.newMessages.filter(m => m.type === 'ai');
83
- const userSnippet = userMsgs.slice(0, 3).map(m => ` - ${m.content.slice(0, 80)}`).join('\n');
84
- const aiSnippet = aiMsgs.slice(0, 3).map(m => ` - ${m.content.slice(0, 80)}`).join('\n');
85
- return `# Session 摘要 — ${opts.channelId} / ${opts.sessionId}
86
-
87
- 时间: ${opts.timestamp}
88
- 新增消息数: ${opts.newMessages.length} (user=${userMsgs.length}, ai=${aiMsgs.length})
89
-
90
- ## 用户关键提问
91
- ${userSnippet || ' (无)'}
92
-
93
- ## AI 关键回答
94
- ${aiSnippet || ' (无)'}
95
-
96
- ## 备注
97
- - 此摘要由模板生成 (LLM 调用失败 fallback)
98
- `;
99
- }
100
- /**
101
- * 尝试调 LLM 生成更精炼的中文摘要. 失败 → 抛错, 由 caller fallback.
102
- *
103
- * 用动态 import + 失败静默 — 不引入 pi-ai 强依赖 (避免循环).
104
- */
105
- async function tryLlmSummary(systemPrompt, userPrompt) {
106
- try {
107
- const piAi = await import('../llm/pi-ai.js');
108
- const generateText = piAi.generateText;
109
- if (typeof generateText !== 'function')
110
- throw new Error('generateText not exported');
111
- const result = await generateText({
112
- messages: [
113
- { role: 'system', content: systemPrompt },
114
- { role: 'user', content: userPrompt },
115
- ],
116
- temperature: 0.2,
117
- maxTokens: 800,
118
- });
119
- const text = result?.reply || result?.text || '';
120
- if (typeof text !== 'string' || text.length < 20)
121
- throw new Error('LLM returned too-short text');
122
- return text;
123
- }
124
- catch (e) {
125
- throw new Error(`LLM call failed: ${e?.message || String(e)}`);
126
- }
127
- }
128
- export async function compressSessionToMemory(opts) {
129
- const agentId = sanitizeAgentId(opts.agentId);
130
- const home = opts.home || os.homedir();
131
- const summaryPath = getSessionSummaryPath(agentId, opts.channelId, opts.sessionId, home);
132
- const cursorPath = getSessionCursorPath(agentId, opts.channelId, opts.sessionId, home);
133
- const sessionCacheFile = getSessionCacheFile(opts.channelId, opts.sessionId, home);
134
- const allMessages = await readSessionMessages(sessionCacheFile);
135
- const cursor = await readCursor(cursorPath);
136
- const newMessages = allMessages.slice(cursor);
137
- const minNew = opts.minNewMessages ?? 4;
138
- if (allMessages.length === 0) {
139
- return { summaryPath, cursorPath, messagesCount: 0, bytesWritten: 0, skipped: 'no-new-messages' };
140
- }
141
- if (newMessages.length < minNew) {
142
- return { summaryPath, cursorPath, messagesCount: newMessages.length, bytesWritten: 0, skipped: 'too-few-messages' };
143
- }
144
- const timestamp = new Date().toISOString();
145
- let summaryBody;
146
- try {
147
- const sysPrompt = '你是 bolloon 记忆压缩助手. 输入是一段 session 消息历史 (用户问题 + AI 回答), 输出 200-400 字中文摘要, 包含 3-5 条关键发现和未完成事项. 不要寒暄, 不要复述已知. 格式: ## 关键发现 / ## 待办.';
148
- const recentSnippet = newMessages.slice(-10).map(m => `[${m.type}] ${m.content}`).join('\n---\n').slice(0, 6000);
149
- const userPrompt = `Channel: ${opts.channelId}\nSession: ${opts.sessionId}\n时间: ${timestamp}\n新增消息数: ${newMessages.length}\n\n最近消息:\n${recentSnippet}`;
150
- summaryBody = await tryLlmSummary(sysPrompt, userPrompt);
151
- }
152
- catch (e) {
153
- summaryBody = templateSummary({
154
- channelId: opts.channelId,
155
- sessionId: opts.sessionId,
156
- newMessages,
157
- timestamp,
158
- });
159
- }
160
- const block = `\n\n---\n\n## 增量摘要 @ ${timestamp} (${newMessages.length} messages)\n\n${summaryBody.trim()}\n`;
161
- await fs.mkdir(path.dirname(summaryPath), { recursive: true });
162
- await fs.appendFile(summaryPath, block, 'utf-8');
163
- await writeCursor(cursorPath, allMessages.length);
164
- return {
165
- summaryPath,
166
- cursorPath,
167
- messagesCount: newMessages.length,
168
- bytesWritten: Buffer.byteLength(block, 'utf-8'),
169
- };
170
- }
@@ -1,94 +0,0 @@
1
- /**
2
- * Persona Documents Loader — ~/.bolloon/persona/<agentId>/*.md
3
- *
4
- * 失败静默: 文件不存在 → 字段 = '', 不抛错
5
- * 安全: agentId sanitize (防路径穿越)
6
- * 6 段输出顺序: identity → soul → project → user → agent → wiki
7
- */
8
- import * as fs from 'fs/promises';
9
- import * as os from 'os';
10
- import * as path from 'path';
11
- const FILE_KEYS = ['soul', 'identity', 'project', 'user', 'agent', 'wiki'];
12
- /**
13
- * 安全转 agentId: 只保留 [a-zA-Z0-9_-], 限长 64
14
- * 防止路径穿越 ('/', '..', '\\\\' 都变 '_')
15
- */
16
- export function sanitizeAgentId(id) {
17
- return id.replace(/[^a-zA-Z0-9_-]/g, '_').slice(0, 64);
18
- }
19
- /**
20
- * 读 ~/.bolloon/persona/<sanitizedAgentId>/{6 files}
21
- * 文件不存在 → 该字段 = ''
22
- */
23
- export async function loadPersonaDocs(agentId, home) {
24
- const safeId = sanitizeAgentId(agentId);
25
- const root = home || os.homedir();
26
- const baseDir = path.join(root, '.bolloon', 'persona', safeId);
27
- const docs = {
28
- agentId: safeId,
29
- soul: '',
30
- identity: '',
31
- project: '',
32
- user: '',
33
- agent: '',
34
- wiki: '',
35
- };
36
- await Promise.all(FILE_KEYS.map(async (key) => {
37
- const file = path.join(baseDir, `${key}.md`);
38
- try {
39
- const content = await fs.readFile(file, 'utf-8');
40
- docs[key] = content;
41
- }
42
- catch {
43
- docs[key] = '';
44
- }
45
- }));
46
- return docs;
47
- }
48
- const DEFAULT_MAX_CHARS = 4000;
49
- const SECTION_LABELS = {
50
- identity: 'Identity',
51
- soul: 'Soul',
52
- project: 'Project',
53
- user: 'User',
54
- agent: 'Agent',
55
- wiki: 'Wiki',
56
- };
57
- const OUTPUT_ORDER = ['identity', 'soul', 'project', 'user', 'agent', 'wiki'];
58
- /**
59
- * 把 PersonaDocs 格式化成 markdown 段, 拼到 system prompt 头部.
60
- *
61
- * 超 maxChars 时按比例截断: 每个字段都保留头部,
62
- * 保证 6 段标识都出现, 不砍段.
63
- */
64
- export function formatPersonaForSystemPrompt(docs, maxChars) {
65
- const cap = maxChars ?? DEFAULT_MAX_CHARS;
66
- // 段: 标识 + 字段值 (空字段跳过)
67
- const sections = [];
68
- for (const key of OUTPUT_ORDER) {
69
- const v = docs[key];
70
- if (v && v.length > 0) {
71
- sections.push({ key, text: `## ${SECTION_LABELS[key]}\n${v}` });
72
- }
73
- }
74
- if (sections.length === 0)
75
- return '';
76
- // 预算每段 (去掉 ## 标识和换行的固定开销)
77
- const header = `# Persona (agentId=${docs.agentId})\n\n`;
78
- const fixedOverhead = header.length + (sections.length - 1) * 2;
79
- const perSectionBudget = Math.max(50, Math.floor((cap - fixedOverhead) / sections.length));
80
- const parts = [header.trim()];
81
- for (const sec of sections) {
82
- let body = sec.text;
83
- if (body.length > perSectionBudget) {
84
- body = body.substring(0, perSectionBudget) + '\n... (截断)';
85
- }
86
- parts.push(body);
87
- }
88
- let result = parts.join('\n\n');
89
- if (result.length > cap) {
90
- const truncateMarker = '\n... (截断)';
91
- result = result.substring(0, Math.max(0, cap - truncateMarker.length)) + truncateMarker;
92
- }
93
- return result;
94
- }
@@ -1,16 +0,0 @@
1
- /**
2
- * 常量配置 (env 解析在这里集中, 不散在 main 流程)
3
- */
4
- import { app } from 'electron';
5
- export const DEFAULT_PORT = 54188;
6
- /** Hard-pin to loopback; LAN exposure must be explicit. */
7
- export const DEFAULT_HOST = '127.0.0.1';
8
- export const WEB_SERVER_STARTUP_TIMEOUT_MS = 15_000;
9
- export const MAIN_WINDOW_DEFAULT = { width: 1200, height: 800 };
10
- export const MAIN_WINDOW_MIN = { width: 800, height: 600 };
11
- export function preferredPort() {
12
- const raw = process.env.ELECTRON_PORT || process.env.PORT;
13
- const n = parseInt(raw || '', 10);
14
- return Number.isFinite(n) && n > 0 && n < 65536 ? n : DEFAULT_PORT;
15
- }
16
- export const isDev = process.env.NODE_ENV === 'development' || !app.isPackaged;
@@ -1 +0,0 @@
1
- {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/electron/config.ts"],"names":[],"mappings":";;;AAcA,sCAIC;AAlBD;;GAEG;AACH,uCAA+B;AAElB,QAAA,YAAY,GAAG,KAAK,CAAC;AAClC,2DAA2D;AAC9C,QAAA,YAAY,GAAG,WAAW,CAAC;AAE3B,QAAA,6BAA6B,GAAG,MAAM,CAAC;AAEvC,QAAA,mBAAmB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AACnD,QAAA,eAAe,GAAG,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;AAE3D,SAAgB,aAAa;IAC3B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC;IAC1D,MAAM,CAAC,GAAG,QAAQ,CAAC,GAAG,IAAI,EAAE,EAAE,EAAE,CAAC,CAAC;IAClC,OAAO,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,oBAAY,CAAC;AACrE,CAAC;AAEY,QAAA,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,KAAK,aAAa,IAAI,CAAC,cAAG,CAAC,UAAU,CAAC"}
@@ -1,71 +0,0 @@
1
- /**
2
- * 文件 dialog 桥 (open / save / dir) + 安全的 fs 桥 (read / write / exists)
3
- *
4
- * 5MB read 上限保护 — 渲染进程直接 fs.readFile 没法做限制, 走主进程就有界
5
- * 所有 handler 解析 event.sender 拿到 window, 让 dialog 模态在该窗口上
6
- */
7
- import { BrowserWindow, dialog, ipcMain } from 'electron';
8
- import * as fs from 'fs';
9
- import * as path from 'path';
10
- import { log } from './logger';
11
- const MAX_READ_BYTES = 5 * 1024 * 1024; // 5MB
12
- function windowFor(event) {
13
- return BrowserWindow.fromWebContents(event.sender);
14
- }
15
- function resolveSafe(target) {
16
- // 不去硬限制路径 — user 给 renderer 暴露 fs 已经信任了, 这里只 normalize
17
- return path.resolve(target);
18
- }
19
- export function registerDialogIpc() {
20
- ipcMain.handle('dialog:open-file', async (event, opts = {}) => {
21
- const win = windowFor(event);
22
- const result = await dialog.showOpenDialog(win, {
23
- title: opts.title,
24
- defaultPath: opts.defaultPath,
25
- filters: opts.filters,
26
- properties: opts.properties ?? ['openFile'],
27
- });
28
- return { canceled: result.canceled, filePaths: result.filePaths };
29
- });
30
- ipcMain.handle('dialog:save-file', async (event, opts = {}) => {
31
- const win = windowFor(event);
32
- const result = await dialog.showSaveDialog(win, {
33
- title: opts.title,
34
- defaultPath: opts.defaultPath,
35
- filters: opts.filters,
36
- });
37
- return { canceled: result.canceled, filePath: result.filePath };
38
- });
39
- ipcMain.handle('dialog:open-directory', async (event, opts = {}) => {
40
- const win = windowFor(event);
41
- const result = await dialog.showOpenDialog(win, {
42
- title: opts.title,
43
- defaultPath: opts.defaultPath,
44
- properties: ['openDirectory', 'createDirectory'],
45
- });
46
- return { canceled: result.canceled, filePaths: result.filePaths };
47
- });
48
- ipcMain.handle('fs:read-text-file', async (_event, opts) => {
49
- const target = resolveSafe(opts.path);
50
- const stat = fs.statSync(target);
51
- if (stat.size > MAX_READ_BYTES) {
52
- throw new Error(`文件过大: ${stat.size} > ${MAX_READ_BYTES} bytes`);
53
- }
54
- return fs.readFileSync(target, { encoding: opts.encoding ?? 'utf8' });
55
- });
56
- ipcMain.handle('fs:write-text-file', async (_event, opts) => {
57
- const target = resolveSafe(opts.path);
58
- fs.mkdirSync(path.dirname(target), { recursive: true });
59
- fs.writeFileSync(target, opts.content, { encoding: opts.encoding ?? 'utf8' });
60
- });
61
- ipcMain.handle('fs:path-exists', async (_event, opts) => {
62
- try {
63
- fs.accessSync(resolveSafe(opts.path));
64
- return true;
65
- }
66
- catch {
67
- return false;
68
- }
69
- });
70
- log('dialog + fs IPC handlers registered');
71
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"dialogs.js","sourceRoot":"","sources":["../../src/electron/dialogs.ts"],"names":[],"mappings":"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"}
@@ -1,129 +0,0 @@
1
- /**
2
- * 首启检测 + 引导浮层
3
- *
4
- * 标记文件写在 userData (不是 ~/.bolloon/), 卸载 app 自然清掉
5
- * 引导窗是父主窗的 modal, frame=false, 透明背景; 关闭时标记写入
6
- */
7
- import { BrowserWindow, app, ipcMain } from 'electron';
8
- import * as fs from 'fs';
9
- import * as path from 'path';
10
- import { firstRunFlagPath, dataDir, logsDir } from './paths';
11
- import { log } from './logger';
12
- const OVERLAY_HTML = `
13
- <!DOCTYPE html>
14
- <html>
15
- <head>
16
- <meta charset="utf-8" />
17
- <style>
18
- :root { color-scheme: light dark; }
19
- body {
20
- font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
21
- margin: 0; padding: 32px 28px;
22
- background: rgba(245,245,247,0.97);
23
- color: #1d1d1f;
24
- height: 100vh; box-sizing: border-box;
25
- }
26
- @media (prefers-color-scheme: dark) {
27
- body { background: rgba(28,28,30,0.97); color: #f5f5f7; }
28
- }
29
- h1 { font-size: 18px; margin: 0 0 14px; font-weight: 600; }
30
- p { font-size: 13px; line-height: 1.55; margin: 8px 0; }
31
- code {
32
- font-family: ui-monospace, "SF Mono", Menlo, monospace;
33
- font-size: 12px; padding: 1px 5px;
34
- background: rgba(0,0,0,0.06); border-radius: 3px;
35
- }
36
- @media (prefers-color-scheme: dark) {
37
- code { background: rgba(255,255,255,0.08); }
38
- }
39
- .btn {
40
- display: inline-block; margin-top: 18px; padding: 8px 18px;
41
- background: #007aff; color: #fff; border: none; border-radius: 6px;
42
- font-size: 13px; font-weight: 500; cursor: pointer;
43
- }
44
- .btn:hover { background: #0066d6; }
45
- ul { padding-left: 20px; }
46
- li { font-size: 13px; line-height: 1.7; }
47
- </style>
48
- </head>
49
- <body>
50
- <h1>欢迎使用 Bolloon Agent</h1>
51
- <p>你的数据存放在本地, 不上传:</p>
52
- <ul>
53
- <li>配置 / 频道 / P2P 密钥: <code id="data"></code></li>
54
- <li>运行日志: <code id="logs"></code></li>
55
- </ul>
56
- <p>所有数据在卸载后仍保留 — 想清理就手动删除 ~/.bolloon/。</p>
57
- <button class="btn" id="ok">知道了</button>
58
- <script>
59
- const ok = document.getElementById('ok');
60
- ok.addEventListener('click', () => window.electronAPI.markFirstRunSeen());
61
- document.getElementById('data').textContent = window.electronAPI.getDataPathSync?.() || '';
62
- document.getElementById('logs').textContent = window.electronAPI.getLogsPathSync?.() || '';
63
- </script>
64
- </body>
65
- </html>
66
- `;
67
- export function hasSeenFirstRun() {
68
- try {
69
- return fs.existsSync(firstRunFlagPath());
70
- }
71
- catch {
72
- return false;
73
- }
74
- }
75
- export function markFirstRunSeen() {
76
- try {
77
- fs.mkdirSync(path.dirname(firstRunFlagPath()), { recursive: true });
78
- fs.writeFileSync(firstRunFlagPath(), new Date().toISOString());
79
- }
80
- catch (err) {
81
- log(`写入首启标记失败: ${err.message}`, 'warn');
82
- }
83
- }
84
- export function showFirstRunOverlay(parent) {
85
- return new Promise((resolve) => {
86
- const overlay = new BrowserWindow({
87
- parent,
88
- modal: true,
89
- frame: false,
90
- transparent: true,
91
- width: 520,
92
- height: 360,
93
- resizable: false,
94
- movable: false,
95
- minimizable: false,
96
- maximizable: false,
97
- title: 'Welcome',
98
- });
99
- const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(OVERLAY_HTML);
100
- overlay.loadURL(dataUrl);
101
- // 一次性的 IPC handler, 关闭后清掉避免累积
102
- const handler = () => {
103
- markFirstRunSeen();
104
- overlay.close();
105
- };
106
- ipcMain.once('first-run:ack', handler);
107
- overlay.on('closed', () => {
108
- ipcMain.removeListener('first-run:ack', handler);
109
- resolve();
110
- });
111
- });
112
- }
113
- /** 注册 IPC handlers (给 preload 桥用) */
114
- export function registerFirstRunIpc() {
115
- ipcMain.handle('first-run:seen', () => hasSeenFirstRun());
116
- ipcMain.handle('first-run:mark-seen', () => { markFirstRunSeen(); });
117
- // 同步值 (不用 ipcRenderer.invoke 的 await) — 用 exposeInMainWorld 的 sync getter 更顺
118
- ipcMain.handle('first-run:data-dir', () => dataDir());
119
- ipcMain.handle('first-run:logs-dir', () => logsDir());
120
- log('first-run IPC handlers registered');
121
- }
122
- /** 包装 — 决定要不要弹 overlay */
123
- export async function maybeShowFirstRun(parent) {
124
- if (hasSeenFirstRun())
125
- return;
126
- log('首启 — 弹出引导');
127
- await showFirstRunOverlay(parent);
128
- app.addRecentDocument(firstRunFlagPath()); // 跟踪最近文档, 让 user 知道有这文件
129
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"first-run.js","sourceRoot":"","sources":["../../src/electron/first-run.ts"],"names":[],"mappings":"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"}
@@ -1,16 +0,0 @@
1
- /**
2
- * IPC handler 集中注册 — version / userData path / open-external (legacy 3 个)
3
- * dialog/fs 的注册在 dialogs.ts; updater 的注册在 updater.ts
4
- */
5
- import { app, ipcMain, shell } from 'electron';
6
- import { userDataDir, dataDir } from './paths';
7
- import { log } from './logger';
8
- export function registerCoreIpc() {
9
- ipcMain.handle('get-version', () => app.getVersion());
10
- ipcMain.handle('get-user-data-path', () => userDataDir());
11
- ipcMain.handle('get-data-path', () => dataDir()); // 跟 userData 分开, 渲染层要用
12
- ipcMain.handle('open-external', async (_event, url) => {
13
- await shell.openExternal(url);
14
- });
15
- log('core IPC handlers registered');
16
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"ipc.js","sourceRoot":"","sources":["../../src/electron/ipc.ts"],"names":[],"mappings":";;AAQA,0CAWC;AAnBD;;;GAGG;AACH,uCAA+C;AAC/C,mCAA+C;AAC/C,qCAA+B;AAE/B,SAAgB,eAAe;IAC7B,kBAAO,CAAC,MAAM,CAAC,aAAa,EAAE,GAAG,EAAE,CAAC,cAAG,CAAC,UAAU,EAAE,CAAC,CAAC;IAEtD,kBAAO,CAAC,MAAM,CAAC,oBAAoB,EAAE,GAAG,EAAE,CAAC,IAAA,mBAAW,GAAE,CAAC,CAAC;IAC1D,kBAAO,CAAC,MAAM,CAAC,eAAe,EAAE,GAAG,EAAE,CAAC,IAAA,eAAO,GAAE,CAAC,CAAC,CAAC,uBAAuB;IAEzE,kBAAO,CAAC,MAAM,CAAC,eAAe,EAAE,KAAK,EAAE,MAAM,EAAE,GAAW,EAAE,EAAE;QAC5D,MAAM,gBAAK,CAAC,YAAY,CAAC,GAAG,CAAC,CAAC;IAChC,CAAC,CAAC,CAAC;IAEH,IAAA,YAAG,EAAC,8BAA8B,CAAC,CAAC;AACtC,CAAC"}
@@ -1,77 +0,0 @@
1
- /**
2
- * 简单 logger: 写日志到 <userData>/logs/bolloon.log, size-based 轮转
3
- * (5MB 上限, 保留 .1 .2 .3 共 3 个备份 → ~20MB 上限)
4
- *
5
- * 同步写是因为 Electron 主进程日志量小, 同步 append 简单可靠, 不丢日志.
6
- * 量大的会话级 jsonl 走自己路径 (lifecycle-hooks 等), 跟本 logger 无关.
7
- */
8
- import * as fs from 'fs';
9
- import { mainLogPath, logsDir } from './paths';
10
- const MAX_BYTES = 5 * 1024 * 1024;
11
- const MAX_BACKUPS = 3; // 保留 bolloon.log.1 .2 .3
12
- let currentSize = 0;
13
- let initialized = false;
14
- function ensureLogFile() {
15
- if (initialized)
16
- return;
17
- initialized = true;
18
- try {
19
- fs.mkdirSync(logsDir(), { recursive: true });
20
- try {
21
- currentSize = fs.statSync(mainLogPath()).size;
22
- }
23
- catch {
24
- currentSize = 0;
25
- }
26
- }
27
- catch (err) {
28
- // 失败也无所谓, log() 内部会 swallow
29
- currentSize = 0;
30
- console.error('[logger] ensureLogFile failed:', err);
31
- }
32
- }
33
- function rotate() {
34
- const logPath = mainLogPath();
35
- for (let i = MAX_BACKUPS; i >= 1; i--) {
36
- const src = `${logPath}.${i}`;
37
- const dst = `${logPath}.${i + 1}`;
38
- if (i === MAX_BACKUPS) {
39
- try {
40
- fs.unlinkSync(src);
41
- }
42
- catch { /* missing ok */ }
43
- }
44
- else {
45
- try {
46
- fs.renameSync(src, dst);
47
- }
48
- catch { /* missing ok */ }
49
- }
50
- }
51
- try {
52
- fs.renameSync(logPath, `${logPath}.1`);
53
- }
54
- catch { /* missing ok */ }
55
- currentSize = 0;
56
- }
57
- export function log(message, level = 'info') {
58
- ensureLogFile();
59
- const ts = new Date().toISOString();
60
- const line = `[${ts}] [${level}] ${message}\n`;
61
- if (currentSize + line.length > MAX_BYTES)
62
- rotate();
63
- try {
64
- fs.appendFileSync(mainLogPath(), line);
65
- currentSize += line.length;
66
- }
67
- catch (err) {
68
- // 写不进就 console, 不要再递归 log
69
- console.error('[logger] appendFileSync failed:', err);
70
- }
71
- if (level === 'error')
72
- console.error(line.trimEnd());
73
- else if (level === 'warn')
74
- console.warn(line.trimEnd());
75
- else
76
- console.log(line.trimEnd());
77
- }
@@ -1 +0,0 @@
1
- {"version":3,"file":"logger.js","sourceRoot":"","sources":["../../src/electron/logger.ts"],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;AAmDA,kBAkBC;AArED;;;;;;GAMG;AACH,uCAAyB;AAEzB,mCAA+C;AAE/C,MAAM,SAAS,GAAG,CAAC,GAAG,IAAI,GAAG,IAAI,CAAC;AAClC,MAAM,WAAW,GAAG,CAAC,CAAC,CAAC,yBAAyB;AAEhD,IAAI,WAAW,GAAG,CAAC,CAAC;AACpB,IAAI,WAAW,GAAG,KAAK,CAAC;AAExB,SAAS,aAAa;IACpB,IAAI,WAAW;QAAE,OAAO;IACxB,WAAW,GAAG,IAAI,CAAC;IACnB,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,IAAA,eAAO,GAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC7C,IAAI,CAAC;YACH,WAAW,GAAG,EAAE,CAAC,QAAQ,CAAC,IAAA,mBAAW,GAAE,CAAC,CAAC,IAAI,CAAC;QAChD,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,GAAG,CAAC,CAAC;QAClB,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,4BAA4B;QAC5B,WAAW,GAAG,CAAC,CAAC;QAChB,OAAO,CAAC,KAAK,CAAC,gCAAgC,EAAE,GAAG,CAAC,CAAC;IACvD,CAAC;AACH,CAAC;AAED,SAAS,MAAM;IACb,MAAM,OAAO,GAAG,IAAA,mBAAW,GAAE,CAAC;IAC9B,KAAK,IAAI,CAAC,GAAG,WAAW,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;QACtC,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,CAAC,EAAE,CAAC;QAC9B,MAAM,GAAG,GAAG,GAAG,OAAO,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;QAClC,IAAI,CAAC,KAAK,WAAW,EAAE,CAAC;YACtB,IAAI,CAAC;gBAAC,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;QACxD,CAAC;aAAM,CAAC;YACN,IAAI,CAAC;gBAAC,EAAE,CAAC,UAAU,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC;YAAC,CAAC;YAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;QAC7D,CAAC;IACH,CAAC;IACD,IAAI,CAAC;QAAC,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,GAAG,OAAO,IAAI,CAAC,CAAC;IAAC,CAAC;IAAC,MAAM,CAAC,CAAC,gBAAgB,CAAC,CAAC;IAC1E,WAAW,GAAG,CAAC,CAAC;AAClB,CAAC;AAID,SAAgB,GAAG,CAAC,OAAe,EAAE,QAAkB,MAAM;IAC3D,aAAa,EAAE,CAAC;IAChB,MAAM,EAAE,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACpC,MAAM,IAAI,GAAG,IAAI,EAAE,MAAM,KAAK,KAAK,OAAO,IAAI,CAAC;IAE/C,IAAI,WAAW,GAAG,IAAI,CAAC,MAAM,GAAG,SAAS;QAAE,MAAM,EAAE,CAAC;IAEpD,IAAI,CAAC;QACH,EAAE,CAAC,cAAc,CAAC,IAAA,mBAAW,GAAE,EAAE,IAAI,CAAC,CAAC;QACvC,WAAW,IAAI,IAAI,CAAC,MAAM,CAAC;IAC7B,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,0BAA0B;QAC1B,OAAO,CAAC,KAAK,CAAC,iCAAiC,EAAE,GAAG,CAAC,CAAC;IACxD,CAAC;IAED,IAAI,KAAK,KAAK,OAAO;QAAE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;SAChD,IAAI,KAAK,KAAK,MAAM;QAAE,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;;QACnD,OAAO,CAAC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,CAAC,CAAC;AACnC,CAAC"}
@@ -1,60 +0,0 @@
1
- /**
2
- * Electron 主进程 lifecycle 入口
3
- * 单实例锁 → whenReady → createMainWindow → cleanup on quit
4
- * 启动时: 装 menu / tray / IPC handlers / 首启引导
5
- */
6
- import { app, BrowserWindow } from 'electron';
7
- import { log } from './logger';
8
- import { createMainWindow, focusMainWindow, getMainWindow } from './window';
9
- import { killWebServer } from './server';
10
- import { installAppMenu } from './menu';
11
- import { createTray, destroyTray } from './tray';
12
- import { registerCoreIpc } from './ipc';
13
- import { registerDialogIpc } from './dialogs';
14
- import { registerFirstRunIpc, maybeShowFirstRun } from './first-run';
15
- log('Bolloon Electron 启动');
16
- // 单实例锁
17
- const gotTheLock = app.requestSingleInstanceLock();
18
- if (!gotTheLock) {
19
- log('已有实例在运行,退出');
20
- app.quit();
21
- }
22
- app.on('second-instance', () => {
23
- focusMainWindow();
24
- });
25
- app.whenReady().then(async () => {
26
- log('Electron 准备好');
27
- registerCoreIpc();
28
- registerDialogIpc();
29
- registerFirstRunIpc();
30
- installAppMenu(getMainWindow);
31
- createTray(getMainWindow);
32
- await createMainWindow();
33
- // 首启引导 (在主窗口就绪后弹, 不阻塞 UI)
34
- const win = getMainWindow();
35
- if (win) {
36
- win.webContents.once('did-finish-load', () => {
37
- void maybeShowFirstRun(win);
38
- });
39
- }
40
- app.on('activate', async () => {
41
- // macOS: dock 图标被点击且没有窗口时, 重开
42
- if (BrowserWindow.getAllWindows().length === 0) {
43
- await createMainWindow();
44
- }
45
- });
46
- });
47
- app.on('window-all-closed', () => {
48
- log('所有窗口已关闭');
49
- destroyTray();
50
- killWebServer();
51
- if (process.platform !== 'darwin') {
52
- app.quit();
53
- }
54
- });
55
- app.on('before-quit', () => {
56
- log('应用即将退出');
57
- destroyTray();
58
- killWebServer();
59
- });
60
- log('主进程初始化完成');
@@ -1 +0,0 @@
1
- {"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/electron/main.ts"],"names":[],"mappings":";;AAAA;;;;GAIG;AACH,uCAA8C;AAC9C,qCAA+B;AAC/B,qCAA4E;AAC5E,qCAAyC;AACzC,iCAAwC;AACxC,iCAAiD;AACjD,+BAAwC;AACxC,uCAA8C;AAC9C,2CAAqE;AAErE,IAAA,YAAG,EAAC,qBAAqB,CAAC,CAAC;AAE3B,OAAO;AACP,MAAM,UAAU,GAAG,cAAG,CAAC,yBAAyB,EAAE,CAAC;AACnD,IAAI,CAAC,UAAU,EAAE,CAAC;IAChB,IAAA,YAAG,EAAC,YAAY,CAAC,CAAC;IAClB,cAAG,CAAC,IAAI,EAAE,CAAC;AACb,CAAC;AAED,cAAG,CAAC,EAAE,CAAC,iBAAiB,EAAE,GAAG,EAAE;IAC7B,IAAA,wBAAe,GAAE,CAAC;AACpB,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,SAAS,EAAE,CAAC,IAAI,CAAC,KAAK,IAAI,EAAE;IAC9B,IAAA,YAAG,EAAC,cAAc,CAAC,CAAC;IACpB,IAAA,qBAAe,GAAE,CAAC;IAClB,IAAA,2BAAiB,GAAE,CAAC;IACpB,IAAA,+BAAmB,GAAE,CAAC;IACtB,IAAA,qBAAc,EAAC,sBAAa,CAAC,CAAC;IAC9B,IAAA,iBAAU,EAAC,sBAAa,CAAC,CAAC;IAE1B,MAAM,IAAA,yBAAgB,GAAE,CAAC;IAEzB,0BAA0B;IAC1B,MAAM,GAAG,GAAG,IAAA,sBAAa,GAAE,CAAC;IAC5B,IAAI,GAAG,EAAE,CAAC;QACR,GAAG,CAAC,WAAW,CAAC,IAAI,CAAC,iBAAiB,EAAE,GAAG,EAAE;YAC3C,KAAK,IAAA,6BAAiB,EAAC,GAAG,CAAC,CAAC;QAC9B,CAAC,CAAC,CAAC;IACL,CAAC;IAED,cAAG,CAAC,EAAE,CAAC,UAAU,EAAE,KAAK,IAAI,EAAE;QAC5B,8BAA8B;QAC9B,IAAI,wBAAa,CAAC,aAAa,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC/C,MAAM,IAAA,yBAAgB,GAAE,CAAC;QAC3B,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,EAAE,CAAC,mBAAmB,EAAE,GAAG,EAAE;IAC/B,IAAA,YAAG,EAAC,SAAS,CAAC,CAAC;IACf,IAAA,kBAAW,GAAE,CAAC;IACd,IAAA,sBAAa,GAAE,CAAC;IAChB,IAAI,OAAO,CAAC,QAAQ,KAAK,QAAQ,EAAE,CAAC;QAClC,cAAG,CAAC,IAAI,EAAE,CAAC;IACb,CAAC;AACH,CAAC,CAAC,CAAC;AAEH,cAAG,CAAC,EAAE,CAAC,aAAa,EAAE,GAAG,EAAE;IACzB,IAAA,YAAG,EAAC,QAAQ,CAAC,CAAC;IACd,IAAA,kBAAW,GAAE,CAAC;IACd,IAAA,sBAAa,GAAE,CAAC;AAClB,CAAC,CAAC,CAAC;AAEH,IAAA,YAAG,EAAC,UAAU,CAAC,CAAC"}