@bolloon/bolloon-agent 0.3.12 → 0.3.14
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.
- package/dist/agents/pi-sdk-tools.js +147 -0
- package/dist/agents/pi-sdk.js +21 -0
- package/dist/agents/x402/x402Pay.js +281 -0
- package/dist/electron/config.js +14 -9
- package/dist/electron/dialogs.js +53 -16
- package/dist/electron/first-run.js +65 -24
- package/dist/electron/ipc.js +14 -10
- package/dist/electron/logger.js +44 -7
- package/dist/electron/main.js +45 -42
- package/dist/electron/menu.js +18 -13
- package/dist/electron/paths.js +54 -12
- package/dist/electron/server.js +57 -18
- package/dist/electron/tray.js +53 -15
- package/dist/electron/window.js +61 -22
- package/dist/electron-preload.js +19 -16
- package/dist/electron.js +4 -1
- package/dist/utils/auto-update.js +51 -12
- package/dist/web/client.js +129 -3
- package/dist/web/index.html +14 -0
- package/dist/web/server-storage.js +41 -9
- package/dist/web/server.js +71 -0
- package/dist/web/style.css +25 -0
- package/package.json +21 -2
package/dist/electron/tray.js
CHANGED
|
@@ -1,3 +1,40 @@
|
|
|
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.createTray = createTray;
|
|
37
|
+
exports.destroyTray = destroyTray;
|
|
1
38
|
/**
|
|
2
39
|
* 系统托盘 — Show / Hide / Quit
|
|
3
40
|
*
|
|
@@ -7,33 +44,33 @@
|
|
|
7
44
|
*
|
|
8
45
|
* 若 build 目录没有 tray 图标, 降级为不创建托盘 (主菜单和窗口关闭行为不变)
|
|
9
46
|
*/
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
47
|
+
const electron_1 = require("electron");
|
|
48
|
+
const path = __importStar(require("path"));
|
|
49
|
+
const fs = __importStar(require("fs"));
|
|
50
|
+
const paths_1 = require("./paths");
|
|
51
|
+
const logger_1 = require("./logger");
|
|
15
52
|
let trayInstance = null;
|
|
16
53
|
function loadTrayIcon() {
|
|
17
54
|
const isMac = process.platform === 'darwin';
|
|
18
55
|
const file = isMac ? 'trayTemplate.png' : 'tray.png';
|
|
19
|
-
const iconPath = path.join(buildResourcesDir(), file);
|
|
56
|
+
const iconPath = path.join((0, paths_1.buildResourcesDir)(), file);
|
|
20
57
|
if (!fs.existsSync(iconPath)) {
|
|
21
|
-
log(`托盘图标缺失: ${iconPath} (跳过托盘创建)`, 'warn');
|
|
58
|
+
(0, logger_1.log)(`托盘图标缺失: ${iconPath} (跳过托盘创建)`, 'warn');
|
|
22
59
|
return null;
|
|
23
60
|
}
|
|
24
|
-
const img = nativeImage.createFromPath(iconPath);
|
|
61
|
+
const img = electron_1.nativeImage.createFromPath(iconPath);
|
|
25
62
|
if (isMac)
|
|
26
63
|
img.setTemplateImage(true);
|
|
27
64
|
return img;
|
|
28
65
|
}
|
|
29
|
-
|
|
66
|
+
function createTray(getMainWindow) {
|
|
30
67
|
if (trayInstance)
|
|
31
68
|
return;
|
|
32
69
|
const icon = loadTrayIcon();
|
|
33
70
|
if (!icon)
|
|
34
71
|
return;
|
|
35
|
-
trayInstance = new Tray(icon);
|
|
36
|
-
trayInstance.setToolTip(`Bolloon Agent v${app.getVersion()}`);
|
|
72
|
+
trayInstance = new electron_1.Tray(icon);
|
|
73
|
+
trayInstance.setToolTip(`Bolloon Agent v${electron_1.app.getVersion()}`);
|
|
37
74
|
const toggle = () => {
|
|
38
75
|
const w = getMainWindow();
|
|
39
76
|
if (!w)
|
|
@@ -48,14 +85,14 @@ export function createTray(getMainWindow) {
|
|
|
48
85
|
w.focus();
|
|
49
86
|
}
|
|
50
87
|
};
|
|
51
|
-
const menu = Menu.buildFromTemplate([
|
|
88
|
+
const menu = electron_1.Menu.buildFromTemplate([
|
|
52
89
|
{ label: 'Show / Hide', click: () => toggle() },
|
|
53
90
|
{ type: 'separator' },
|
|
54
91
|
{
|
|
55
92
|
label: 'Quit',
|
|
56
93
|
click: () => {
|
|
57
|
-
log('托盘菜单 Quit');
|
|
58
|
-
app.quit();
|
|
94
|
+
(0, logger_1.log)('托盘菜单 Quit');
|
|
95
|
+
electron_1.app.quit();
|
|
59
96
|
},
|
|
60
97
|
},
|
|
61
98
|
]);
|
|
@@ -65,9 +102,10 @@ export function createTray(getMainWindow) {
|
|
|
65
102
|
trayInstance.on('click', () => toggle());
|
|
66
103
|
}
|
|
67
104
|
}
|
|
68
|
-
|
|
105
|
+
function destroyTray() {
|
|
69
106
|
if (trayInstance) {
|
|
70
107
|
trayInstance.destroy();
|
|
71
108
|
trayInstance = null;
|
|
72
109
|
}
|
|
73
110
|
}
|
|
111
|
+
//# sourceMappingURL=tray.js.map
|
package/dist/electron/window.js
CHANGED
|
@@ -1,25 +1,63 @@
|
|
|
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;
|
|
1
39
|
/**
|
|
2
40
|
* 主窗口工厂 — preload 路径解析 + dev/prod loadURL + 外部链接走系统浏览器
|
|
3
41
|
*/
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
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");
|
|
9
47
|
const g = globalThis;
|
|
10
48
|
const __basedir = g.__dirname
|
|
11
49
|
?? (g.__filename ? path.dirname(g.__filename) : process.cwd());
|
|
12
50
|
let mainWindow = null;
|
|
13
|
-
|
|
51
|
+
function getMainWindow() {
|
|
14
52
|
return mainWindow;
|
|
15
53
|
}
|
|
16
|
-
|
|
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,
|
|
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,
|
|
23
61
|
title: 'Bolloon Agent',
|
|
24
62
|
webPreferences: {
|
|
25
63
|
nodeIntegration: false,
|
|
@@ -29,40 +67,40 @@ export async function createMainWindow() {
|
|
|
29
67
|
},
|
|
30
68
|
show: false,
|
|
31
69
|
});
|
|
32
|
-
if (isDev) {
|
|
70
|
+
if (config_1.isDev) {
|
|
33
71
|
// dev:web 用 tsx 起 server, 端口固定 preferredPort, 不会 EADDRINUSE 自增
|
|
34
|
-
const port = preferredPort();
|
|
72
|
+
const port = (0, config_1.preferredPort)();
|
|
35
73
|
mainWindow.loadURL(`http://localhost:${port}`);
|
|
36
74
|
mainWindow.webContents.openDevTools();
|
|
37
75
|
}
|
|
38
76
|
else {
|
|
39
77
|
try {
|
|
40
|
-
log('启动内置 Web 服务器...');
|
|
41
|
-
const { port: actualPort } = await startWebServer(preferredPort());
|
|
78
|
+
(0, logger_1.log)('启动内置 Web 服务器...');
|
|
79
|
+
const { port: actualPort } = await (0, server_1.startWebServer)((0, config_1.preferredPort)());
|
|
42
80
|
mainWindow.loadURL(`http://localhost:${actualPort}`);
|
|
43
81
|
}
|
|
44
82
|
catch (err) {
|
|
45
|
-
log(`启动服务器失败: ${err.message}`, 'error');
|
|
83
|
+
(0, logger_1.log)(`启动服务器失败: ${err.message}`, 'error');
|
|
46
84
|
console.error('启动服务器失败:', err);
|
|
47
85
|
}
|
|
48
86
|
}
|
|
49
87
|
mainWindow.once('ready-to-show', () => {
|
|
50
88
|
mainWindow?.show();
|
|
51
|
-
log('窗口已显示');
|
|
89
|
+
(0, logger_1.log)('窗口已显示');
|
|
52
90
|
});
|
|
53
91
|
// 外部链接走系统浏览器, 不在 app 内开新窗口
|
|
54
92
|
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
|
55
93
|
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
56
|
-
shell.openExternal(url);
|
|
94
|
+
electron_1.shell.openExternal(url);
|
|
57
95
|
}
|
|
58
96
|
return { action: 'deny' };
|
|
59
97
|
});
|
|
60
98
|
mainWindow.on('closed', () => {
|
|
61
99
|
mainWindow = null;
|
|
62
100
|
});
|
|
63
|
-
log('窗口创建完成');
|
|
101
|
+
(0, logger_1.log)('窗口创建完成');
|
|
64
102
|
}
|
|
65
|
-
|
|
103
|
+
function focusMainWindow() {
|
|
66
104
|
if (!mainWindow)
|
|
67
105
|
return;
|
|
68
106
|
if (mainWindow.isMinimized())
|
|
@@ -70,3 +108,4 @@ export function focusMainWindow() {
|
|
|
70
108
|
mainWindow.show();
|
|
71
109
|
mainWindow.focus();
|
|
72
110
|
}
|
|
111
|
+
//# sourceMappingURL=window.js.map
|
package/dist/electron-preload.js
CHANGED
|
@@ -1,29 +1,32 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
3
|
/**
|
|
2
4
|
* Electron Preload 脚本
|
|
3
5
|
* 在渲染进程和主进程之间建立安全的通信桥梁
|
|
4
6
|
* contextIsolation: true, nodeIntegration: false — 只能通过这里暴露的 API 触达主进程
|
|
5
7
|
*/
|
|
6
|
-
|
|
7
|
-
contextBridge.exposeInMainWorld('electronAPI', {
|
|
8
|
+
const electron_1 = require("electron");
|
|
9
|
+
electron_1.contextBridge.exposeInMainWorld('electronAPI', {
|
|
8
10
|
// === 原有 (保留) ===
|
|
9
|
-
getVersion: () => ipcRenderer.invoke('get-version'),
|
|
10
|
-
getUserDataPath: () => ipcRenderer.invoke('get-user-data-path'),
|
|
11
|
-
openExternal: (url) => ipcRenderer.invoke('open-external', url),
|
|
11
|
+
getVersion: () => electron_1.ipcRenderer.invoke('get-version'),
|
|
12
|
+
getUserDataPath: () => electron_1.ipcRenderer.invoke('get-user-data-path'),
|
|
13
|
+
openExternal: (url) => electron_1.ipcRenderer.invoke('open-external', url),
|
|
12
14
|
// === 新增: 数据目录 ===
|
|
13
|
-
getDataPath: () => ipcRenderer.invoke('get-data-path'),
|
|
15
|
+
getDataPath: () => electron_1.ipcRenderer.invoke('get-data-path'),
|
|
14
16
|
// === 新增: 文件 dialog ===
|
|
15
|
-
openFile: (opts) => ipcRenderer.invoke('dialog:open-file', opts),
|
|
16
|
-
saveFile: (opts) => ipcRenderer.invoke('dialog:save-file', opts),
|
|
17
|
-
openDirectory: (opts) => ipcRenderer.invoke('dialog:open-directory', opts),
|
|
17
|
+
openFile: (opts) => electron_1.ipcRenderer.invoke('dialog:open-file', opts),
|
|
18
|
+
saveFile: (opts) => electron_1.ipcRenderer.invoke('dialog:save-file', opts),
|
|
19
|
+
openDirectory: (opts) => electron_1.ipcRenderer.invoke('dialog:open-directory', opts),
|
|
18
20
|
// === 新增: 文件系统 (限大小, 主进程守卫) ===
|
|
19
|
-
readTextFile: (opts) => ipcRenderer.invoke('fs:read-text-file', opts),
|
|
20
|
-
writeTextFile: (opts) => ipcRenderer.invoke('fs:write-text-file', opts),
|
|
21
|
-
pathExists: (opts) => ipcRenderer.invoke('fs:path-exists', opts),
|
|
21
|
+
readTextFile: (opts) => electron_1.ipcRenderer.invoke('fs:read-text-file', opts),
|
|
22
|
+
writeTextFile: (opts) => electron_1.ipcRenderer.invoke('fs:write-text-file', opts),
|
|
23
|
+
pathExists: (opts) => electron_1.ipcRenderer.invoke('fs:path-exists', opts),
|
|
22
24
|
// === 新增: 首启引导 ===
|
|
23
|
-
getFirstRunSeen: () => ipcRenderer.invoke('first-run:seen'),
|
|
24
|
-
markFirstRunSeen: () => ipcRenderer.invoke('first-run:mark-seen'),
|
|
25
|
-
getDataPathSync: () => ipcRenderer.invoke('first-run:data-dir'),
|
|
26
|
-
getLogsPathSync: () => ipcRenderer.invoke('first-run:logs-dir'),
|
|
25
|
+
getFirstRunSeen: () => electron_1.ipcRenderer.invoke('first-run:seen'),
|
|
26
|
+
markFirstRunSeen: () => electron_1.ipcRenderer.invoke('first-run:mark-seen'),
|
|
27
|
+
getDataPathSync: () => electron_1.ipcRenderer.invoke('first-run:data-dir'),
|
|
28
|
+
getLogsPathSync: () => electron_1.ipcRenderer.invoke('first-run:logs-dir'),
|
|
27
29
|
// === 元数据 ===
|
|
28
30
|
platform: process.platform,
|
|
29
31
|
});
|
|
32
|
+
//# sourceMappingURL=electron-preload.js.map
|
package/dist/electron.js
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
1
3
|
/**
|
|
2
4
|
* Electron 入口 shim — 真正逻辑在 src/electron/main.ts
|
|
3
5
|
* (保留 src/electron.ts 平铺入口, 不动 package.json 的 dist/electron.js 解析)
|
|
4
6
|
*/
|
|
5
|
-
|
|
7
|
+
require("./electron/main");
|
|
8
|
+
//# sourceMappingURL=electron.js.map
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
"use strict";
|
|
1
2
|
/**
|
|
2
3
|
* npm 自动更新检查器
|
|
3
4
|
*
|
|
@@ -13,11 +14,48 @@
|
|
|
13
14
|
* 开发态下若 cwd 的 package.json 就是本包则回退到 cwd,不受任意工作目录影响。
|
|
14
15
|
* - 检查频率受节流缓存约束(默认 24h 一次),不会每次启动都打 npm。
|
|
15
16
|
*/
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
17
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
18
|
+
if (k2 === undefined) k2 = k;
|
|
19
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
20
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
21
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
22
|
+
}
|
|
23
|
+
Object.defineProperty(o, k2, desc);
|
|
24
|
+
}) : (function(o, m, k, k2) {
|
|
25
|
+
if (k2 === undefined) k2 = k;
|
|
26
|
+
o[k2] = m[k];
|
|
27
|
+
}));
|
|
28
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
29
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
30
|
+
}) : function(o, v) {
|
|
31
|
+
o["default"] = v;
|
|
32
|
+
});
|
|
33
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
34
|
+
var ownKeys = function(o) {
|
|
35
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
36
|
+
var ar = [];
|
|
37
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
38
|
+
return ar;
|
|
39
|
+
};
|
|
40
|
+
return ownKeys(o);
|
|
41
|
+
};
|
|
42
|
+
return function (mod) {
|
|
43
|
+
if (mod && mod.__esModule) return mod;
|
|
44
|
+
var result = {};
|
|
45
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
46
|
+
__setModuleDefault(result, mod);
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
})();
|
|
50
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
51
|
+
exports.checkAndUpdate = checkAndUpdate;
|
|
52
|
+
exports.checkForUpdates = checkForUpdates;
|
|
53
|
+
exports.performUpdate = performUpdate;
|
|
54
|
+
const child_process_1 = require("child_process");
|
|
55
|
+
const fs = __importStar(require("fs"));
|
|
56
|
+
const path = __importStar(require("path"));
|
|
57
|
+
const https = __importStar(require("https"));
|
|
58
|
+
const http = __importStar(require("http"));
|
|
21
59
|
// ANSI 颜色
|
|
22
60
|
const RESET = '\x1b[0m';
|
|
23
61
|
const BOLD = '\x1b[1m';
|
|
@@ -75,7 +113,7 @@ function getGlobalBolloonDir() {
|
|
|
75
113
|
const candidates = [];
|
|
76
114
|
// 1. npm root -g(最可靠)
|
|
77
115
|
try {
|
|
78
|
-
const npmRoot = execSync('npm root -g', { encoding: 'utf-8', timeout: 8000 }).trim();
|
|
116
|
+
const npmRoot = (0, child_process_1.execSync)('npm root -g', { encoding: 'utf-8', timeout: 8000 }).trim();
|
|
79
117
|
if (npmRoot)
|
|
80
118
|
candidates.push(path.join(npmRoot, '@bolloon', 'bolloon-agent'));
|
|
81
119
|
}
|
|
@@ -84,7 +122,7 @@ function getGlobalBolloonDir() {
|
|
|
84
122
|
}
|
|
85
123
|
// 2. npm prefix -g
|
|
86
124
|
try {
|
|
87
|
-
const npmPrefix = execSync('npm prefix -g', { encoding: 'utf-8', timeout: 8000 }).trim();
|
|
125
|
+
const npmPrefix = (0, child_process_1.execSync)('npm prefix -g', { encoding: 'utf-8', timeout: 8000 }).trim();
|
|
88
126
|
if (npmPrefix)
|
|
89
127
|
candidates.push(path.join(npmPrefix, 'lib', 'node_modules', '@bolloon', 'bolloon-agent'));
|
|
90
128
|
}
|
|
@@ -242,7 +280,7 @@ async function checkBolloonUpdates() {
|
|
|
242
280
|
*/
|
|
243
281
|
function checkNpmOutdated() {
|
|
244
282
|
try {
|
|
245
|
-
const output = execSync('npm outdated --json', {
|
|
283
|
+
const output = (0, child_process_1.execSync)('npm outdated --json', {
|
|
246
284
|
encoding: 'utf-8',
|
|
247
285
|
timeout: 30000,
|
|
248
286
|
maxBuffer: 10 * 1024 * 1024,
|
|
@@ -306,7 +344,7 @@ async function updatePackagesWithVersion(packagesWithVersion) {
|
|
|
306
344
|
const args = ['npm', 'install', '-g', ...packagesWithVersion];
|
|
307
345
|
notify(`\n${CYAN}📦 正在更新包...${RESET}\n`, RESET);
|
|
308
346
|
try {
|
|
309
|
-
execSync(args.join(' '), {
|
|
347
|
+
(0, child_process_1.execSync)(args.join(' '), {
|
|
310
348
|
encoding: 'utf-8',
|
|
311
349
|
timeout: 300000,
|
|
312
350
|
stdio: 'inherit',
|
|
@@ -424,7 +462,7 @@ function resolveAutoUpdatePolicy() {
|
|
|
424
462
|
* 例如 Electron 用 app.relaunch(),Node 用 detached 重新 spawn)。
|
|
425
463
|
* 若未提供或 autoRestart=false,则仅提示用户手动重启。
|
|
426
464
|
*/
|
|
427
|
-
|
|
465
|
+
async function checkAndUpdate(opts = {}) {
|
|
428
466
|
const policy = resolveAutoUpdatePolicy();
|
|
429
467
|
if (policy.blocked) {
|
|
430
468
|
return { hasUpdate: false, info: null, updated: false, message: '跳过更新检查(已显式禁用)' };
|
|
@@ -528,13 +566,13 @@ export async function checkAndUpdate(opts = {}) {
|
|
|
528
566
|
/**
|
|
529
567
|
* 仅检查更新,不自动安装
|
|
530
568
|
*/
|
|
531
|
-
|
|
569
|
+
async function checkForUpdates() {
|
|
532
570
|
return await checkBolloonUpdates();
|
|
533
571
|
}
|
|
534
572
|
/**
|
|
535
573
|
* 手动触发更新
|
|
536
574
|
*/
|
|
537
|
-
|
|
575
|
+
async function performUpdate(packages) {
|
|
538
576
|
return await updatePackages(packages);
|
|
539
577
|
}
|
|
540
578
|
// CLI 入口
|
|
@@ -557,3 +595,4 @@ if (process.argv[1]?.includes('auto-update')) {
|
|
|
557
595
|
}
|
|
558
596
|
})();
|
|
559
597
|
}
|
|
598
|
+
//# sourceMappingURL=auto-update.js.map
|
package/dist/web/client.js
CHANGED
|
@@ -4346,9 +4346,11 @@ ${data.error || "channel not found"}`, "error");
|
|
|
4346
4346
|
<span style="font-size:13px;">${strangerIcon}</span>
|
|
4347
4347
|
<span style="flex:1;font-size:12px;font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;" title="${escapeHtml2(peer.publicKey)}">${escapeHtml2(peer.name)}</span>
|
|
4348
4348
|
<span style="font-size:9px;color:var(--text-muted);">${peerChannels.length > 0 ? `${peerChannels.length} ch \xB7 ` : ""}${lastConn}</span>
|
|
4349
|
-
|
|
4350
|
-
|
|
4351
|
-
|
|
4349
|
+
<button class="peer-edit-btn" title="\u7F16\u8F91\u597D\u53CB\u540D\u5B57/\u5907\u6CE8"
|
|
4350
|
+
style="background:transparent;border:1px solid var(--border);color:var(--text);cursor:pointer;width:22px;height:22px;border-radius:4px;font-size:12px;line-height:1;padding:0;display:flex;align-items:center;justify-content:center;flex:0 0 auto;">\u270F\uFE0F</button>
|
|
4351
|
+
<button class="peer-share-btn" title="\u5206\u4EAB channel \u7ED9 ${escapeHtml2(peer.name)}"
|
|
4352
|
+
style="background:transparent;border:1px solid var(--border);color:var(--text);cursor:pointer;width:22px;height:22px;border-radius:4px;font-size:12px;line-height:1;padding:0;display:flex;align-items:center;justify-content:center;flex:0 0 auto;">\u{1F4E4}</button>
|
|
4353
|
+
</div>
|
|
4352
4354
|
<div class="remote-peer-channels" style="margin-top:4px;margin-left:8px;">
|
|
4353
4355
|
${peerChannels.length === 0 ? '<div style="font-size:10px;color:var(--text-muted);padding:2px 4px;">(\u5BF9\u65B9\u8FD8\u6CA1\u5206\u4EAB channel \u7ED9\u4F60)</div>' : peerChannels.map((c) => `
|
|
4354
4356
|
<div class="remote-channel-row" data-peer-id="${escapeHtml2(peer.publicKey)}" data-channel-id="${escapeHtml2(c.id)}"
|
|
@@ -4389,9 +4391,22 @@ ${data.error || "channel not found"}`, "error");
|
|
|
4389
4391
|
});
|
|
4390
4392
|
}
|
|
4391
4393
|
});
|
|
4394
|
+
list.querySelectorAll(".remote-peer-header").forEach((row) => {
|
|
4395
|
+
const editBtn = row.querySelector(".peer-edit-btn");
|
|
4396
|
+
if (editBtn) {
|
|
4397
|
+
editBtn.addEventListener("click", (e) => {
|
|
4398
|
+
e.stopPropagation();
|
|
4399
|
+
const peerName = row.dataset.peerName;
|
|
4400
|
+
const peerPk = row.dataset.peerPk;
|
|
4401
|
+
openEditPeerModal(peerName, peerPk);
|
|
4402
|
+
});
|
|
4403
|
+
}
|
|
4404
|
+
});
|
|
4392
4405
|
list.querySelectorAll(".remote-peer-header").forEach((row) => {
|
|
4393
4406
|
row.addEventListener("dblclick", (e) => {
|
|
4394
4407
|
if (e.target.closest(".peer-caret-btn")) return;
|
|
4408
|
+
if (e.target.closest(".peer-edit-btn")) return;
|
|
4409
|
+
if (e.target.closest(".peer-share-btn")) return;
|
|
4395
4410
|
const peerName = row.dataset.peerName;
|
|
4396
4411
|
const peerPk = row.dataset.peerPk;
|
|
4397
4412
|
openEditPeerModal(peerName, peerPk);
|
|
@@ -5032,6 +5047,44 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5032
5047
|
var walletListEl = document.getElementById("wallet-list");
|
|
5033
5048
|
var walletModalPendingSecret = null;
|
|
5034
5049
|
var walletModalPendingMnemonic = null;
|
|
5050
|
+
var walletStoreKey = document.getElementById("wallet-store-key");
|
|
5051
|
+
var walletAutopayEnabled = document.getElementById("wallet-autopay-enabled");
|
|
5052
|
+
var walletStoreKeyBtn = document.getElementById("wallet-store-key-btn");
|
|
5053
|
+
var walletEncryptGroup = document.getElementById("wallet-encrypt-group");
|
|
5054
|
+
var walletAutopayGroup = document.getElementById("wallet-autopay-group");
|
|
5055
|
+
async function encryptPrivateKeyAESGCM(privateKeyHex, did) {
|
|
5056
|
+
const keyMaterial = await crypto.subtle.importKey(
|
|
5057
|
+
"raw",
|
|
5058
|
+
new TextEncoder().encode(did),
|
|
5059
|
+
"PBKDF2",
|
|
5060
|
+
false,
|
|
5061
|
+
["deriveBits", "deriveKey"]
|
|
5062
|
+
);
|
|
5063
|
+
const key = await crypto.subtle.deriveKey(
|
|
5064
|
+
{
|
|
5065
|
+
name: "PBKDF2",
|
|
5066
|
+
salt: new TextEncoder().encode("bolloon-wallet-aes256"),
|
|
5067
|
+
iterations: 1e5,
|
|
5068
|
+
hash: "SHA-256"
|
|
5069
|
+
},
|
|
5070
|
+
keyMaterial,
|
|
5071
|
+
{ name: "AES-GCM", length: 256 },
|
|
5072
|
+
false,
|
|
5073
|
+
["encrypt"]
|
|
5074
|
+
);
|
|
5075
|
+
const iv = crypto.getRandomValues(new Uint8Array(12));
|
|
5076
|
+
const encoded = new TextEncoder().encode(privateKeyHex);
|
|
5077
|
+
const encrypted = await crypto.subtle.encrypt(
|
|
5078
|
+
{ name: "AES-GCM", iv },
|
|
5079
|
+
key,
|
|
5080
|
+
encoded
|
|
5081
|
+
);
|
|
5082
|
+
const combined = new Uint8Array(encrypted);
|
|
5083
|
+
const ciphertext = combined;
|
|
5084
|
+
const ivHex = btoa(String.fromCharCode(...iv));
|
|
5085
|
+
const encryptedHex = btoa(String.fromCharCode(...ciphertext));
|
|
5086
|
+
return { encryptedPrivateKey: encryptedHex, encryptedPrivateKeyIv: ivHex };
|
|
5087
|
+
}
|
|
5035
5088
|
if (walletModalClose) {
|
|
5036
5089
|
walletModalClose.addEventListener("click", closeWalletModal);
|
|
5037
5090
|
}
|
|
@@ -5092,6 +5145,9 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5092
5145
|
walletModalPendingMnemonic = null;
|
|
5093
5146
|
walletNewInfo.style.display = "block";
|
|
5094
5147
|
walletNewInfo.innerHTML = "\u2705 \u7ED1\u5B9A\u6210\u529F<br><strong>\u5730\u5740:</strong> <code>" + escapeHtml2(updated.walletAddress) + "</code><br><strong>\u7B7E\u540D DID:</strong> <code>" + escapeHtml2(did) + '</code><br><small style="color:#9c9;">\u670D\u52A1\u7AEF\u5DF2\u7528 recoverMessage \u6821\u9A8C\u7B7E\u540D, \u8BC1\u660E\u4F60\u6301\u6709\u8BE5\u94B1\u5305\u79C1\u94A5\u3002</small>';
|
|
5148
|
+
if (walletEncryptGroup) walletEncryptGroup.style.display = "block";
|
|
5149
|
+
if (walletAutopayGroup) walletAutopayGroup.style.display = "block";
|
|
5150
|
+
if (walletStoreKeyBtn) walletStoreKeyBtn.style.display = "inline-block";
|
|
5095
5151
|
} catch (err) {
|
|
5096
5152
|
alert("\u7ED1\u5B9A\u5931\u8D25: " + err.message);
|
|
5097
5153
|
}
|
|
@@ -5117,17 +5173,81 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5117
5173
|
walletBindAddress.value = "";
|
|
5118
5174
|
renderChannels();
|
|
5119
5175
|
renderWalletList();
|
|
5176
|
+
if (walletEncryptGroup) walletEncryptGroup.style.display = "none";
|
|
5177
|
+
if (walletAutopayGroup) walletAutopayGroup.style.display = "none";
|
|
5178
|
+
if (walletStoreKeyBtn) walletStoreKeyBtn.style.display = "none";
|
|
5120
5179
|
} catch (err) {
|
|
5121
5180
|
alert("\u89E3\u7ED1\u5931\u8D25: " + err.message);
|
|
5122
5181
|
}
|
|
5123
5182
|
});
|
|
5124
5183
|
}
|
|
5184
|
+
if (walletStoreKeyBtn) {
|
|
5185
|
+
walletStoreKeyBtn.addEventListener("click", async () => {
|
|
5186
|
+
if (!currentChannelId) {
|
|
5187
|
+
alert("\u8BF7\u5148\u9009\u62E9\u4E00\u4E2A\u667A\u80FD\u4F53");
|
|
5188
|
+
return;
|
|
5189
|
+
}
|
|
5190
|
+
if (!walletModalPendingSecret) {
|
|
5191
|
+
alert("\u672A\u68C0\u6D4B\u5230\u4E34\u65F6\u79C1\u94A5, \u8BF7\u5148\u751F\u6210\u6216\u5BFC\u5165\u94B1\u5305");
|
|
5192
|
+
return;
|
|
5193
|
+
}
|
|
5194
|
+
const ch = channels.find((c) => c.id === currentChannelId);
|
|
5195
|
+
const did = ch?.did || "";
|
|
5196
|
+
if (!did || did === "undefined" || did === "null") {
|
|
5197
|
+
alert("\u5F53\u524D\u667A\u80FD\u4F53\u8FD8\u6CA1\u6709\u751F\u6210 DID");
|
|
5198
|
+
return;
|
|
5199
|
+
}
|
|
5200
|
+
try {
|
|
5201
|
+
walletStoreKeyBtn.textContent = "\u52A0\u5BC6\u4E2D...";
|
|
5202
|
+
walletStoreKeyBtn.disabled = true;
|
|
5203
|
+
const { encryptedPrivateKey, encryptedPrivateKeyIv } = await encryptPrivateKeyAESGCM(walletModalPendingSecret, did);
|
|
5204
|
+
const autoPay = walletAutopayEnabled ? walletAutopayEnabled.checked : true;
|
|
5205
|
+
const res = await fetch(`/channels/${currentChannelId}/encrypted-key`, {
|
|
5206
|
+
method: "POST",
|
|
5207
|
+
headers: { "Content-Type": "application/json" },
|
|
5208
|
+
body: JSON.stringify({ encryptedPrivateKey, encryptedPrivateKeyIv, autoPayEnabled: autoPay })
|
|
5209
|
+
});
|
|
5210
|
+
if (!res.ok) {
|
|
5211
|
+
const err = await res.json().catch(() => ({}));
|
|
5212
|
+
throw new Error(err.error || "store encrypted key failed");
|
|
5213
|
+
}
|
|
5214
|
+
const updated = await res.json();
|
|
5215
|
+
const idx = channels.findIndex((c) => c.id === currentChannelId);
|
|
5216
|
+
if (idx >= 0) channels[idx] = updated;
|
|
5217
|
+
renderChannels();
|
|
5218
|
+
renderWalletList();
|
|
5219
|
+
walletNewInfo.style.display = "block";
|
|
5220
|
+
walletNewInfo.innerHTML = '\u2705 \u52A0\u5BC6\u79C1\u94A5\u5DF2\u5B89\u5168\u5B58\u50A8\u5728\u670D\u52A1\u7AEF<br><small style="color:#9c9;">\u79C1\u94A5\u7528 AES-256-GCM \u52A0\u5BC6, \u4EC5\u5F53\u524D\u667A\u80FD\u4F53\u8FDB\u7A0B\u53EF\u89E3\u5BC6\u7528\u4E8E\u81EA\u52A8\u652F\u4ED8\u3002</small>';
|
|
5221
|
+
if (walletStoreKeyBtn) {
|
|
5222
|
+
walletStoreKeyBtn.textContent = "\u5DF2\u5B58\u50A8 \u2713";
|
|
5223
|
+
walletStoreKeyBtn.disabled = true;
|
|
5224
|
+
}
|
|
5225
|
+
} catch (err) {
|
|
5226
|
+
alert("\u5B58\u50A8\u52A0\u5BC6\u79C1\u94A5\u5931\u8D25: " + err.message);
|
|
5227
|
+
if (walletStoreKeyBtn) {
|
|
5228
|
+
walletStoreKeyBtn.textContent = "\u5B58\u50A8\u52A0\u5BC6\u79C1\u94A5\u5230\u670D\u52A1\u7AEF";
|
|
5229
|
+
walletStoreKeyBtn.disabled = false;
|
|
5230
|
+
}
|
|
5231
|
+
}
|
|
5232
|
+
});
|
|
5233
|
+
}
|
|
5125
5234
|
function openWalletModal() {
|
|
5126
5235
|
if (walletModal) {
|
|
5127
5236
|
walletModal.classList.add("active");
|
|
5128
5237
|
if (currentChannelId && walletBindAddress && channels.find((c) => c.id === currentChannelId)) {
|
|
5129
5238
|
const ch = channels.find((c) => c.id === currentChannelId);
|
|
5130
5239
|
walletBindAddress.value = ch?.walletAddress || "";
|
|
5240
|
+
const hasWallet = !!ch?.walletAddress;
|
|
5241
|
+
if (walletEncryptGroup) walletEncryptGroup.style.display = hasWallet ? "block" : "none";
|
|
5242
|
+
if (walletAutopayGroup) walletAutopayGroup.style.display = hasWallet ? "block" : "none";
|
|
5243
|
+
if (walletStoreKeyBtn) {
|
|
5244
|
+
const hasEncryptedKey = !!ch?.encryptedPrivateKey;
|
|
5245
|
+
walletStoreKeyBtn.style.display = hasWallet && !hasEncryptedKey ? "inline-block" : "none";
|
|
5246
|
+
walletStoreKeyBtn.textContent = hasEncryptedKey ? "\u5DF2\u5B58\u50A8 \u2713" : "\u5B58\u50A8\u52A0\u5BC6\u79C1\u94A5\u5230\u670D\u52A1\u7AEF";
|
|
5247
|
+
walletStoreKeyBtn.disabled = hasEncryptedKey;
|
|
5248
|
+
}
|
|
5249
|
+
if (walletAutopayEnabled) walletAutopayEnabled.checked = ch?.autoPayEnabled ?? true;
|
|
5250
|
+
if (walletStoreKey) walletStoreKey.checked = true;
|
|
5131
5251
|
}
|
|
5132
5252
|
renderWalletList();
|
|
5133
5253
|
}
|
|
@@ -5148,11 +5268,17 @@ ${data.error || "channel not found"}`, "error");
|
|
|
5148
5268
|
const chain = detectChain(ch.walletAddress);
|
|
5149
5269
|
const row = document.createElement("div");
|
|
5150
5270
|
row.className = "wallet-row" + (isActive ? " is-active" : "");
|
|
5271
|
+
const hasEncryptedKey = !!ch.encryptedPrivateKey;
|
|
5272
|
+
const autoPay = ch.autoPayEnabled;
|
|
5273
|
+
const badges = [];
|
|
5274
|
+
if (autoPay) badges.push('<span class="wallet-badge badge-autopay" title="\u81EA\u52A8\u652F\u4ED8\u5DF2\u542F\u7528">auto</span>');
|
|
5275
|
+
else if (hasEncryptedKey) badges.push('<span class="wallet-badge badge-stored" title="\u79C1\u94A5\u5DF2\u52A0\u5BC6\u5B58\u50A8">key</span>');
|
|
5151
5276
|
row.innerHTML = `
|
|
5152
5277
|
<span class="wallet-chain">${escapeHtml2(chain)}</span>
|
|
5153
5278
|
<div class="wallet-info">
|
|
5154
5279
|
<span class="wallet-agent" title="${escapeHtml2(ch.name || "")}">${escapeHtml2(ch.name || "(\u672A\u547D\u540D)")}</span>
|
|
5155
5280
|
<span class="wallet-address" title="${escapeHtml2(ch.walletAddress)}">${escapeHtml2(ch.walletAddress)}</span>
|
|
5281
|
+
${badges.length ? '<span class="wallet-badges">' + badges.join("") + "</span>" : ""}
|
|
5156
5282
|
</div>
|
|
5157
5283
|
<div class="wallet-actions">
|
|
5158
5284
|
<button class="wallet-mini-btn" data-action="copy" data-addr="${escapeHtml2(ch.walletAddress)}" title="\u590D\u5236\u5730\u5740">
|
package/dist/web/index.html
CHANGED
|
@@ -344,9 +344,23 @@
|
|
|
344
344
|
</label>
|
|
345
345
|
</div>
|
|
346
346
|
<div id="wallet-new-info" class="form-info" style="display:none;"></div>
|
|
347
|
+
<div class="form-group" id="wallet-encrypt-group" style="display:none;">
|
|
348
|
+
<label class="checkbox-label">
|
|
349
|
+
<input type="checkbox" id="wallet-store-key" checked>
|
|
350
|
+
<span>加密存储私钥到服务端 (用于 x402 自动支付)</span>
|
|
351
|
+
</label>
|
|
352
|
+
<small class="form-hint">私钥用 DID 派生密钥 AES-256-GCM 加密后上传, 仅当前智能体进程可解密。</small>
|
|
353
|
+
</div>
|
|
354
|
+
<div class="form-group" id="wallet-autopay-group" style="display:none;">
|
|
355
|
+
<label class="checkbox-label">
|
|
356
|
+
<input type="checkbox" id="wallet-autopay-enabled" checked>
|
|
357
|
+
<span>自动支付 (智能体遇到 402 Payment Required 时自动用绑定钱包支付)</span>
|
|
358
|
+
</label>
|
|
359
|
+
</div>
|
|
347
360
|
<div class="btn-group">
|
|
348
361
|
<button id="wallet-bind-btn" class="btn-primary">绑定到当前智能体</button>
|
|
349
362
|
<button id="wallet-unbind-btn" class="btn-secondary">解绑当前智能体</button>
|
|
363
|
+
<button id="wallet-store-key-btn" class="btn-secondary" style="display:none;">存储加密私钥到服务端</button>
|
|
350
364
|
</div>
|
|
351
365
|
|
|
352
366
|
<h3 style="margin-top:24px;font-size:14px;font-weight:600;">所有已绑定钱包</h3>
|