@bolloon/bolloon-agent 0.3.36 → 0.3.38

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 (53) hide show
  1. package/dist/agents/pi-sdk-tools.js +107 -0
  2. package/dist/agents/pi-sdk.js +20 -2
  3. package/dist/bootstrap/context-collector.js +5 -1
  4. package/dist/cli/ink-app.js +46 -8
  5. package/dist/cli/loading-tui.js +7 -5
  6. package/dist/cli-entry.js +1 -1
  7. package/dist/electron/config.js +9 -14
  8. package/dist/electron/dialogs.js +16 -53
  9. package/dist/electron/first-run.js +24 -65
  10. package/dist/electron/ipc.js +10 -14
  11. package/dist/electron/logger.js +7 -44
  12. package/dist/electron/main.js +42 -45
  13. package/dist/electron/menu.js +13 -18
  14. package/dist/electron/paths.js +12 -54
  15. package/dist/electron/server.js +18 -57
  16. package/dist/electron/tray.js +15 -53
  17. package/dist/electron/window.js +22 -61
  18. package/dist/electron-build/electron/config.js +21 -0
  19. package/dist/electron-build/electron/config.js.map +1 -0
  20. package/dist/electron-build/electron/dialogs.js +108 -0
  21. package/dist/electron-build/electron/dialogs.js.map +1 -0
  22. package/dist/electron-build/electron/first-run.js +170 -0
  23. package/dist/electron-build/electron/first-run.js.map +1 -0
  24. package/dist/electron-build/electron/ipc.js +20 -0
  25. package/dist/electron-build/electron/ipc.js.map +1 -0
  26. package/dist/electron-build/electron/logger.js +114 -0
  27. package/dist/electron-build/electron/logger.js.map +1 -0
  28. package/dist/electron-build/electron/main.js +79 -0
  29. package/dist/electron-build/electron/main.js.map +1 -0
  30. package/dist/electron-build/electron/menu.js +145 -0
  31. package/dist/electron-build/electron/menu.js.map +1 -0
  32. package/dist/electron-build/electron/paths.js +75 -0
  33. package/dist/electron-build/electron/paths.js.map +1 -0
  34. package/dist/electron-build/electron/server.js +119 -0
  35. package/dist/electron-build/electron/server.js.map +1 -0
  36. package/dist/electron-build/electron/tray.js +111 -0
  37. package/dist/electron-build/electron/tray.js.map +1 -0
  38. package/dist/electron-build/electron/window.js +111 -0
  39. package/dist/electron-build/electron/window.js.map +1 -0
  40. package/dist/electron-build/electron-preload.js +32 -0
  41. package/dist/electron-build/electron-preload.js.map +1 -0
  42. package/dist/electron-build/electron.js +8 -0
  43. package/dist/electron-build/electron.js.map +1 -0
  44. package/dist/electron-build/utils/auto-update.js +606 -0
  45. package/dist/electron-build/utils/auto-update.js.map +1 -0
  46. package/dist/electron-preload.js +16 -19
  47. package/dist/electron.js +1 -4
  48. package/dist/index.js +134 -31
  49. package/dist/llm/config-store.js +18 -2
  50. package/dist/llm/pi-ai.js +29 -11
  51. package/dist/security/tool-gate.js +2 -0
  52. package/dist/utils/auto-update.js +19 -51
  53. package/package.json +6 -5
@@ -1,63 +1,25 @@
1
- "use strict";
2
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
- if (k2 === undefined) k2 = k;
4
- var desc = Object.getOwnPropertyDescriptor(m, k);
5
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
- desc = { enumerable: true, get: function() { return m[k]; } };
7
- }
8
- Object.defineProperty(o, k2, desc);
9
- }) : (function(o, m, k, k2) {
10
- if (k2 === undefined) k2 = k;
11
- o[k2] = m[k];
12
- }));
13
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
- Object.defineProperty(o, "default", { enumerable: true, value: v });
15
- }) : function(o, v) {
16
- o["default"] = v;
17
- });
18
- var __importStar = (this && this.__importStar) || (function () {
19
- var ownKeys = function(o) {
20
- ownKeys = Object.getOwnPropertyNames || function (o) {
21
- var ar = [];
22
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
- return ar;
24
- };
25
- return ownKeys(o);
26
- };
27
- return function (mod) {
28
- if (mod && mod.__esModule) return mod;
29
- var result = {};
30
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
- __setModuleDefault(result, mod);
32
- return result;
33
- };
34
- })();
35
- Object.defineProperty(exports, "__esModule", { value: true });
36
- exports.getMainWindow = getMainWindow;
37
- exports.createMainWindow = createMainWindow;
38
- exports.focusMainWindow = focusMainWindow;
39
1
  /**
40
2
  * 主窗口工厂 — preload 路径解析 + dev/prod loadURL + 外部链接走系统浏览器
41
3
  */
