@bolloon/bolloon-agent 0.3.9 → 0.3.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.
- package/dist/agents/pi-sdk.js +26 -5
- package/dist/bootstrap/exhaust-scrubber.js +233 -0
- package/dist/bootstrap/memory-compressor.js +11 -0
- package/dist/cli-entry.js +94 -0
- package/dist/electron/config.js +9 -14
- package/dist/electron/dialogs.js +16 -53
- package/dist/electron/first-run.js +24 -65
- package/dist/electron/ipc.js +10 -14
- package/dist/electron/logger.js +7 -44
- package/dist/electron/main.js +42 -45
- package/dist/electron/menu.js +13 -18
- package/dist/electron/paths.js +12 -54
- package/dist/electron/server.js +18 -57
- package/dist/electron/tray.js +15 -53
- package/dist/electron/window.js +22 -61
- package/dist/electron-preload.js +16 -19
- package/dist/electron.js +1 -4
- package/dist/index.js +63 -3
- package/dist/pi-ecosystem-judgment/injection-gate.js +85 -1
- package/dist/utils/auto-update.js +12 -51
- package/dist/web/client.js +4138 -4639
- package/dist/web/components/p2p/P2PModal.js +188 -0
- package/dist/web/components/p2p/index.js +276 -234
- package/dist/web/components/p2p/p2p-modal.js +664 -0
- package/dist/web/components/p2p/p2p-tools.js +248 -0
- package/dist/web/index.html +47 -23
- package/dist/web/routes-judgments.js +8 -2
- package/dist/web/server.js +11 -0
- package/dist/web/style.css +30 -0
- package/dist/web/ui/message-renderer.js +535 -396
- package/dist/web/ui/step-timeline.js +371 -272
- package/package.json +2 -2
package/dist/electron/server.js
CHANGED
|
@@ -1,51 +1,13 @@
|
|
|
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.getWebServerProcess = getWebServerProcess;
|
|
37
|
-
exports.killWebServer = killWebServer;
|
|
38
|
-
exports.startWebServer = startWebServer;
|
|
39
1
|
/**
|
|
40
2
|
* Spawns dist/web/server.js as a child Node process (via Electron's
|
|
41
3
|
* ELECTRON_RUN_AS_NODE=1) and parses BOLLOON_PORT=NNNN to learn the
|
|
42
4
|
* actually-bound port (which may have drifted from the preferred port
|
|
43
5
|
* due to EADDRINUSE auto-bump).
|
|
44
6
|
*/
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
7
|
+
import { spawn } from 'child_process';
|
|
8
|
+
import * as path from 'path';
|
|
9
|
+
import { log } from './logger';
|
|
10
|
+
import { WEB_SERVER_STARTUP_TIMEOUT_MS, DEFAULT_HOST } from './config';
|
|
49
11
|
// Resolve to the directory holding this file. See src/electron/window.ts for the rationale;
|
|
50
12
|
// this avoids the same `import.meta` / `__dirname` redeclaration conflicts that broke
|
|
51
13
|
// the electron tsconfig when esnext module mode was set.
|
|
@@ -53,30 +15,30 @@ const g = globalThis;
|
|
|
53
15
|
const __basedir = g.__dirname
|
|
54
16
|
?? (g.__filename ? path.dirname(g.__filename) : process.cwd());
|
|
55
17
|
let webServerProcess = null;
|
|
56
|
-
function getWebServerProcess() {
|
|
18
|
+
export function getWebServerProcess() {
|
|
57
19
|
return webServerProcess;
|
|
58
20
|
}
|
|
59
|
-
function killWebServer() {
|
|
21
|
+
export function killWebServer() {
|
|
60
22
|
if (webServerProcess && !webServerProcess.killed) {
|
|
61
|
-
|
|
23
|
+
log('终止 Web 服务器进程');
|
|
62
24
|
webServerProcess.kill();
|
|
63
25
|
}
|
|
64
26
|
webServerProcess = null;
|
|
65
27
|
}
|
|
66
|
-
function startWebServer(preferredPort) {
|
|
28
|
+
export function startWebServer(preferredPort) {
|
|
67
29
|
return new Promise((resolve, reject) => {
|
|
68
30
|
const serverScript = path.join(__basedir, '..', 'web', 'server.js');
|
|
69
|
-
|
|
31
|
+
log(`启动 Web 服务器进程: ${serverScript}`);
|
|
70
32
|
// ELECTRON_RUN_AS_NODE=1 — packaged 时 process.execPath 是 Electron 二进制,
|
|
71
33
|
// 没这行 require() 会失败. Dev 模式 (electron dist/electron.js) 同样情况.
|
|
72
|
-
webServerProcess =
|
|
34
|
+
webServerProcess = spawn(process.execPath, [serverScript], {
|
|
73
35
|
env: {
|
|
74
36
|
...process.env,
|
|
75
37
|
ELECTRON_RUN_AS_NODE: '1',
|
|
76
38
|
NODE_ENV: 'production',
|
|
77
39
|
PORT: String(preferredPort),
|
|
78
40
|
ELECTRON_PORT: String(preferredPort),
|
|
79
|
-
BOLLOON_HOST:
|
|
41
|
+
BOLLOON_HOST: DEFAULT_HOST,
|
|
80
42
|
},
|
|
81
43
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
82
44
|
});
|
|
@@ -88,32 +50,31 @@ function startWebServer(preferredPort) {
|
|
|
88
50
|
const m = stdoutBuf.match(/^BOLLOON_PORT=(\d+)/m);
|
|
89
51
|
if (m) {
|
|
90
52
|
const actualPort = parseInt(m[1], 10);
|
|
91
|
-
|
|
53
|
+
log(`Web 服务器就绪: 实际端口=${actualPort} (preferred=${preferredPort})`);
|
|
92
54
|
resolve({ port: actualPort });
|
|
93
55
|
}
|
|
94
56
|
});
|
|
95
57
|
webServerProcess.stderr?.on('data', (data) => {
|
|
96
58
|
stderrData += data.toString();
|
|
97
59
|
process.stderr.write(`[WebServer ERR] ${data}`);
|
|
98
|
-
|
|
60
|
+
log(`[WebServer stderr] ${data.toString().trim()}`, 'warn');
|
|
99
61
|
});
|
|
100
62
|
webServerProcess.on('error', (err) => {
|
|
101
|
-
|
|
63
|
+
log(`Web 服务器启动失败: ${err.message}`, 'error');
|
|
102
64
|
reject(err);
|
|
103
65
|
});
|
|
104
66
|
webServerProcess.on('exit', (code, signal) => {
|
|
105
|
-
|
|
67
|
+
log(`Web 服务器退出: code=${code} signal=${signal}`);
|
|
106
68
|
if (code !== 0 && code !== null) {
|
|
107
|
-
|
|
69
|
+
log(`Web 服务器 stderr: ${stderrData.slice(0, 500)}`, 'error');
|
|
108
70
|
}
|
|
109
71
|
webServerProcess = null;
|
|
110
72
|
});
|
|
111
73
|
setTimeout(() => {
|
|
112
74
|
if (webServerProcess && !webServerProcess.killed) {
|
|
113
|
-
|
|
75
|
+
log(`Web 服务器启动超时 (${WEB_SERVER_STARTUP_TIMEOUT_MS}ms)`, 'error');
|
|
114
76
|
reject(new Error('Web server startup timeout'));
|
|
115
77
|
}
|
|
116
|
-
},
|
|
78
|
+
}, WEB_SERVER_STARTUP_TIMEOUT_MS);
|
|
117
79
|
});
|
|
118
80
|
}
|
|
119
|
-
//# sourceMappingURL=server.js.map
|
package/dist/electron/tray.js
CHANGED
|
@@ -1,40 +1,3 @@
|
|
|
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;
|
|
38
1
|
/**
|
|
39
2
|
* 系统托盘 — Show / Hide / Quit
|
|
40
3
|
*
|
|
@@ -44,33 +7,33 @@ exports.destroyTray = destroyTray;
|
|
|
44
7
|
*
|
|
45
8
|
* 若 build 目录没有 tray 图标, 降级为不创建托盘 (主菜单和窗口关闭行为不变)
|
|
46
9
|
*/
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
10
|
+
import { Tray, Menu, nativeImage, app } from 'electron';
|
|
11
|
+
import * as path from 'path';
|
|
12
|
+
import * as fs from 'fs';
|
|
13
|
+
import { buildResourcesDir } from './paths';
|
|
14
|
+
import { log } from './logger';
|
|
52
15
|
let trayInstance = null;
|
|
53
16
|
function loadTrayIcon() {
|
|
54
17
|
const isMac = process.platform === 'darwin';
|
|
55
18
|
const file = isMac ? 'trayTemplate.png' : 'tray.png';
|
|
56
|
-
const iconPath = path.join(
|
|
19
|
+
const iconPath = path.join(buildResourcesDir(), file);
|
|
57
20
|
if (!fs.existsSync(iconPath)) {
|
|
58
|
-
|
|
21
|
+
log(`托盘图标缺失: ${iconPath} (跳过托盘创建)`, 'warn');
|
|
59
22
|
return null;
|
|
60
23
|
}
|
|
61
|
-
const img =
|
|
24
|
+
const img = nativeImage.createFromPath(iconPath);
|
|
62
25
|
if (isMac)
|
|
63
26
|
img.setTemplateImage(true);
|
|
64
27
|
return img;
|
|
65
28
|
}
|
|
66
|
-
function createTray(getMainWindow) {
|
|
29
|
+
export function createTray(getMainWindow) {
|
|
67
30
|
if (trayInstance)
|
|
68
31
|
return;
|
|
69
32
|
const icon = loadTrayIcon();
|
|
70
33
|
if (!icon)
|
|
71
34
|
return;
|
|
72
|
-
trayInstance = new
|
|
73
|
-
trayInstance.setToolTip(`Bolloon Agent v${
|
|
35
|
+
trayInstance = new Tray(icon);
|
|
36
|
+
trayInstance.setToolTip(`Bolloon Agent v${app.getVersion()}`);
|
|
74
37
|
const toggle = () => {
|
|
75
38
|
const w = getMainWindow();
|
|
76
39
|
if (!w)
|
|
@@ -85,14 +48,14 @@ function createTray(getMainWindow) {
|
|
|
85
48
|
w.focus();
|
|
86
49
|
}
|
|
87
50
|
};
|
|
88
|
-
const menu =
|
|
51
|
+
const menu = Menu.buildFromTemplate([
|
|
89
52
|
{ label: 'Show / Hide', click: () => toggle() },
|
|
90
53
|
{ type: 'separator' },
|
|
91
54
|
{
|
|
92
55
|
label: 'Quit',
|
|
93
56
|
click: () => {
|
|
94
|
-
|
|
95
|
-
|
|
57
|
+
log('托盘菜单 Quit');
|
|
58
|
+
app.quit();
|
|
96
59
|
},
|
|
97
60
|
},
|
|
98
61
|
]);
|
|
@@ -102,10 +65,9 @@ function createTray(getMainWindow) {
|
|
|
102
65
|
trayInstance.on('click', () => toggle());
|
|
103
66
|
}
|
|
104
67
|
}
|
|
105
|
-
function destroyTray() {
|
|
68
|
+
export function destroyTray() {
|
|
106
69
|
if (trayInstance) {
|
|
107
70
|
trayInstance.destroy();
|
|
108
71
|
trayInstance = null;
|
|
109
72
|
}
|
|
110
73
|
}
|
|
111
|
-
//# sourceMappingURL=tray.js.map
|
package/dist/electron/window.js
CHANGED
|
@@ -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
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
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
|
-
|
|
56
|
-
mainWindow = new
|
|
57
|
-
width:
|
|
58
|
-
height:
|
|
59
|
-
minWidth:
|
|
60
|
-
minHeight:
|
|
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 (
|
|
32
|
+
if (isDev) {
|
|
71
33
|
// dev:web 用 tsx 起 server, 端口固定 preferredPort, 不会 EADDRINUSE 自增
|
|
72
|
-
const port =
|
|
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
|
-
|
|
79
|
-
const { port: actualPort } = await
|
|
40
|
+
log('启动内置 Web 服务器...');
|
|
41
|
+
const { port: actualPort } = await startWebServer(preferredPort());
|
|
80
42
|
mainWindow.loadURL(`http://localhost:${actualPort}`);
|
|
81
43
|
}
|
|
82
44
|
catch (err) {
|
|
83
|
-
|
|
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
|
-
|
|
51
|
+
log('窗口已显示');
|
|
90
52
|
});
|
|
91
53
|
// 外部链接走系统浏览器, 不在 app 内开新窗口
|
|
92
54
|
mainWindow.webContents.setWindowOpenHandler(({ url }) => {
|
|
93
55
|
if (url.startsWith('http://') || url.startsWith('https://')) {
|
|
94
|
-
|
|
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
|
-
|
|
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
|
package/dist/electron-preload.js
CHANGED
|
@@ -1,32 +1,29 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
1
|
/**
|
|
4
2
|
* Electron Preload 脚本
|
|
5
3
|
* 在渲染进程和主进程之间建立安全的通信桥梁
|
|
6
4
|
* contextIsolation: true, nodeIntegration: false — 只能通过这里暴露的 API 触达主进程
|
|
7
5
|
*/
|
|
8
|
-
|
|
9
|
-
|
|
6
|
+
import { contextBridge, ipcRenderer } from 'electron';
|
|
7
|
+
contextBridge.exposeInMainWorld('electronAPI', {
|
|
10
8
|
// === 原有 (保留) ===
|
|
11
|
-
getVersion: () =>
|
|
12
|
-
getUserDataPath: () =>
|
|
13
|
-
openExternal: (url) =>
|
|
9
|
+
getVersion: () => ipcRenderer.invoke('get-version'),
|
|
10
|
+
getUserDataPath: () => ipcRenderer.invoke('get-user-data-path'),
|
|
11
|
+
openExternal: (url) => ipcRenderer.invoke('open-external', url),
|
|
14
12
|
// === 新增: 数据目录 ===
|
|
15
|
-
getDataPath: () =>
|
|
13
|
+
getDataPath: () => ipcRenderer.invoke('get-data-path'),
|
|
16
14
|
// === 新增: 文件 dialog ===
|
|
17
|
-
openFile: (opts) =>
|
|
18
|
-
saveFile: (opts) =>
|
|
19
|
-
openDirectory: (opts) =>
|
|
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),
|
|
20
18
|
// === 新增: 文件系统 (限大小, 主进程守卫) ===
|
|
21
|
-
readTextFile: (opts) =>
|
|
22
|
-
writeTextFile: (opts) =>
|
|
23
|
-
pathExists: (opts) =>
|
|
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),
|
|
24
22
|
// === 新增: 首启引导 ===
|
|
25
|
-
getFirstRunSeen: () =>
|
|
26
|
-
markFirstRunSeen: () =>
|
|
27
|
-
getDataPathSync: () =>
|
|
28
|
-
getLogsPathSync: () =>
|
|
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'),
|
|
29
27
|
// === 元数据 ===
|
|
30
28
|
platform: process.platform,
|
|
31
29
|
});
|
|
32
|
-
//# sourceMappingURL=electron-preload.js.map
|
package/dist/electron.js
CHANGED
|
@@ -1,8 +1,5 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
1
|
/**
|
|
4
2
|
* Electron 入口 shim — 真正逻辑在 src/electron/main.ts
|
|
5
3
|
* (保留 src/electron.ts 平铺入口, 不动 package.json 的 dist/electron.js 解析)
|
|
6
4
|
*/
|
|
7
|
-
|
|
8
|
-
//# sourceMappingURL=electron.js.map
|
|
5
|
+
import './electron/main';
|
package/dist/index.js
CHANGED
|
@@ -553,7 +553,7 @@ const AVAILABLE_TOOLS = [
|
|
|
553
553
|
{ name: 'update_check', description: '检查 npm 包更新', example: '--update-check' },
|
|
554
554
|
{ name: 'update_now', description: '立即更新到最新版本', example: '--update-now [package]' },
|
|
555
555
|
];
|
|
556
|
-
async function runToolCommand(tool, args, outputJson, comm) {
|
|
556
|
+
async function runToolCommand(tool, args, outputJson, comm, model) {
|
|
557
557
|
const a = await getAgent();
|
|
558
558
|
const startTime = Date.now();
|
|
559
559
|
let response;
|
|
@@ -1028,6 +1028,60 @@ async function runToolCommand(tool, args, outputJson, comm) {
|
|
|
1028
1028
|
}
|
|
1029
1029
|
break;
|
|
1030
1030
|
}
|
|
1031
|
+
case 'engine': {
|
|
1032
|
+
const { delegateToEngine } = await import('./external-engines/delegate.js');
|
|
1033
|
+
const { prompt } = (() => {
|
|
1034
|
+
const p = process.argv.slice(2).reduce((acc, arg, idx, arr) => {
|
|
1035
|
+
if (arg === '-e' || arg === '--engine') {
|
|
1036
|
+
acc.skip = idx + 2;
|
|
1037
|
+
return acc;
|
|
1038
|
+
}
|
|
1039
|
+
if (idx < acc.skip)
|
|
1040
|
+
return acc;
|
|
1041
|
+
if (arg.startsWith('--model') || arg.startsWith('-m')) {
|
|
1042
|
+
acc.skip = idx + 2;
|
|
1043
|
+
return acc;
|
|
1044
|
+
}
|
|
1045
|
+
if (arg.startsWith('-') || idx < acc.skip)
|
|
1046
|
+
return acc;
|
|
1047
|
+
acc.parts.push(arg);
|
|
1048
|
+
return acc;
|
|
1049
|
+
}, { skip: 0, parts: [] });
|
|
1050
|
+
return { prompt: p.parts.join(' ') };
|
|
1051
|
+
})();
|
|
1052
|
+
const engineId = args[0];
|
|
1053
|
+
if (!engineId) {
|
|
1054
|
+
response = '用法: --engine <engine-id> [--model <model>] <prompt>\n可用引擎: opencode, codex, claude-code, hermes';
|
|
1055
|
+
error = response;
|
|
1056
|
+
break;
|
|
1057
|
+
}
|
|
1058
|
+
if (!prompt) {
|
|
1059
|
+
response = '错误: 缺少 prompt 文本';
|
|
1060
|
+
error = response;
|
|
1061
|
+
break;
|
|
1062
|
+
}
|
|
1063
|
+
if (outputJson) {
|
|
1064
|
+
process.stdout.write(JSON.stringify({ tool: 'engine', id: engineId, model, prompt: prompt.slice(0, 60) }) + '\n');
|
|
1065
|
+
}
|
|
1066
|
+
const result = await delegateToEngine(engineId, prompt, {
|
|
1067
|
+
...(model ? { model } : {}),
|
|
1068
|
+
});
|
|
1069
|
+
const elapsed = Date.now() - startTime;
|
|
1070
|
+
if (outputJson) {
|
|
1071
|
+
console.log(JSON.stringify({ ...result, elapsedMs: elapsed }, null, 2));
|
|
1072
|
+
}
|
|
1073
|
+
else {
|
|
1074
|
+
if (result.success) {
|
|
1075
|
+
response = result.output || '(无输出)';
|
|
1076
|
+
}
|
|
1077
|
+
else {
|
|
1078
|
+
response = `❌ 委派失败: ${result.error}`;
|
|
1079
|
+
if (result.output)
|
|
1080
|
+
response += `\n[输出]\n${result.output.slice(0, 2000)}`;
|
|
1081
|
+
}
|
|
1082
|
+
}
|
|
1083
|
+
break;
|
|
1084
|
+
}
|
|
1031
1085
|
case 'context': {
|
|
1032
1086
|
const ctx = await getGlobalSharedContext();
|
|
1033
1087
|
response = await ctx.getContextSummary();
|
|
@@ -1576,6 +1630,11 @@ function parseArgs() {
|
|
|
1576
1630
|
}
|
|
1577
1631
|
result.toolArgs = delArgs;
|
|
1578
1632
|
break;
|
|
1633
|
+
case '--engine':
|
|
1634
|
+
case '-e':
|
|
1635
|
+
result.engine = args[++i];
|
|
1636
|
+
result.tool = 'engine';
|
|
1637
|
+
break;
|
|
1579
1638
|
case '--context':
|
|
1580
1639
|
result.context = true;
|
|
1581
1640
|
result.tool = 'context';
|
|
@@ -1736,9 +1795,10 @@ function parseArgs() {
|
|
|
1736
1795
|
i = args.length;
|
|
1737
1796
|
break;
|
|
1738
1797
|
default:
|
|
1739
|
-
if (!arg.startsWith('-') && !result.prompt
|
|
1798
|
+
if (!arg.startsWith('-') && !result.prompt) {
|
|
1740
1799
|
result.prompt = arg;
|
|
1741
|
-
result.tool
|
|
1800
|
+
if (!result.tool)
|
|
1801
|
+
result.tool = 'prompt';
|
|
1742
1802
|
}
|
|
1743
1803
|
}
|
|
1744
1804
|
}
|
|
@@ -138,7 +138,7 @@ function formatInjection(values, mode, resolvedCount, maxChars = 1500) {
|
|
|
138
138
|
// 使用记录 (回溯): AI 实际"用了"哪些判断力
|
|
139
139
|
// ============================================================
|
|
140
140
|
const USAGE_LOG = (os.homedir() || '/tmp') + '/.bolloon/human-values/usage.jsonl';
|
|
141
|
-
export async function recordJudgmentUsage(usedIds, meta) {
|
|
141
|
+
export async function recordJudgmentUsage(usedIds, meta = {}) {
|
|
142
142
|
if (usedIds.length === 0)
|
|
143
143
|
return;
|
|
144
144
|
try {
|
|
@@ -147,6 +147,7 @@ export async function recordJudgmentUsage(usedIds, meta) {
|
|
|
147
147
|
channelId: meta.channelId ?? null,
|
|
148
148
|
userInputPreview: (meta.userInput ?? '').substring(0, 80),
|
|
149
149
|
usedIds,
|
|
150
|
+
polarity: meta.polarity ?? 'positive',
|
|
150
151
|
};
|
|
151
152
|
await fs.appendFile(USAGE_LOG, JSON.stringify(entry) + '\n', 'utf-8');
|
|
152
153
|
}
|
|
@@ -154,6 +155,89 @@ export async function recordJudgmentUsage(usedIds, meta) {
|
|
|
154
155
|
console.warn('[injection-gate] recordJudgmentUsage failed:', err);
|
|
155
156
|
}
|
|
156
157
|
}
|
|
158
|
+
// ============================================================
|
|
159
|
+
// 2026-07-22 设计 B: 负向判断力回收 — "避免清单"注入 (显式, 进 prompt)
|
|
160
|
+
//
|
|
161
|
+
// 涡轮增压锚点: 判断力的负向是"判断力"不是"上下文废气", 可进 prompt 作为约束
|
|
162
|
+
// (精准 = 正向指引 + 负向避免). 从 reject 类 + 高 stakes + 高 confidence 选 Top N,
|
|
163
|
+
// 以"避免清单"语义产出 systemAddition. maxChars=300 (远小于正向 1500, 防噪音).
|
|
164
|
+
// ============================================================
|
|
165
|
+
export const DEFAULT_NEGATIVE_CONFIG = {
|
|
166
|
+
topN: 3,
|
|
167
|
+
mode: 'concise',
|
|
168
|
+
skip: false,
|
|
169
|
+
maxChars: 300,
|
|
170
|
+
/** 最低置信度门槛 (只注入足够可信的否决) */
|
|
171
|
+
minConfidence: 0.7,
|
|
172
|
+
};
|
|
173
|
+
function emptyGateResult(skipReason) {
|
|
174
|
+
return { systemAddition: '', usedIds: [], matchedCount: 0, didInject: false, skipReason };
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* 负向判断力注入门: 给定用户输入, 返回"避免清单"追加文本 + 用到的负向 judgment id.
|
|
178
|
+
*
|
|
179
|
+
* 筛选: decision_type='reject' && status='active' && stakes∈{high,critical} && confidence>=minConfidence
|
|
180
|
+
* 排序: critical 优先, 再按 confidence desc
|
|
181
|
+
* 静默: 任意步骤失败返回空字符串, 不 throw (主对话不阻塞)
|
|
182
|
+
*/
|
|
183
|
+
export async function injectNegativeGuard(userInput, _ctx = {}, options = {}) {
|
|
184
|
+
const cfg = { ...DEFAULT_NEGATIVE_CONFIG, ...options };
|
|
185
|
+
if (cfg.skip)
|
|
186
|
+
return emptyGateResult('skip');
|
|
187
|
+
if (!userInput || userInput.trim().length === 0)
|
|
188
|
+
return emptyGateResult('no-input');
|
|
189
|
+
try {
|
|
190
|
+
const all = await loadAllJudgments();
|
|
191
|
+
const negatives = all.filter((j) => j.decision_type === 'reject' &&
|
|
192
|
+
(j.status ?? 'active') === 'active' &&
|
|
193
|
+
(j.context?.stakes === 'high' || j.context?.stakes === 'critical') &&
|
|
194
|
+
(j.metadata?.confidence ?? 0.5) >= (cfg.minConfidence ?? 0.7));
|
|
195
|
+
if (negatives.length === 0)
|
|
196
|
+
return emptyGateResult('empty-negatives');
|
|
197
|
+
// 排序: critical > high, 再按 confidence desc
|
|
198
|
+
negatives.sort((a, b) => {
|
|
199
|
+
const sa = a.context?.stakes === 'critical' ? 2 : 1;
|
|
200
|
+
const sb = b.context?.stakes === 'critical' ? 2 : 1;
|
|
201
|
+
const ca = a.metadata?.confidence ?? 0.5;
|
|
202
|
+
const cb = b.metadata?.confidence ?? 0.5;
|
|
203
|
+
return (sb - sa) || (cb - ca);
|
|
204
|
+
});
|
|
205
|
+
const top = negatives.slice(0, cfg.topN);
|
|
206
|
+
const usedIds = top.map((j) => j.id);
|
|
207
|
+
const systemAddition = formatNegativeInjection(top, cfg.maxChars);
|
|
208
|
+
return {
|
|
209
|
+
systemAddition,
|
|
210
|
+
usedIds,
|
|
211
|
+
matchedCount: negatives.length,
|
|
212
|
+
didInject: true,
|
|
213
|
+
skipReason: null,
|
|
214
|
+
};
|
|
215
|
+
}
|
|
216
|
+
catch (err) {
|
|
217
|
+
console.warn('[injection-gate] injectNegativeGuard failed (silent fallback):', err);
|
|
218
|
+
return emptyGateResult('exception');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
function formatNegativeInjection(items, maxChars) {
|
|
222
|
+
if (items.length === 0)
|
|
223
|
+
return '';
|
|
224
|
+
const SOURCE_TAG = '<!-- source: injection-gate (negative) -->';
|
|
225
|
+
const lines = items.map((j, i) => {
|
|
226
|
+
const stakes = j.context?.stakes === 'critical' ? ' [关键风险]' : ' [高风险]';
|
|
227
|
+
const decision = (j.decision || '').slice(0, 80);
|
|
228
|
+
return `${i + 1}. 避免: ${decision}${stakes}`;
|
|
229
|
+
});
|
|
230
|
+
let result = `${SOURCE_TAG}\n` +
|
|
231
|
+
`# 避免清单 (负向判断力, 自动注入)\n` +
|
|
232
|
+
`- 以下行为已被明确否决, 执行时主动规避; 如情境冲突在回复中说明\n` +
|
|
233
|
+
`${lines.join('\n')}\n`;
|
|
234
|
+
if (maxChars > 0 && result.length > maxChars) {
|
|
235
|
+
result =
|
|
236
|
+
result.substring(0, maxChars) +
|
|
237
|
+
'\n[System Note: 避免清单因长度截断, 这是背景约束, 不影响用户实际请求.]\n';
|
|
238
|
+
}
|
|
239
|
+
return result;
|
|
240
|
+
}
|
|
157
241
|
/**
|
|
158
242
|
* 给定 channelId, 取最近 N 条 usage 记录 (UI 显示用)
|
|
159
243
|
*/
|