42
- const electron_1 = require("electron");
43
- const path = __importStar(require("path"));
44
- const logger_1 = require("./logger");
45
- const config_1 = require("./config");
46
- const server_1 = require("./server");
4
+ import { BrowserWindow, shell } from 'electron';
5
+ import * as path from 'path';
6
+ import { log } from './logger';
7
+ import { isDev, MAIN_WINDOW_DEFAULT, MAIN_WINDOW_MIN, preferredPort } from './config';
8
+ import { startWebServer } from './server';
47
9
  const g = globalThis;
48
10
  const __basedir = g.__dirname
49
11
  ?? (g.__filename ? path.dirname(g.__filename) : process.cwd());
50
12
  let mainWindow = null;
51
- function getMainWindow() {
13
+ export function getMainWindow() {
52
14
  return mainWindow;
53
15
  }
54
- async function createMainWindow() {
55
- (0, logger_1.log)('创建主窗口...');
56
- mainWindow = new electron_1.BrowserWindow({
57
- width: config_1.MAIN_WINDOW_DEFAULT.width,
58
- height: config_1.MAIN_WINDOW_DEFAULT.height,
59
- minWidth: config_1.MAIN_WINDOW_MIN.width,
60
- minHeight: config_1.MAIN_WINDOW_MIN.height,
16
+ export async function createMainWindow() {
17
+ log('创建主窗口...');
18
+ mainWindow = new BrowserWindow({
19
+ width: MAIN_WINDOW_DEFAULT.width,
20
+ height: MAIN_WINDOW_DEFAULT.height,
21
+ minWidth: MAIN_WINDOW_MIN.width,
22
+ minHeight: MAIN_WINDOW_MIN.height,
61
23
  title: 'Bolloon Agent',
62
24
  webPreferences: {
63
25
  nodeIntegration: false,
@@ -67,40 +29,40 @@ async function createMainWindow() {
67
29
  },
68
30
  show: false,
69
31
  });
70
- if (config_1.isDev) {
32
+ if (isDev) {
71
33
  // dev:web 用 tsx 起 server, 端口固定 preferredPort, 不会 EADDRINUSE 自增
72
- const port = (0, config_1.preferredPort)();
34
+ const port = preferredPort();
73
35
  mainWindow.loadURL(`http://localhost:${port}`);
74
36
  mainWindow.webContents.openDevTools();
75
37
  }
76
38
  else {
77
39
  try {
78
- (0, logger_1.log)('启动内置 Web 服务器...');
79
- const { port: actualPort } = await (0, server_1.startWebServer)((0, config_1.preferredPort)());
40
+ log('启动内置 Web 服务器...');
41
+ const { port: actualPort } = await startWebServer(preferredPort());
80
42
  mainWindow.loadURL(`http://localhost:${actualPort}`);
81
43
  }
82
44
  catch (err) {
83
- (0, logger_1.log)(`启动服务器失败: ${err.message}`, 'error');
45
+ log(`启动服务器失败: ${err.message}`, 'error');
84
46
  console.error('启动服务器失败:', err);
85
47
  }
86
48
  }
87
49
  mainWindow.once('ready-to-show', () => {
88
50
  mainWindow?.show();
89
- (0, logger_1.log)('窗口已显示');
51
+ log('窗口已显示');
90
52
  });
91
53
  // 外部链接走系统浏览器, 不在 app 内开新窗口
92
54
  mainWindow.webContents.setWindowOpenHandler(({ url }) => {
93
55
  if (url.startsWith('http://') || url.startsWith('https://')) {
94
- electron_1.shell.openExternal(url);
56
+ shell.openExternal(url);
95
57
  }
96
58
  return { action: 'deny' };
97
59
  });
98
60
  mainWindow.on('closed', () => {
99
61
  mainWindow = null;
100
62
  });
101
- (0, logger_1.log)('窗口创建完成');
63
+ log('窗口创建完成');
102
64
  }
103
- function focusMainWindow() {
65
+ export function focusMainWindow() {
104
66
  if (!mainWindow)
105
67
  return;
106
68
  if (mainWindow.isMinimized())
@@ -108,4 +70,3 @@ function focusMainWindow() {
108
70
  mainWindow.show();
109
71
  mainWindow.focus();
110
72
  }
111
- //# sourceMappingURL=window.js.map
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.isDev = exports.MAIN_WINDOW_MIN = exports.MAIN_WINDOW_DEFAULT = exports.WEB_SERVER_STARTUP_TIMEOUT_MS = exports.DEFAULT_HOST = exports.DEFAULT_PORT = void 0;
4
+ exports.preferredPort = preferredPort;
5
+ /**
6
+ * 常量配置 (env 解析在这里集中, 不散在 main 流程)
7
+ */
8
+ const electron_1 = require("electron");
9
+ exports.DEFAULT_PORT = 54188;
10
+ /** Hard-pin to loopback; LAN exposure must be explicit. */
11
+ exports.DEFAULT_HOST = '127.0.0.1';
12
+ exports.WEB_SERVER_STARTUP_TIMEOUT_MS = 15_000;
13
+ exports.MAIN_WINDOW_DEFAULT = { width: 1200, height: 800 };
14
+ exports.MAIN_WINDOW_MIN = { width: 800, height: 600 };
15
+ function preferredPort() {
16
+ const raw = process.env.ELECTRON_PORT || process.env.PORT;
17
+ const n = parseInt(raw || '', 10);
18
+ return Number.isFinite(n) && n > 0 && n < 65536 ? n : exports.DEFAULT_PORT;
19
+ }
20
+ exports.isDev = process.env.NODE_ENV === 'development' || !electron_1.app.isPackaged;
21
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.registerDialogIpc = registerDialogIpc;
37
+ /**
38
+ * 文件 dialog 桥 (open / save / dir) + 安全的 fs 桥 (read / write / exists)
39
+ *
40
+ * 5MB read 上限保护 — 渲染进程直接 fs.readFile 没法做限制, 走主进程就有界
41
+ * 所有 handler 解析 event.sender 拿到 window, 让 dialog 模态在该窗口上
42
+ */
43
+ const electron_1 = require("electron");
44
+ const fs = __importStar(require("fs"));
45
+ const path = __importStar(require("path"));
46
+ const logger_1 = require("./logger");
47
+ const MAX_READ_BYTES = 5 * 1024 * 1024; // 5MB
48
+ function windowFor(event) {
49
+ return electron_1.BrowserWindow.fromWebContents(event.sender);
50
+ }
51
+ function resolveSafe(target) {
52
+ // 不去硬限制路径 — user 给 renderer 暴露 fs 已经信任了, 这里只 normalize
53
+ return path.resolve(target);
54
+ }
55
+ function registerDialogIpc() {
56
+ electron_1.ipcMain.handle('dialog:open-file', async (event, opts = {}) => {
57
+ const win = windowFor(event);
58
+ const result = await electron_1.dialog.showOpenDialog(win, {
59
+ title: opts.title,
60
+ defaultPath: opts.defaultPath,
61
+ filters: opts.filters,
62
+ properties: opts.properties ?? ['openFile'],
63
+ });
64
+ return { canceled: result.canceled, filePaths: result.filePaths };
65
+ });
66
+ electron_1.ipcMain.handle('dialog:save-file', async (event, opts = {}) => {
67
+ const win = windowFor(event);
68
+ const result = await electron_1.dialog.showSaveDialog(win, {
69
+ title: opts.title,
70
+ defaultPath: opts.defaultPath,
71
+ filters: opts.filters,
72
+ });
73
+ return { canceled: result.canceled, filePath: result.filePath };
74
+ });
75
+ electron_1.ipcMain.handle('dialog:open-directory', async (event, opts = {}) => {
76
+ const win = windowFor(event);
77
+ const result = await electron_1.dialog.showOpenDialog(win, {
78
+ title: opts.title,
79
+ defaultPath: opts.defaultPath,
80
+ properties: ['openDirectory', 'createDirectory'],
81
+ });
82
+ return { canceled: result.canceled, filePaths: result.filePaths };
83
+ });
84
+ electron_1.ipcMain.handle('fs:read-text-file', async (_event, opts) => {
85
+ const target = resolveSafe(opts.path);
86
+ const stat = fs.statSync(target);
87
+ if (stat.size > MAX_READ_BYTES) {
88
+ throw new Error(`文件过大: ${stat.size} > ${MAX_READ_BYTES} bytes`);
89
+ }
90
+ return fs.readFileSync(target, { encoding: opts.encoding ?? 'utf8' });
91
+ });
92
+ electron_1.ipcMain.handle('fs:write-text-file', async (_event, opts) => {
93
+ const target = resolveSafe(opts.path);
94
+ fs.mkdirSync(path.dirname(target), { recursive: true });
95
+ fs.writeFileSync(target, opts.content, { encoding: opts.encoding ?? 'utf8' });
96
+ });
97
+ electron_1.ipcMain.handle('fs:path-exists', async (_event, opts) => {
98
+ try {
99
+ fs.accessSync(resolveSafe(opts.path));
100
+ return true;
101
+ }
102
+ catch {
103
+ return false;
104
+ }
105
+ });
106
+ (0, logger_1.log)('dialog + fs IPC handlers registered');
107
+ }
108
+ //# sourceMappingURL=dialogs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dialogs.js","sourceRoot":"","sources":["../../../src/electron/dialogs.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,170 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.hasSeenFirstRun = hasSeenFirstRun;
37
+ exports.markFirstRunSeen = markFirstRunSeen;
38
+ exports.showFirstRunOverlay = showFirstRunOverlay;
39
+ exports.registerFirstRunIpc = registerFirstRunIpc;
40
+ exports.maybeShowFirstRun = maybeShowFirstRun;
41
+ /**
42
+ * 首启检测 + 引导浮层
43
+ *
44
+ * 标记文件写在 userData (不是 ~/.bolloon/), 卸载 app 自然清掉
45
+ * 引导窗是父主窗的 modal, frame=false, 透明背景; 关闭时标记写入
46
+ */
47
+ const electron_1 = require("electron");
48
+ const fs = __importStar(require("fs"));
49
+ const path = __importStar(require("path"));
50
+ const paths_1 = require("./paths");
51
+ const logger_1 = require("./logger");
52
+ const OVERLAY_HTML = `
53
+ <!DOCTYPE html>
54
+ <html>
55
+ <head>
56
+ <meta charset="utf-8" />
57
+ <style>
58
+ :root { color-scheme: light dark; }
59
+ body {
60
+ font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
61
+ margin: 0; padding: 32px 28px;
62
+ background: rgba(245,245,247,0.97);
63
+ color: #1d1d1f;
64
+ height: 100vh; box-sizing: border-box;
65
+ }
66
+ @media (prefers-color-scheme: dark) {
67
+ body { background: rgba(28,28,30,0.97); color: #f5f5f7; }
68
+ }
69
+ h1 { font-size: 18px; margin: 0 0 14px; font-weight: 600; }
70
+ p { font-size: 13px; line-height: 1.55; margin: 8px 0; }
71
+ code {
72
+ font-family: ui-monospace, "SF Mono", Menlo, monospace;
73
+ font-size: 12px; padding: 1px 5px;
74
+ background: rgba(0,0,0,0.06); border-radius: 3px;
75
+ }
76
+ @media (prefers-color-scheme: dark) {
77
+ code { background: rgba(255,255,255,0.08); }
78
+ }
79
+ .btn {
80
+ display: inline-block; margin-top: 18px; padding: 8px 18px;
81
+ background: #007aff; color: #fff; border: none; border-radius: 6px;
82
+ font-size: 13px; font-weight: 500; cursor: pointer;
83
+ }
84
+ .btn:hover { background: #0066d6; }
85
+ ul { padding-left: 20px; }
86
+ li { font-size: 13px; line-height: 1.7; }
87
+ </style>
88
+ </head>
89
+ <body>
90
+ <h1>欢迎使用 Bolloon Agent</h1>
91
+ <p>你的数据存放在本地, 不上传:</p>
92
+ <ul>
93
+ <li>配置 / 频道 / P2P 密钥: <code id="data"></code></li>
94
+ <li>运行日志: <code id="logs"></code></li>
95
+ </ul>
96
+ <p>所有数据在卸载后仍保留 — 想清理就手动删除 ~/.bolloon/。</p>
97
+ <button class="btn" id="ok">知道了</button>
98
+ <script>
99
+ const ok = document.getElementById('ok');
100
+ ok.addEventListener('click', () => window.electronAPI.markFirstRunSeen());
101
+ document.getElementById('data').textContent = window.electronAPI.getDataPathSync?.() || '';
102
+ document.getElementById('logs').textContent = window.electronAPI.getLogsPathSync?.() || '';
103
+ </script>
104
+ </body>
105
+ </html>
106
+ `;
107
+ function hasSeenFirstRun() {
108
+ try {
109
+ return fs.existsSync((0, paths_1.firstRunFlagPath)());
110
+ }
111
+ catch {
112
+ return false;
113
+ }
114
+ }
115
+ function markFirstRunSeen() {
116
+ try {
117
+ fs.mkdirSync(path.dirname((0, paths_1.firstRunFlagPath)()), { recursive: true });
118
+ fs.writeFileSync((0, paths_1.firstRunFlagPath)(), new Date().toISOString());
119
+ }
120
+ catch (err) {
121
+ (0, logger_1.log)(`写入首启标记失败: ${err.message}`, 'warn');
122
+ }
123
+ }
124
+ function showFirstRunOverlay(parent) {
125
+ return new Promise((resolve) => {
126
+ const overlay = new electron_1.BrowserWindow({
127
+ parent,
128
+ modal: true,
129
+ frame: false,
130
+ transparent: true,
131
+ width: 520,
132
+ height: 360,
133
+ resizable: false,
134
+ movable: false,
135
+ minimizable: false,
136
+ maximizable: false,
137
+ title: 'Welcome',
138
+ });
139
+ const dataUrl = 'data:text/html;charset=utf-8,' + encodeURIComponent(OVERLAY_HTML);
140
+ overlay.loadURL(dataUrl);
141
+ // 一次性的 IPC handler, 关闭后清掉避免累积
142
+ const handler = () => {
143
+ markFirstRunSeen();
144
+ overlay.close();
145
+ };
146
+ electron_1.ipcMain.once('first-run:ack', handler);
147
+ overlay.on('closed', () => {
148
+ electron_1.ipcMain.removeListener('first-run:ack', handler);
149
+ resolve();
150
+ });
151
+ });
152
+ }
153
+ /** 注册 IPC handlers (给 preload 桥用) */
154
+ function registerFirstRunIpc() {
155
+ electron_1.ipcMain.handle('first-run:seen', () => hasSeenFirstRun());
156
+ electron_1.ipcMain.handle('first-run:mark-seen', () => { markFirstRunSeen(); });
157
+ // 同步值 (不用 ipcRenderer.invoke 的 await) — 用 exposeInMainWorld 的 sync getter 更顺
158
+ electron_1.ipcMain.handle('first-run:data-dir', () => (0, paths_1.dataDir)());
159
+ electron_1.ipcMain.handle('first-run:logs-dir', () => (0, paths_1.logsDir)());
160
+ (0, logger_1.log)('first-run IPC handlers registered');
161
+ }
162
+ /** 包装 — 决定要不要弹 overlay */
163
+ async function maybeShowFirstRun(parent) {
164
+ if (hasSeenFirstRun())
165
+ return;
166
+ (0, logger_1.log)('首启 — 弹出引导');
167
+ await showFirstRunOverlay(parent);
168
+ electron_1.app.addRecentDocument((0, paths_1.firstRunFlagPath)()); // 跟踪最近文档, 让 user 知道有这文件
169
+ }
170
+ //# sourceMappingURL=first-run.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"first-run.js","sourceRoot":"","sources":["../../../src/electron/first-run.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerCoreIpc = registerCoreIpc;
4
+ /**
5
+ * IPC handler 集中注册 — version / userData path / open-external (legacy 3 个)
6
+ * dialog/fs 的注册在 dialogs.ts; updater 的注册在 updater.ts
7
+ */
8
+ const electron_1 = require("electron");
9
+ const paths_1 = require("./paths");
10
+ const logger_1 = require("./logger");
11
+ function registerCoreIpc() {
12
+ electron_1.ipcMain.handle('get-version', () => electron_1.app.getVersion());
13
+ electron_1.ipcMain.handle('get-user-data-path', () => (0, paths_1.userDataDir)());
14
+ electron_1.ipcMain.handle('get-data-path', () => (0, paths_1.dataDir)()); // 跟 userData 分开, 渲染层要用
15
+ electron_1.ipcMain.handle('open-external', async (_event, url) => {
16
+ await electron_1.shell.openExternal(url);
17
+ });
18
+ (0, logger_1.log)('core IPC handlers registered');
19
+ }
20
+ //# sourceMappingURL=ipc.js.map
@@ -0,0 +1 @@
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"}
@@ -0,0 +1,114 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.log = log;
37
+ /**
38
+ * 简单 logger: 写日志到 <userData>/logs/bolloon.log, size-based 轮转
39
+ * (5MB 上限, 保留 .1 .2 .3 共 3 个备份 → ~20MB 上限)
40
+ *
41
+ * 同步写是因为 Electron 主进程日志量小, 同步 append 简单可靠, 不丢日志.
42
+ * 量大的会话级 jsonl 走自己路径 (lifecycle-hooks 等), 跟本 logger 无关.
43
+ */
44
+ const fs = __importStar(require("fs"));
45
+ const paths_1 = require("./paths");
46
+ const MAX_BYTES = 5 * 1024 * 1024;
47
+ const MAX_BACKUPS = 3; // 保留 bolloon.log.1 .2 .3
48
+ let currentSize = 0;
49
+ let initialized = false;
50
+ function ensureLogFile() {
51
+ if (initialized)
52
+ return;
53
+ initialized = true;
54
+ try {
55
+ fs.mkdirSync((0, paths_1.logsDir)(), { recursive: true });
56
+ try {
57
+ currentSize = fs.statSync((0, paths_1.mainLogPath)()).size;
58
+ }
59
+ catch {
60
+ currentSize = 0;
61
+ }
62
+ }
63
+ catch (err) {
64
+ // 失败也无所谓, log() 内部会 swallow
65
+ currentSize = 0;
66
+ console.error('[logger] ensureLogFile failed:', err);
67
+ }
68
+ }
69
+ function rotate() {
70
+ const logPath = (0, paths_1.mainLogPath)();
71
+ for (let i = MAX_BACKUPS; i >= 1; i--) {
72
+ const src = `${logPath}.${i}`;
73
+ const dst = `${logPath}.${i + 1}`;
74
+ if (i === MAX_BACKUPS) {
75
+ try {
76
+ fs.unlinkSync(src);
77
+ }
78
+ catch { /* missing ok */ }
79
+ }
80
+ else {
81
+ try {
82
+ fs.renameSync(src, dst);
83
+ }
84
+ catch { /* missing ok */ }
85
+ }
86
+ }
87
+ try {
88
+ fs.renameSync(logPath, `${logPath}.1`);
89
+ }
90
+ catch { /* missing ok */ }
91
+ currentSize = 0;
92
+ }
93
+ function log(message, level = 'info') {
94
+ ensureLogFile();
95
+ const ts = new Date().toISOString();
96
+ const line = `[${ts}] [${level}] ${message}\n`;
97
+ if (currentSize + line.length > MAX_BYTES)
98
+ rotate();
99
+ try {
100
+ fs.appendFileSync((0, paths_1.mainLogPath)(), line);
101
+ currentSize += line.length;
102
+ }
103
+ catch (err) {
104
+ // 写不进就 console, 不要再递归 log
105
+ console.error('[logger] appendFileSync failed:', err);
106
+ }
107
+ if (level === 'error')
108
+ console.error(line.trimEnd());
109
+ else if (level === 'warn')
110
+ console.warn(line.trimEnd());
111
+ else
112
+ console.log(line.trimEnd());
113
+ }
114
+ //# sourceMappingURL=logger.js.map
@@ -0,0 +1 @@
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"}